Merge remote-tracking branch 'upstream/develop' into timeline-event-mgr

# Conflicts:
#	Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java
#	RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Chrome.java
#	RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractIE.java
#	RecentActivity/src/org/sleuthkit/autopsy/recentactivity/FirefoxExtractor.java
#	RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Util.java
This commit is contained in:
millmanorama 2018-11-08 16:23:54 +01:00
commit 1bbee98a78
72 changed files with 2654 additions and 1107 deletions

View File

@ -23,6 +23,8 @@
<dependency conf="core->default" org="com.adobe.xmp" name="xmpcore" rev="5.1.2"/>
<dependency conf="core->default" org="org.apache.zookeeper" name="zookeeper" rev="3.4.6"/>
<dependency conf="core->default" org="com.healthmarketscience.jackcess" name="jackcess" rev="2.2.0"/>
<dependency conf="core->default" org="com.healthmarketscience.jackcess" name="jackcess-encrypt" rev="2.1.4"/>
<dependency conf="core->default" org="org.apache.commons" name="commons-dbcp2" rev="2.1.1"/>
<dependency conf="core->default" org="org.apache.commons" name="commons-pool2" rev="2.4.2"/>

View File

@ -18,8 +18,8 @@ file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar
file.reference.sqlite-jdbc-3.8.11.jar=release\\modules\\ext\\sqlite-jdbc-3.8.11.jar
file.reference.StixLib.jar=release/modules/ext/StixLib.jar
file.reference.bcprov-jdk15on-1.54.jar=release/modules/ext/bcprov-jdk15on-1.54.jar
file.reference.jackcess-2.1.8.jar=release/modules/ext/jackcess-2.1.8.jar
file.reference.jackcess-encrypt-2.1.2.jar=release/modules/ext/jackcess-encrypt-2.1.2.jar
file.reference.jackcess-2.2.0.jar=release/modules/ext/jackcess-2.2.0.jar
file.reference.jackcess-encrypt-2.1.4.jar=release/modules/ext/jackcess-encrypt-2.1.4.jar
file.reference.jempbox-1.8.13.jar=release/modules/ext/jempbox-1.8.13.jar
file.reference.javax.ws.rs-api-2.0.1.jar=release/modules/ext/javax.ws.rs-api-2.0.1.jar
file.reference.cxf-core-3.0.16.jar=release/modules/ext/cxf-core-3.0.16.jar
@ -29,7 +29,7 @@ file.reference.cxf-rt-transports-http-3.0.16.jar=release/modules/ext/cxf-rt-tran
file.reference.fontbox-2.0.8.jar=release/modules/ext/fontbox-2.0.8.jar
file.reference.pdfbox-2.0.8.jar=release/modules/ext/pdfbox-2.0.8.jar
file.reference.pdfbox-tools-2.0.8.jar=release/modules/ext/pdfbox-tools-2.0.8.jar
file.reference.sleuthkit-postgresql-4.6.3.jar=release/modules/ext/sleuthkit-postgresql-4.6.3.jar
file.reference.sleuthkit-postgresql-4.6.4.jar=release/modules/ext/sleuthkit-postgresql-4.6.4.jar
file.reference.tika-core-1.17.jar=release/modules/ext/tika-core-1.17.jar
file.reference.tika-parsers-1.17.jar=release/modules/ext/tika-parsers-1.17.jar
file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar

View File

@ -342,8 +342,8 @@
<package>org.sleuthkit.datamodel</package>
</public-packages>
<class-path-extension>
<runtime-relative-path>ext/jackcess-2.1.8.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-2.1.8.jar</binary-origin>
<runtime-relative-path>ext/jackcess-2.2.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-2.2.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/zookeeper-3.4.6.jar</runtime-relative-path>
@ -394,8 +394,8 @@
<binary-origin>release/modules/ext/sevenzipjbinding.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.3.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.3.jar</binary-origin>
<runtime-relative-path>ext/sleuthkit-postgresql-4.6.4.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.6.4.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/mchange-commons-java-0.2.9.jar</runtime-relative-path>
@ -482,8 +482,8 @@
<binary-origin>release\modules\ext\commons-pool2-2.4.2.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jackcess-encrypt-2.1.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-encrypt-2.1.2.jar</binary-origin>
<runtime-relative-path>ext/jackcess-encrypt-2.1.4.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackcess-encrypt-2.1.4.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jsoup-1.10.3.jar</runtime-relative-path>

View File

@ -122,6 +122,7 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TimelineManager;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskUnsupportedSchemaVersionException;
import org.sleuthkit.autopsy.coreutils.StopWatch;
/**
* An Autopsy case. Currently, only one case at a time may be open.
@ -743,11 +744,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."
})
public static void deleteCase(CaseMetadata metadata) throws CaseActionException {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
synchronized (caseActionSerializationLock) {
if (null != currentCase) {
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
@ -769,10 +774,19 @@ public class Case {
* cannot be deleted if another node has it open.
*/
progressIndicator.progress(Bundle.Case_progressMessage_checkingForOtherUser());
stopWatch.reset();
stopWatch.start();
try (CoordinationService.Lock dirLock = CoordinationService.getInstance().tryGetExclusiveLock(CategoryNode.CASES, metadata.getCaseDirectory())) {
assert (null != dirLock);
deleteCase(metadata, progressIndicator);
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);
} else {
throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock());
}
} 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);
}
}
@ -982,11 +996,13 @@ public class Case {
"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 {
StopWatch stopWatch = new StopWatch();
boolean errorsOccurred = false;
if (CaseType.MULTI_USER_CASE == metadata.getCaseType()) {
/*
* Delete the case database from the database server.
*/
stopWatch.start();
try {
progressIndicator.progress(Bundle.Case_progressMessage_deletingCaseDatabase());
CaseDbConnectionInfo db;
@ -996,10 +1012,14 @@ public class Case {
Statement statement = connection.createStatement();) {
String deleteCommand = "DROP DATABASE \"" + metadata.getCaseDatabaseName() + "\""; //NON-NLS
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) {
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;
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()));
}
}
@ -1009,10 +1029,16 @@ public class Case {
progressIndicator.progress(Bundle.Case_progressMessage_deletingTextIndex());
for (KeywordSearchService searchService : Lookup.getDefault().lookupAll(KeywordSearchService.class)) {
try {
stopWatch.reset();
stopWatch.start();
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) {
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;
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()));
}
}
@ -1020,9 +1046,16 @@ public class Case {
* Delete the case directory.
*/
progressIndicator.progress(Bundle.Case_progressMessage_deletingCaseDirectory());
stopWatch.reset();
stopWatch.start();
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()));
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()));
}
/*
@ -1576,11 +1609,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)
*
* @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
*/
public void notifyCentralRepoCommentChanged(long contentId, String newComment) {
@ -1836,7 +1871,7 @@ public class Case {
progressIndicator.progress(Bundle.Case_progressMessage_preparingToOpenCaseResources());
acquireSharedCaseDirLock(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);
} catch (CaseActionException ex) {
releaseSharedCaseDirLock(getMetadata().getCaseDirectory());
@ -2414,7 +2449,7 @@ public class Case {
* @throws CaseActionException with a user-friendly message if the lock
* 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 {
try {
caseDirLock = CoordinationService.getInstance().tryGetSharedLock(CategoryNode.CASES, caseDir, DIR_LOCK_TIMOUT_HOURS, TimeUnit.HOURS);

View File

@ -21,8 +21,6 @@ package org.sleuthkit.autopsy.casemodule;
import java.io.File;
import java.util.Calendar;
import java.util.List;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.logging.Level;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
@ -39,6 +37,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.PathValidator;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
/**
* Panel for adding an image file such as .img, .E0x, .00x, etc. Allows the user
@ -72,11 +71,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
initComponents();
// Populate the drop down list of time zones
for (String id : SimpleTimeZone.getAvailableIDs()) {
timeZoneComboBox.addItem(timeZoneToString(TimeZone.getTimeZone(id)));
}
// set the selected timezone to the current timezone
timeZoneComboBox.setSelectedItem(timeZoneToString(Calendar.getInstance().getTimeZone()));
createTimeZoneList();
// Populate the drop down list of sector size options
for (String choice : SECTOR_SIZE_CHOICES) {
@ -95,6 +90,20 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
}
}
/**
* Creates the drop down list for the time zones and defaults the selection
* to the local machine time zone.
*/
private void createTimeZoneList() {
List<String> timeZoneList = TimeZoneUtils.createTimeZoneList();
for (String timeZone : timeZoneList) {
timeZoneComboBox.addItem(timeZone);
}
// set the selected timezone
timeZoneComboBox.setSelectedItem(TimeZoneUtils.createTimeZoneString(Calendar.getInstance().getTimeZone()));
}
/**
* Creates and returns an instance of a ImageFilePanel.
*
@ -348,21 +357,6 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
}
}
/**
* Get a string representation of a TimeZone for use in the drop down list.
*
* @param zone The TimeZone to make a string for
*
* @return A string representation of a TimeZone for use in the drop down
* list.
*/
static private String timeZoneToString(TimeZone zone) {
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
return String.format("(GMT%+d:%02d) %s", hour, minutes, zone.getID()); //NON-NLS
}
@Override
public void insertUpdate(DocumentEvent e) {
updateHelper();

View File

@ -21,8 +21,7 @@ package org.sleuthkit.autopsy.casemodule;
import java.io.File;
import java.nio.file.Paths;
import java.util.Calendar;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
@ -32,6 +31,7 @@ import org.sleuthkit.autopsy.coreutils.LocalDisk;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings;
/**
@ -469,36 +469,13 @@ final class LocalDiskPanel extends JPanel {
* to the local machine time zone.
*/
public void createTimeZoneList() {
// load and add all timezone
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
TimeZone zone = TimeZone.getTimeZone(id);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id); //NON-NLS
/*
* DateFormat dfm = new SimpleDateFormat("z");
* dfm.setTimeZone(zone); boolean hasDaylight =
* zone.useDaylightTime(); String first = dfm.format(new Date(2010,
* 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid
* = hour * -1; String result = first + Integer.toString(mid);
* if(hasDaylight){ result = result + second; }
* timeZoneComboBox.addItem(item + " (" + result + ")");
*/
timeZoneComboBox.addItem(item);
List<String> timeZoneList = TimeZoneUtils.createTimeZoneList();
for (String timeZone : timeZoneList) {
timeZoneComboBox.addItem(timeZone);
}
// get the current timezone
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
int thisOffset = thisTimeZone.getRawOffset() / 1000;
int thisHour = thisOffset / 3600;
int thisMinutes = (thisOffset % 3600) / 60;
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID()); //NON-NLS
// set the selected timezone
timeZoneComboBox.setSelectedItem(formatted);
timeZoneComboBox.setSelectedItem(TimeZoneUtils.createTimeZoneString(Calendar.getInstance().getTimeZone()));
}
/**

View File

@ -369,7 +369,7 @@ public class LocalFilesDSProcessor implements DataSourceProcessor, AutoIngestDat
@Override
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) {
List<String> filePaths = Arrays.asList(new String[]{dataSourcePath.toString()});
run(deviceId, deviceId, filePaths, progressMonitor, callBack);
run(deviceId, "", filePaths, progressMonitor, callBack);
}
/**

View File

@ -492,6 +492,7 @@ public class FileManager implements Closeable {
}
}
trans.commit();
trans = null;
/*
* Publish content added events for the added files and directories.
@ -502,15 +503,14 @@ public class FileManager implements Closeable {
return dataSource;
} catch (TskCoreException ex) {
} finally {
if (null != trans) {
try {
trans.rollback();
} catch (TskCoreException ex2) {
LOGGER.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to rollback transaction after exception", ex);
}
}
throw ex;
}
}

View File

@ -2960,14 +2960,10 @@ abstract class AbstractSqlEamDb implements EamDb {
resultSet.getString("poc_phone"));
}
CorrelationCase eamCase = new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), resultSet.getString("case_name"));
eamCase.setOrg(eamOrg);
eamCase.setCreationDate(resultSet.getString("creation_date"));
eamCase.setCaseNumber(resultSet.getString("case_number"));
eamCase.setExaminerName(resultSet.getString("examiner_name"));
eamCase.setExaminerEmail(resultSet.getString("examiner_email"));
eamCase.setExaminerPhone(resultSet.getString("examiner_phone"));
eamCase.setNotes(resultSet.getString("notes"));
CorrelationCase eamCase = new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes"));
return eamCase;
}
@ -3017,7 +3013,6 @@ abstract class AbstractSqlEamDb implements EamDb {
if (null == resultSet) {
return null;
}
// @@@ We should have data source ID in the previous query instead of passing -1 into the below constructor
return new CorrelationAttributeInstance(
aType,
resultSet.getString("value"),

View File

@ -66,7 +66,7 @@ GlobalSettingsPanel.lbCentralRepository.text=A central repository allows you to
GlobalSettingsPanel.pnCorrelationProperties.border.title=Correlation Properties
GlobalSettingsPanel.organizationPanel.border.title=Organizations
GlobalSettingsPanel.casesPanel.border.title=Case Details
GlobalSettingsPanel.showCasesButton.text=Show Cases
GlobalSettingsPanel.showCasesButton.text=Manage Cases
ShowCasesDialog.closeButton.AccessibleContext.accessibleName=Close
ShowCasesDialog.closeButton.actionCommand=Close
ShowCasesDialog.closeButton.text=Close
@ -76,3 +76,12 @@ GlobalSettingsPanel.Case\ Details.AccessibleContext.accessibleName=Cases Details
ShowCasesDialog.caseDetailsTable.AccessibleContext.accessibleDescription=Click column name to sort.
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!
ManageCasesDialog.examinerPhoneLabel.text=Examiner Phone:
ManageCasesDialog.examinerNameLabel.text=Examiner Name:
ManageCasesDialog.examinerEmailLabel.text=Examiner Email:
ManageCasesDialog.caseNumberLabel.text=Case Number:
ManageCasesDialog.orgLabel.text=Organization:
ManageCasesDialog.closeButton.text=Close
ManageCasesDialog.notesLabel.text=Notes:
ManageCasesDialog.dataSourcesLabel.text=Data Sources:
ManageCasesDialog.caseInfoLabel.text=Case Info:

View File

@ -0,0 +1,131 @@
/*
* Central Repository
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository.optionspanel;
import java.util.Collections;
import java.util.List;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization;
/**
* An object to contain both a CorrelationCase and the list of
* CorrelationDataSources which are associated with that case.
*/
class CaseDataSourcesWrapper {
private final CorrelationCase eamCase;
private final List<CorrelationDataSource> dataSources;
/**
* Create a new CaseDataSourcesWrapper object.
*
* @param correlationCase - the CorrelationCase which is being represented
* @param dataSourceList - the list of CorrelationDataSource objects which
* are associated with the CorrelationCase
*/
CaseDataSourcesWrapper(CorrelationCase correlationCase, List<CorrelationDataSource> dataSourceList) {
eamCase = correlationCase;
dataSources = dataSourceList;
}
/**
* Get the display name of the CorrelationCase.
*
* @return the display name of the CorrelationCase.
*/
String getDisplayName() {
return eamCase.getDisplayName();
}
/**
* Get the list of CorrelationDataSources associated with the
* CorrelationCase.
*
* @return the list of CorrelationDataSources associated with the
* CorrelationCase.
*/
List<CorrelationDataSource> getDataSources() {
return Collections.unmodifiableList(dataSources);
}
/**
* Get the creation date of the CorrelationCase.
*
* @return the creation date of the CorrelationCase.
*/
String getCreationDate() {
return eamCase.getCreationDate();
}
/**
* Get the organization name of the CorrelationCase.
*
* @return the organization name of the CorrelationCase.
*/
String getOrganizationName() {
EamOrganization org = eamCase.getOrg();
return org == null ? "" : org.getName();
}
/**
* Get the case number of the CorrelationCase.
*
* @return the case number of the CorrelationCase.
*/
String getCaseNumber() {
return eamCase.getCaseNumber();
}
/**
* Get the examiner name of the CorrelationCase.
*
* @return the examiner name of the CorrelationCase.
*/
String getExaminerName() {
return eamCase.getExaminerName();
}
/**
* Get the examiner email of the CorrelationCase.
*
* @return the examiner email of the CorrelationCase.
*/
String getExaminerEmail() {
return eamCase.getExaminerEmail();
}
/**
* Get the notes of the CorrelationCase.
*
* @return the notes of the CorrelationCase.
*/
String getNotes() {
return eamCase.getNotes();
}
/**
* Get the examiner phone number of the CorrelationCase.
*
* @return the examiner phone number of the CorrelationCase.
*/
String getExaminerPhone() {
return eamCase.getExaminerPhone();
}
}

View File

@ -0,0 +1,156 @@
/*
* Central Repository
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository.optionspanel;
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
/**
* Model for cells to display correlation case information
*/
class CasesTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
/**
* list of Eam Cases from central repository.
*/
private final List<CaseDataSourcesWrapper> eamCases;
/**
* Model for cells to display correlation case information
*/
CasesTableModel() {
eamCases = new ArrayList<>();
}
@Override
public int getColumnCount() {
return CaseTableColumns.values().length;
}
@Override
public int getRowCount() {
return eamCases.size();
}
@Override
public String getColumnName(int colIdx) {
return CaseTableColumns.values()[colIdx].columnName();
}
@Override
public Object getValueAt(int rowIdx, int colIdx) {
if (eamCases.isEmpty()) {
return Bundle.CasesTableModel_noData();
}
return mapValueById(rowIdx, CaseTableColumns.values()[colIdx]);
}
/**
* Map a rowIdx and colId to the value in that cell.
*
* @param rowIdx Index of row to search
* @param colId ID of column to search
*
* @return value in the cell
*/
@Messages({"CasesTableModel.noData=No Cases"})
private Object mapValueById(int rowIdx, CaseTableColumns colId) {
CaseDataSourcesWrapper eamCase = eamCases.get(rowIdx);
String value = Bundle.CasesTableModel_noData();
switch (colId) {
case CASE_NAME:
value = eamCase.getDisplayName();
break;
case CREATION_DATE:
value = eamCase.getCreationDate();
break;
default:
break;
}
return value;
}
@Override
public Class<String> getColumnClass(int colIdx) {
return String.class;
}
/**
* Add one local central repository case to the table.
*
* @param eamCase central repository case to add to the table
*/
void addEamCase(CorrelationCase eamCase, List<CorrelationDataSource> dataSourceList) {
eamCases.add(new CaseDataSourcesWrapper(eamCase, dataSourceList));
fireTableDataChanged();
}
/**
* Get the CaseDataSourcesWrapper for the specified index in the table.
*
* @param listIndex the idex of the object to get
*
* @return A caseDataSourcesWrapper containing the CorrelationCase and the
* CorrelationDataSources associated with it for the specified
* index.
*/
CaseDataSourcesWrapper getEamCase(int listIndex) {
return eamCases.get(listIndex);
}
/**
* Enum which lists columns of interest from CorrelationCase.
*/
@Messages({"CasesTableModel.case=Case Name",
"CasesTableModel.creationDate=Creation Date"})
private enum CaseTableColumns {
// Ordering here determines displayed column order in Content Viewer.
// If order is changed, update the CellRenderer to ensure correct row coloring.
CASE_NAME(Bundle.CasesTableModel_case()),
CREATION_DATE(Bundle.CasesTableModel_creationDate());
private final String columnName;
/**
* Make a DataSourceTableColumns enum item.
*
* @param columnName the name of the column.s
*/
CaseTableColumns(String columnName) {
this.columnName = columnName;
}
/**
* The name displayed in the column header.
*
* @return the name of the column.
*/
String columnName() {
return columnName;
}
}
}

View File

@ -0,0 +1,152 @@
/*
* Central Repository
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository.optionspanel;
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
/**
* Model for cells to display correlation data source information
*/
class DataSourcesTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
/**
* A list of correlation data sources from central repository.
*/
private final List<CorrelationDataSource> dataSources;
/**
* Create a new DataSourcesTableModel, with an initially empty list of data
* sources.
*/
DataSourcesTableModel() {
dataSources = new ArrayList<>();
}
@Override
public int getColumnCount() {
return DataSourcesTableColumns.values().length;
}
@Override
public int getRowCount() {
return dataSources.size();
}
@Override
public String getColumnName(int colIdx) {
return DataSourcesTableColumns.values()[colIdx].columnName();
}
@Override
public Object getValueAt(int rowIdx, int colIdx) {
if (dataSources.isEmpty()) {
return Bundle.DataSourcesTableModel_noData();
}
return mapValueById(rowIdx, DataSourcesTableColumns.values()[colIdx]);
}
/**
* Map a rowIdx and colId to the value in that cell.
*
* @param rowIdx Index of row to search
* @param colId ID of column to search
*
* @return value in the cell
*/
@Messages({"DataSourcesTableModel.noData=No Data Sources"})
private Object mapValueById(int rowIdx, DataSourcesTableColumns colId) {
CorrelationDataSource dataSource = dataSources.get(rowIdx);
String value = Bundle.DataSourcesTableModel_noData();
switch (colId) {
case DATA_SOURCE:
value = dataSource.getName();
break;
case DEVICE_ID:
value = dataSource.getDeviceID();
break;
default:
break;
}
return value;
}
@Override
public Class<String> getColumnClass(int colIdx) {
return String.class;
}
/**
* Add a list of datasources to the table.
*
* @param dataSourceList the list of datasources to add to the table
*/
void addDataSources(List<CorrelationDataSource> dataSourceList) {
dataSources.addAll(dataSourceList);
fireTableDataChanged();
}
/**
* Clear the data sources currently included in the model.
*/
void clearTable() {
dataSources.clear();
fireTableDataChanged();
}
@Messages({"DataSourcesTableModel.dataSource=Data Source Name",
"DataSourcesTableModel.deviceId=Device ID"})
/**
* Enum which lists columns of interest from CorrelationDataSource.
*/
private enum DataSourcesTableColumns {
// Ordering here determines displayed column order in Content Viewer.
// If order is changed, update the CellRenderer to ensure correct row coloring.
DATA_SOURCE(Bundle.DataSourcesTableModel_dataSource()),
DEVICE_ID(Bundle.DataSourcesTableModel_deviceId());
private final String columnName;
/**
* Make a CasesTableColumns enum item.
*
* @param columnName the name of the column.
*/
DataSourcesTableColumns(String columnName) {
this.columnName = columnName;
}
/**
* The name displayed in the column header.
*
* @return the name of the column.
*/
String columnName() {
return columnName;
}
}
}

View File

@ -441,7 +441,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
private void showCasesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCasesButtonActionPerformed
store();
ShowCasesDialog showCasesDialog = new ShowCasesDialog();
ManageCasesDialog.displayManageCasesDialog();
}//GEN-LAST:event_showCasesButtonActionPerformed
@Override

View File

@ -0,0 +1,358 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.6" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[400, 400]"/>
</Property>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="casesSplitPane" alignment="1" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="casesSplitPane" alignment="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JSplitPane" name="casesSplitPane">
<Properties>
<Property name="dividerLocation" type="int" value="380"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="caseInfoPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
<JSplitPaneConstraints position="right"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Component id="dataSourcesScrollPane" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Component id="orgLabel" min="-2" pref="88" max="-2" attributes="0"/>
<Component id="caseNumberLabel" min="-2" pref="88" max="-2" attributes="0"/>
<Component id="examinerNameLabel" alignment="1" min="-2" pref="88" max="-2" attributes="0"/>
<Component id="examinerEmailLabel" alignment="1" min="-2" pref="88" max="-2" attributes="0"/>
<Component id="examinerPhoneLabel" alignment="1" min="-2" pref="88" max="-2" attributes="0"/>
</Group>
<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="caseNumberValueLabel" max="32767" attributes="0"/>
<Component id="orgValueLabel" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="examinerNameValueLabel" max="32767" attributes="0"/>
<Component id="examinerEmailValueLabel" max="32767" attributes="0"/>
<Component id="examinerPhoneValueLabel" alignment="0" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
<Component id="notesLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Component id="notesScrollPane" pref="428" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Component id="closeButton" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="caseInfoLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="dataSourcesLabel" alignment="0" min="-2" pref="77" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="caseInfoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="1" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="orgLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="caseNumberLabel" max="32767" attributes="0"/>
<Component id="caseNumberValueLabel" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="examinerNameLabel" max="32767" attributes="0"/>
<Component id="examinerNameValueLabel" max="32767" attributes="0"/>
</Group>
</Group>
<Component id="orgValueLabel" alignment="0" min="-2" pref="14" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="examinerEmailLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="examinerEmailValueLabel" min="-2" pref="14" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="examinerPhoneLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="examinerPhoneValueLabel" alignment="0" min="-2" pref="14" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="notesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="notesScrollPane" pref="55" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="dataSourcesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="dataSourcesScrollPane" pref="129" max="32767" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="closeButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="dataSourcesScrollPane">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="dataSourcesTable">
<Properties>
<Property name="autoCreateRowSorter" type="boolean" value="true"/>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="dataSourcesTableModel" type="code"/>
</Property>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="0"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_SerializeTo" type="java.lang.String" value="CaseManagerDialog_dataSourcesTable"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JScrollPane" name="notesScrollPane">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="notesTextArea">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="f0" green="f0" red="f0" type="rgb"/>
</Property>
<Property name="columns" type="int" value="20"/>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="0"/>
</Property>
<Property name="lineWrap" type="boolean" value="true"/>
<Property name="rows" type="int" value="3"/>
<Property name="wrapStyleWord" type="boolean" value="true"/>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JLabel" name="caseInfoLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.caseInfoLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="dataSourcesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.dataSourcesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="notesLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.notesLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="orgLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.orgLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="caseNumberLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.caseNumberLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="examinerEmailLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.examinerEmailLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="examinerNameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.examinerNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="examinerPhoneLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.examinerPhoneLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="orgValueLabel">
</Component>
<Component class="javax.swing.JLabel" name="caseNumberValueLabel">
</Component>
<Component class="javax.swing.JLabel" name="examinerNameValueLabel">
</Component>
<Component class="javax.swing.JLabel" name="examinerEmailValueLabel">
</Component>
<Component class="javax.swing.JLabel" name="examinerPhoneValueLabel">
</Component>
<Component class="javax.swing.JButton" name="closeButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ManageCasesDialog.closeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[65, 23]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[65, 23]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[65, 23]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="closeButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="casesPanel">
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
<JSplitPaneConstraints position="left"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="casesScrollPane" pref="379" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="casesScrollPane" pref="361" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="40" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="casesScrollPane">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="casesTable">
<Properties>
<Property name="autoCreateRowSorter" type="boolean" value="true"/>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="casesTableModel" type="code"/>
</Property>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="0"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,353 @@
/*
* Central Repository
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository.optionspanel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.openide.util.NbBundle.Messages;
/**
* A dialog which displays cases existing in the central repository and the
* central repo information associated with them.
*
*/
final class ManageCasesDialog extends javax.swing.JDialog {
private static final long serialVersionUID = 1L;
private final CasesTableModel casesTableModel = new CasesTableModel();
private final DataSourcesTableModel dataSourcesTableModel = new DataSourcesTableModel();
private final static Logger logger = Logger.getLogger(ManageCasesDialog.class.getName());
/**
* Creates new form ManageCasesDialog
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
@Messages({"ManageCasesDialog.title.text=Manage Cases"})
private ManageCasesDialog() {
super(WindowManager.getDefault().getMainWindow(), Bundle.ManageCasesDialog_title_text(),
true);
initComponents();
try {
EamDb dbManager = EamDb.getInstance();
Map<Integer, List<CorrelationDataSource>> dataSourcesByCaseId = new HashMap<>();
for (CorrelationDataSource dataSource : dbManager.getDataSources()) {
int caseID = dataSource.getCaseID();
List<CorrelationDataSource> dataSourceNames = dataSourcesByCaseId.getOrDefault(caseID, new ArrayList<>());
dataSourceNames.add(dataSource);
dataSourcesByCaseId.put(caseID, dataSourceNames);
}
for (CorrelationCase eamCase : dbManager.getCases()) {
casesTableModel.addEamCase(eamCase, dataSourcesByCaseId.getOrDefault(eamCase.getID(), new ArrayList<>()));
}
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error getting list of cases from database.", ex); // NON-NLS
}
casesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
updateSelection();
}
}
});
//sort on first column by default
casesTable.getRowSorter().toggleSortOrder(0);
}
/**
* Create and display the Manage Cases dialog for the currently enabled
* central repository.
*/
static void displayManageCasesDialog() {
ManageCasesDialog caseInfoDialog = new ManageCasesDialog();
caseInfoDialog.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
caseInfoDialog.setVisible(true);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
casesSplitPane = new javax.swing.JSplitPane();
caseInfoPanel = new javax.swing.JPanel();
dataSourcesScrollPane = new javax.swing.JScrollPane();
dataSourcesTable = new javax.swing.JTable();
notesScrollPane = new javax.swing.JScrollPane();
notesTextArea = new javax.swing.JTextArea();
caseInfoLabel = new javax.swing.JLabel();
dataSourcesLabel = new javax.swing.JLabel();
notesLabel = new javax.swing.JLabel();
orgLabel = new javax.swing.JLabel();
caseNumberLabel = new javax.swing.JLabel();
examinerEmailLabel = new javax.swing.JLabel();
examinerNameLabel = new javax.swing.JLabel();
examinerPhoneLabel = new javax.swing.JLabel();
orgValueLabel = new javax.swing.JLabel();
caseNumberValueLabel = new javax.swing.JLabel();
examinerNameValueLabel = new javax.swing.JLabel();
examinerEmailValueLabel = new javax.swing.JLabel();
examinerPhoneValueLabel = new javax.swing.JLabel();
closeButton = new javax.swing.JButton();
casesPanel = new javax.swing.JPanel();
casesScrollPane = new javax.swing.JScrollPane();
casesTable = new javax.swing.JTable();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setMinimumSize(new java.awt.Dimension(400, 400));
casesSplitPane.setDividerLocation(380);
dataSourcesTable.setAutoCreateRowSorter(true);
dataSourcesTable.setModel(dataSourcesTableModel);
dataSourcesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
dataSourcesScrollPane.setViewportView(dataSourcesTable);
notesScrollPane.setBorder(null);
notesTextArea.setEditable(false);
notesTextArea.setBackground(new java.awt.Color(240, 240, 240));
notesTextArea.setColumns(20);
notesTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
notesTextArea.setLineWrap(true);
notesTextArea.setRows(3);
notesTextArea.setWrapStyleWord(true);
notesTextArea.setBorder(null);
notesScrollPane.setViewportView(notesTextArea);
org.openide.awt.Mnemonics.setLocalizedText(caseInfoLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.caseInfoLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(dataSourcesLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.dataSourcesLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(notesLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.notesLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(orgLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.orgLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(caseNumberLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.caseNumberLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(examinerEmailLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.examinerEmailLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(examinerNameLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.examinerNameLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(examinerPhoneLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.examinerPhoneLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.closeButton.text")); // NOI18N
closeButton.setMaximumSize(new java.awt.Dimension(65, 23));
closeButton.setMinimumSize(new java.awt.Dimension(65, 23));
closeButton.setPreferredSize(new java.awt.Dimension(65, 23));
closeButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
closeButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout caseInfoPanelLayout = new javax.swing.GroupLayout(caseInfoPanel);
caseInfoPanel.setLayout(caseInfoPanelLayout);
caseInfoPanelLayout.setHorizontalGroup(
caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addGap(6, 6, 6)
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(orgLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(caseNumberLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(examinerNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(examinerEmailLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(examinerPhoneLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(caseNumberValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(orgValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addGap(6, 6, 6)
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(examinerNameValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(examinerEmailValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(examinerPhoneValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
.addComponent(notesLabel)
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(notesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 428, Short.MAX_VALUE))))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, caseInfoPanelLayout.createSequentialGroup()
.addGap(0, 0, Short.MAX_VALUE)
.addComponent(closeButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(caseInfoLabel)
.addComponent(dataSourcesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
caseInfoPanelLayout.setVerticalGroup(
caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, caseInfoPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(caseInfoLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(caseInfoPanelLayout.createSequentialGroup()
.addComponent(orgLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(caseNumberLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(caseNumberValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(examinerNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(examinerNameValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addComponent(orgValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(examinerEmailLabel))
.addComponent(examinerEmailValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(examinerPhoneLabel)
.addComponent(examinerPhoneValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(notesLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(notesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 55, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(dataSourcesLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 129, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(closeButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
casesSplitPane.setRightComponent(caseInfoPanel);
casesTable.setAutoCreateRowSorter(true);
casesTable.setModel(casesTableModel);
casesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
casesScrollPane.setViewportView(casesTable);
javax.swing.GroupLayout casesPanelLayout = new javax.swing.GroupLayout(casesPanel);
casesPanel.setLayout(casesPanelLayout);
casesPanelLayout.setHorizontalGroup(
casesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(casesPanelLayout.createSequentialGroup()
.addComponent(casesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 379, Short.MAX_VALUE)
.addGap(0, 0, 0))
);
casesPanelLayout.setVerticalGroup(
casesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(casesPanelLayout.createSequentialGroup()
.addComponent(casesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 361, Short.MAX_VALUE)
.addGap(40, 40, 40))
);
casesSplitPane.setLeftComponent(casesPanel);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(casesSplitPane, javax.swing.GroupLayout.Alignment.TRAILING)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(casesSplitPane)
);
pack();
}// </editor-fold>//GEN-END:initComponents
private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
this.dispose();
}//GEN-LAST:event_closeButtonActionPerformed
/**
* Update the information displayed to reflect the currently selected case.
*/
private void updateSelection() {
dataSourcesTableModel.clearTable();
if (casesTable.getSelectedRow() >= 0 && casesTable.getSelectedRow() < casesTable.getRowCount()) {
CaseDataSourcesWrapper caseWrapper = casesTableModel.getEamCase(casesTable.convertRowIndexToModel(casesTable.getSelectedRow()));
orgValueLabel.setText(caseWrapper.getOrganizationName());
caseNumberValueLabel.setText(caseWrapper.getCaseNumber());
examinerNameValueLabel.setText(caseWrapper.getExaminerName());
examinerPhoneValueLabel.setText(caseWrapper.getExaminerPhone());
examinerEmailValueLabel.setText(caseWrapper.getExaminerEmail());
notesTextArea.setText(caseWrapper.getNotes());
dataSourcesTableModel.addDataSources(caseWrapper.getDataSources());
} else {
orgValueLabel.setText("");
caseNumberValueLabel.setText("");
examinerNameValueLabel.setText("");
examinerPhoneValueLabel.setText("");
examinerEmailValueLabel.setText("");
notesTextArea.setText("");
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel caseInfoLabel;
private javax.swing.JPanel caseInfoPanel;
private javax.swing.JLabel caseNumberLabel;
private javax.swing.JLabel caseNumberValueLabel;
private javax.swing.JPanel casesPanel;
private javax.swing.JScrollPane casesScrollPane;
private javax.swing.JSplitPane casesSplitPane;
private javax.swing.JTable casesTable;
private javax.swing.JButton closeButton;
private javax.swing.JLabel dataSourcesLabel;
private javax.swing.JScrollPane dataSourcesScrollPane;
private javax.swing.JTable dataSourcesTable;
private javax.swing.JLabel examinerEmailLabel;
private javax.swing.JLabel examinerEmailValueLabel;
private javax.swing.JLabel examinerNameLabel;
private javax.swing.JLabel examinerNameValueLabel;
private javax.swing.JLabel examinerPhoneLabel;
private javax.swing.JLabel examinerPhoneValueLabel;
private javax.swing.JLabel notesLabel;
private javax.swing.JScrollPane notesScrollPane;
private javax.swing.JTextArea notesTextArea;
private javax.swing.JLabel orgLabel;
private javax.swing.JLabel orgValueLabel;
// End of variables declaration//GEN-END:variables
}

View File

@ -1,169 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.6" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="title" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[545, 415]"/>
</Property>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Component id="showCasesPanel" pref="1188" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace max="32767" attributes="0"/>
<Component id="closeButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Component id="showCasesPanel" pref="473" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="closeButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="showCasesPanel">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[527, 407]"/>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="1188" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="showCasesScrollPane" alignment="0" pref="527" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="473" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="showCasesScrollPane" alignment="0" pref="407" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="showCasesScrollPane">
<Properties>
<Property name="verticalScrollBarPolicy" type="int" value="21"/>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[535, 415]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="outCasesPane">
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="1423" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="innerCaseScrollPane" alignment="0" pref="1423" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="500" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Component id="innerCaseScrollPane" alignment="0" pref="500" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="innerCaseScrollPane">
<Properties>
<Property name="horizontalScrollBarPolicy" type="int" value="31"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTable" name="caseDetailsTable">
<Properties>
<Property name="autoCreateRowSorter" type="boolean" value="true"/>
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="tableModel" type="code"/>
</Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.caseDetailsTable.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor">
<JTableSelectionModel selectionMode="1"/>
</Property>
<Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor">
<TableHeader reorderingAllowed="false" resizingAllowed="true"/>
</Property>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleDescription" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.caseDetailsTable.AccessibleContext.accessibleDescription" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</AccessibilityProperties>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Component class="javax.swing.JButton" name="closeButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.closeButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="actionCommand" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.closeButton.actionCommand" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties" key="ShowCasesDialog.closeButton.AccessibleContext.accessibleName" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</AccessibilityProperties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="closeButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -1,190 +0,0 @@
/*
* Central Repository
*
* Copyright 2015-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository.optionspanel;
import java.util.List;
import java.util.logging.Level;
import javax.swing.JDialog;
import javax.swing.JFrame;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Dialog to display table of CorrelationCase information from the CR tab of options.
*/
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class ShowCasesDialog extends JDialog {
private static final long serialVersionUID = 1L;
private final static Logger logger = Logger.getLogger(ShowCasesDialog.class.getName());
private final ShowCasesTableModel tableModel;
@Messages({"ShowCasesDialog.title_text=All Cases Details"})
/**
* Creates new form ShowCases Panel
*/
ShowCasesDialog() {
super((JFrame) WindowManager.getDefault().getMainWindow(),
Bundle.ShowCasesDialog_title_text(),
true);
tableModel = new ShowCasesTableModel();
initComponents();
try {
EamDb dbManager = EamDb.getInstance();
List<CorrelationCase> eamCases = dbManager.getCases();
for(CorrelationCase eamCase : eamCases) {
tableModel.addEamCase(eamCase);
}
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error getting list of cases from database.", ex); // NON-NLS
}
display();
}
private void display() {
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
setVisible(true);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
showCasesPanel = new javax.swing.JPanel();
showCasesScrollPane = new javax.swing.JScrollPane();
outCasesPane = new javax.swing.JPanel();
innerCaseScrollPane = new javax.swing.JScrollPane();
caseDetailsTable = new javax.swing.JTable();
closeButton = new javax.swing.JButton();
setTitle(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.title")); // NOI18N
setMinimumSize(new java.awt.Dimension(545, 415));
showCasesPanel.setPreferredSize(new java.awt.Dimension(527, 407));
showCasesScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
showCasesScrollPane.setPreferredSize(new java.awt.Dimension(535, 415));
innerCaseScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
caseDetailsTable.setAutoCreateRowSorter(true);
caseDetailsTable.setModel(tableModel);
caseDetailsTable.setToolTipText(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.caseDetailsTable.toolTipText")); // NOI18N
caseDetailsTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
caseDetailsTable.getTableHeader().setReorderingAllowed(false);
innerCaseScrollPane.setViewportView(caseDetailsTable);
caseDetailsTable.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.caseDetailsTable.AccessibleContext.accessibleDescription")); // NOI18N
javax.swing.GroupLayout outCasesPaneLayout = new javax.swing.GroupLayout(outCasesPane);
outCasesPane.setLayout(outCasesPaneLayout);
outCasesPaneLayout.setHorizontalGroup(
outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 1423, Short.MAX_VALUE)
.addGroup(outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(innerCaseScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1423, Short.MAX_VALUE))
);
outCasesPaneLayout.setVerticalGroup(
outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 500, Short.MAX_VALUE)
.addGroup(outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(innerCaseScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 500, Short.MAX_VALUE))
);
showCasesScrollPane.setViewportView(outCasesPane);
javax.swing.GroupLayout showCasesPanelLayout = new javax.swing.GroupLayout(showCasesPanel);
showCasesPanel.setLayout(showCasesPanelLayout);
showCasesPanelLayout.setHorizontalGroup(
showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 1188, Short.MAX_VALUE)
.addGroup(showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(showCasesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 527, Short.MAX_VALUE))
);
showCasesPanelLayout.setVerticalGroup(
showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 473, Short.MAX_VALUE)
.addGroup(showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(showCasesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 407, Short.MAX_VALUE))
);
org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.closeButton.text")); // NOI18N
closeButton.setActionCommand(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.closeButton.actionCommand")); // NOI18N
closeButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
closeButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(6, 6, 6)
.addComponent(showCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1188, Short.MAX_VALUE)
.addGap(6, 6, 6))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(closeButton)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(6, 6, 6)
.addComponent(showCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 473, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(closeButton)
.addContainerGap())
);
closeButton.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.closeButton.AccessibleContext.accessibleName")); // NOI18N
pack();
}// </editor-fold>//GEN-END:initComponents
private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
dispose();
}//GEN-LAST:event_closeButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JTable caseDetailsTable;
private javax.swing.JButton closeButton;
private javax.swing.JScrollPane innerCaseScrollPane;
private javax.swing.JPanel outCasesPane;
private javax.swing.JPanel showCasesPanel;
private javax.swing.JScrollPane showCasesScrollPane;
// End of variables declaration//GEN-END:variables
}

View File

@ -1,187 +0,0 @@
/*
* Central Repository
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.centralrepository.optionspanel;
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
/**
* Model for cells to display correlation case information
*/
class ShowCasesTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
@Messages({"ShowCasesTableModel.case=Case Name",
"ShowCasesTableModel.creationDate=Creation Date",
"ShowCasesTableModel.caseNumber=Case Number",
"ShowCasesTableModel.examinerName=Examiner Name",
"ShowCasesTableModel.examinerEmail=Examiner Email",
"ShowCasesTableModel.examinerPhone=Examiner Phone",
"ShowCasesTableModel.notes=Notes",
"ShowCasesTableModel.noData=No Cases"})
/**
* Enum which lists columns of interest from CorrelationCase.
*/
enum TableColumns {
// Ordering here determines displayed column order in Content Viewer.
// If order is changed, update the CellRenderer to ensure correct row coloring.
CASE_NAME(Bundle.ShowCasesTableModel_case(), 200),
CREATION_DATE(Bundle.ShowCasesTableModel_creationDate(), 150),
CASE_NUMBER(Bundle.ShowCasesTableModel_caseNumber(), 100),
EXAMINER_NAME(Bundle.ShowCasesTableModel_examinerName(), 200),
EXAMINER_EMAIL(Bundle.ShowCasesTableModel_examinerEmail(), 100),
EXAMINER_PHONE(Bundle.ShowCasesTableModel_examinerPhone(), 100),
NOTES(Bundle.ShowCasesTableModel_notes(), 450);
private final String columnName;
private final int columnWidth;
TableColumns(String columnName, int columnWidth) {
this.columnName = columnName;
this.columnWidth = columnWidth;
}
String columnName() {
return columnName;
}
int columnWidth() {
return columnWidth;
}
};
/**
* list of Eam Cases from central repository.
*/
private List<CorrelationCase> eamCases;
ShowCasesTableModel() {
eamCases = new ArrayList<>();
}
@Override
public int getColumnCount() {
return TableColumns.values().length;
}
/**
* Get the preferred width that has been configured for this column.
*
* A value of 0 means that no preferred width has been defined for this
* column.
*
* @param colIdx Column index
*
* @return preferred column width >= 0
*/
int getColumnPreferredWidth(int colIdx) {
return TableColumns.values()[colIdx].columnWidth();
}
@Override
public int getRowCount() {
return eamCases.size();
}
@Override
public String getColumnName(int colIdx) {
return TableColumns.values()[colIdx].columnName();
}
@Override
public Object getValueAt(int rowIdx, int colIdx) {
if (eamCases.isEmpty()) {
return Bundle.ShowCasesTableModel_noData();
}
return mapValueById(rowIdx, TableColumns.values()[colIdx]);
}
Object getRow(int rowIdx) {
return eamCases.get(rowIdx);
}
/**
* Map a rowIdx and colId to the value in that cell.
*
* @param rowIdx Index of row to search
* @param colId ID of column to search
*
* @return value in the cell
*/
private Object mapValueById(int rowIdx, TableColumns colId) {
CorrelationCase eamCase = eamCases.get(rowIdx);
String value = Bundle.ShowCasesTableModel_noData();
switch (colId) {
case CASE_NAME:
value = eamCase.getDisplayName();
break;
case CREATION_DATE:
value = eamCase.getCreationDate();
break;
case CASE_NUMBER:
value = eamCase.getCaseNumber();
break;
case EXAMINER_NAME:
value = eamCase.getExaminerName();
break;
case EXAMINER_EMAIL:
value = eamCase.getExaminerEmail();
break;
case EXAMINER_PHONE:
value = eamCase.getExaminerPhone();
break;
case NOTES:
value = eamCase.getNotes();
break;
default:
break;
}
return value;
}
@Override
public Class<String> getColumnClass(int colIdx) {
return String.class;
}
/**
* Add one local central repository case to the table.
*
* @param eamCase central repository case to add to the
* table
*/
void addEamCase(CorrelationCase eamCase) {
eamCases.add(eamCase);
fireTableDataChanged();
}
void clearTable() {
eamCases.clear();
fireTableDataChanged();
}
}

View File

@ -303,23 +303,25 @@
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="dateRangeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="endCheckBox" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
<Component id="endDatePicker" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="startCheckBox" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
<Component id="startDatePicker" min="-2" max="-2" attributes="0"/>
<Component id="dateRangeLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="endCheckBox" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
<Component id="endDatePicker" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="startCheckBox" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="12" max="-2" attributes="0"/>
<Component id="startDatePicker" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>

View File

@ -124,7 +124,8 @@ final public class FiltersPanel extends JPanel {
updateFilters(true);
UserPreferences.addChangeListener(preferenceChangeEvent -> {
if (preferenceChangeEvent.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME)) {
if (preferenceChangeEvent.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME) ||
preferenceChangeEvent.getKey().equals(UserPreferences.TIME_ZONE_FOR_DISPLAYS)) {
updateTimeZone();
}
});
@ -175,7 +176,7 @@ final public class FiltersPanel extends JPanel {
}
private void updateTimeZone() {
dateRangeLabel.setText("Date Range ( " + Utils.getUserPreferredZoneId().toString() + "):");
dateRangeLabel.setText("Date Range (" + Utils.getUserPreferredZoneId().toString() + "):");
}
/**

View File

@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.communications;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.TimeZone;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
import org.sleuthkit.datamodel.Account;
@ -33,7 +34,8 @@ class Utils {
}
static ZoneId getUserPreferredZoneId() {
ZoneId zone = UserPreferences.displayTimesInLocalTime() ? ZoneOffset.systemDefault() : ZoneOffset.UTC;
ZoneId zone = UserPreferences.displayTimesInLocalTime() ?
ZoneOffset.systemDefault() : TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays()).toZoneId();
return zone;
}

View File

@ -424,7 +424,7 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
try (Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(
"SELECT count (*) as count FROM " + "\"" + tableName + "\"")) { //NON-NLS{
"SELECT count (*) as count FROM " + "\"" + tableName + "\"")) { //NON-NLS
numRows = resultSet.getInt("count");
numEntriesField.setText(numRows + " entries");
@ -442,9 +442,23 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
} else {
exportCsvButton.setEnabled(false);
nextPageButton.setEnabled(false);
selectedTableView.setupTable(Collections.emptyList());
}
//Execute a dummy SELECT * statement so that the metadata
//contains all column names
Map<String, Object> columnRow;
try (ResultSet metaDataResultSet = statement.executeQuery(
"SELECT * FROM " + "\"" + tableName + "\"")) {
//Column names are not found in the metadata of the result set
//above.
ResultSetMetaData metaData = metaDataResultSet.getMetaData();
columnRow = new LinkedHashMap<>();
for(int i = 1; i < metaData.getColumnCount(); i++){
columnRow.put(metaData.getColumnName(i), "");
}
}
selectedTableView.setupTable(Collections.singletonList(columnRow));
}
} catch (SQLException ex) {
logger.log(Level.SEVERE, String.format("Failed to load table %s from DB file '%s' (objId=%d)", tableName, sqliteDbFile.getName(), sqliteDbFile.getId()), ex); //NON-NLS
MessageNotifyUtil.Message.error(Bundle.SQLiteViewer_selectTable_errorText(tableName));

View File

@ -24,6 +24,7 @@ import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo;
import java.util.prefs.PreferenceChangeListener;
import java.util.prefs.Preferences;
import org.openide.util.NbPreferences;
import org.python.icu.util.TimeZone;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.TextConverterException;
@ -45,6 +46,7 @@ public final class UserPreferences {
public static final String HIDE_SLACK_FILES_IN_DATA_SRCS_TREE = "HideSlackFilesInDataSourcesTree"; //NON-NLS
public static final String HIDE_SLACK_FILES_IN_VIEWS_TREE = "HideSlackFilesInViewsTree"; //NON-NLS
public static final String DISPLAY_TIMES_IN_LOCAL_TIME = "DisplayTimesInLocalTime"; //NON-NLS
public static final String TIME_ZONE_FOR_DISPLAYS = "TimeZoneForDisplays"; //NON-NLS
public static final String NUMBER_OF_FILE_INGEST_THREADS = "NumberOfFileIngestThreads"; //NON-NLS
public static final String IS_MULTI_USER_MODE_ENABLED = "IsMultiUserModeEnabled"; //NON-NLS
public static final String EXTERNAL_DATABASE_HOSTNAME_OR_IP = "ExternalDatabaseHostnameOrIp"; //NON-NLS
@ -182,6 +184,14 @@ public final class UserPreferences {
preferences.putBoolean(DISPLAY_TIMES_IN_LOCAL_TIME, value);
}
public static String getTimeZoneForDisplays() {
return preferences.get(TIME_ZONE_FOR_DISPLAYS, TimeZone.GMT_ZONE.getID());
}
public static void setTimeZoneForDisplays(String timeZone) {
preferences.put(TIME_ZONE_FOR_DISPLAYS, timeZone);
}
public static int numberOfFileIngestThreads() {
return preferences.getInt(NUMBER_OF_FILE_INGEST_THREADS, 2);
}

View File

@ -180,7 +180,6 @@ ViewPreferencesPanel.useBestViewerRadioButton.text=Change to the most specific f
ViewPreferencesPanel.keepCurrentViewerRadioButton.toolTipText=For example, stay in Hex view when a JPEG is selected.
ViewPreferencesPanel.keepCurrentViewerRadioButton.text=Stay on the same file viewer
ViewPreferencesPanel.useLocalTimeRadioButton.text=Use local time zone
ViewPreferencesPanel.useGMTTimeRadioButton.text=Use GMT
ViewPreferencesPanel.dataSourcesHideKnownCheckbox.text=Data Sources area (the directory hierarchy)
ViewPreferencesPanel.viewsHideKnownCheckbox.text=Views area
ViewPreferencesPanel.dataSourcesHideSlackCheckbox.text=Data Sources area (the directory hierarchy)
@ -192,3 +191,4 @@ ViewPreferencesPanel.centralRepoLabel.text=Do not use Central Repository for:
ViewPreferencesPanel.commentsOccurencesColumnsCheckbox.text=C(omments) and O(ccurences) columns to reduce loading times
ViewPreferencesPanel.deletedFilesLimitCheckbox.text=Limit to 10,000
ViewPreferencesPanel.deletedFilesLimitLabel.text=Limit number of deleted files displayed:
ViewPreferencesPanel.useAnotherTimeRadioButton.text=Use another time zone

View File

@ -128,6 +128,5 @@ ViewPreferencesPanel.useBestViewerRadioButton.text=\u6700\u3082\u5c02\u9580\u768
ViewPreferencesPanel.keepCurrentViewerRadioButton.text=\u305d\u306e\u307e\u307e\u540c\u3058\u30d5\u30a1\u30a4\u30eb\u30d3\u30e5\u30fc\u30a2\u3092\u4f7f\u7528
ViewPreferencesPanel.keepCurrentViewerRadioButton.toolTipText=\u4f8b\u3048\u3070\u3001JPEG\u304c\u9078\u629e\u3055\u308c\u305f\u5834\u5408\u306b\u305d\u306e\u307e\u307eHEX\u30d3\u30e5\u30fc\u3092\u4f7f\u7528\u3002
ViewPreferencesPanel.useLocalTimeRadioButton.text=\u30ed\u30fc\u30ab\u30eb\u30bf\u30a4\u30e0\u30be\u30fc\u30f3\u3092\u4f7f\u7528
ViewPreferencesPanel.useGMTTimeRadioButton.text=GMT\u3092\u4f7f\u7528
ViewPreferencesPanel.dataSourcesHideKnownCheckbox.text=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u30a8\u30ea\u30a2\uff08\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u968e\u5c64\uff09
ViewPreferencesPanel.viewsHideKnownCheckbox.text=\u30d3\u30e5\u30fc\u30a8\u30ea\u30a2

View File

@ -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_INTERESTING_FILE_HIT.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;
} else {
return 6;

View File

@ -40,6 +40,7 @@ public final class TextPrompt extends JLabel
public TextPrompt(String text, JTextComponent component, Show show) {
this.component = component;
component.removeAll();
setShow(show);
document = component.getDocument();

View File

@ -31,11 +31,19 @@
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="null"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[625, 452]"/>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="viewPreferencesPanel">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[625, 452]"/>
</Property>
</Properties>
<Layout>
<DimensionLayout dim="0">
@ -87,57 +95,68 @@
<Group type="103" groupAlignment="0" attributes="0">
<Component id="commentsOccurencesColumnsCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="deletedFilesLimitCheckbox" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="deletedFilesLimitCheckbox" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="399" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="centralRepoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="135" max="-2" attributes="0"/>
<Component id="jScrollPane1" min="-2" pref="272" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="hideKnownFilesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="103" alignment="0" groupAlignment="1" attributes="0">
<Group type="103" alignment="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dataSourcesHideSlackCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="viewsHideSlackCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="hideKnownFilesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="103" alignment="0" groupAlignment="1" attributes="0">
<Group type="103" alignment="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dataSourcesHideSlackCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="viewsHideSlackCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="hideSlackFilesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dataSourcesHideKnownCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="viewsHideKnownCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<Component id="hideSlackFilesLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="dataSourcesHideKnownCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="viewsHideKnownCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="displayTimeLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="keepCurrentViewerRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useBestViewerRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useGMTTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useLocalTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="displayTimeLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="keepCurrentViewerRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useBestViewerRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useLocalTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="useAnotherTimeRadioButton" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="selectFileLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Component id="selectFileLabel" min="-2" max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="deletedFilesLimitLabel" alignment="0" min="-2" pref="215" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Component id="hideOtherUsersTagsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="centralRepoLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="deletedFilesLimitLabel" alignment="0" min="-2" pref="215" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="10" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -158,6 +177,16 @@
<Component id="dataSourcesHideSlackCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="viewsHideSlackCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="centralRepoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="commentsOccurencesColumnsCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="deletedFilesLimitLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="selectFileLabel" min="-2" max="-2" attributes="0"/>
@ -169,20 +198,12 @@
<Component id="displayTimeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="useLocalTimeRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="useGMTTimeRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="useAnotherTimeRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" min="-2" pref="67" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="hideOtherUsersTagsCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="centralRepoLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="commentsOccurencesColumnsCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="deletedFilesLimitLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="deletedFilesLimitCheckbox" min="-2" pref="33" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
@ -295,14 +316,14 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useLocalTimeRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="useGMTTimeRadioButton">
<Component class="javax.swing.JRadioButton" name="useAnotherTimeRadioButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.useGMTTimeRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="ViewPreferencesPanel.useAnotherTimeRadioButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useGMTTimeRadioButtonActionPerformed"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useAnotherTimeRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="hideOtherUsersTagsCheckbox">
@ -356,6 +377,28 @@
</Property>
</Properties>
</Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane1">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JList" name="timeZoneList">
<Properties>
<Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor">
<StringArray count="0"/>
</Property>
</Properties>
<Events>
<EventHandler event="valueChanged" listener="javax.swing.event.ListSelectionListener" parameters="javax.swing.event.ListSelectionEvent" handler="timeZoneListValueChanged"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/>
</AuxValues>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="currentCaseSettingsPanel">

View File

@ -19,12 +19,14 @@
package org.sleuthkit.autopsy.corecomponents;
import java.util.Objects;
import java.util.TimeZone;
import javax.swing.JPanel;
import org.netbeans.spi.options.OptionsPanelController;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.CasePreferences;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.deletedFiles.DeletedFilePreferences;
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
@ -44,6 +46,8 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
public ViewPreferencesPanel(boolean immediateUpdates) {
initComponents();
this.immediateUpdates = immediateUpdates;
this.timeZoneList.setListData(TimeZoneUtils.createTimeZoneList().stream().toArray(String[]::new));
}
@Override
@ -54,8 +58,10 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
useBestViewerRadioButton.setSelected(!keepPreferredViewer);
boolean useLocalTime = UserPreferences.displayTimesInLocalTime();
timeZoneList.setEnabled(!useLocalTime);
timeZoneList.setSelectedValue(TimeZoneUtils.createTimeZoneString(TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays())), true);
useLocalTimeRadioButton.setSelected(useLocalTime);
useGMTTimeRadioButton.setSelected(!useLocalTime);
useAnotherTimeRadioButton.setSelected(!useLocalTime);
dataSourcesHideKnownCheckbox.setSelected(UserPreferences.hideKnownFilesInDataSourcesTree());
viewsHideKnownCheckbox.setSelected(UserPreferences.hideKnownFilesInViewsTree());
@ -84,6 +90,9 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
public void store() {
UserPreferences.setKeepPreferredContentViewer(keepCurrentViewerRadioButton.isSelected());
UserPreferences.setDisplayTimesInLocalTime(useLocalTimeRadioButton.isSelected());
if (useAnotherTimeRadioButton.isSelected()) {
UserPreferences.setTimeZoneForDisplays(timeZoneList.getSelectedValue().substring(11).trim());
}
UserPreferences.setHideKnownFilesInDataSourcesTree(dataSourcesHideKnownCheckbox.isSelected());
UserPreferences.setHideKnownFilesInViewsTree(viewsHideKnownCheckbox.isSelected());
UserPreferences.setHideSlackFilesInDataSourcesTree(dataSourcesHideSlackCheckbox.isSelected());
@ -135,19 +144,24 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
viewsHideSlackCheckbox = new javax.swing.JCheckBox();
displayTimeLabel = new javax.swing.JLabel();
useLocalTimeRadioButton = new javax.swing.JRadioButton();
useGMTTimeRadioButton = new javax.swing.JRadioButton();
useAnotherTimeRadioButton = new javax.swing.JRadioButton();
hideOtherUsersTagsCheckbox = new javax.swing.JCheckBox();
hideOtherUsersTagsLabel = new javax.swing.JLabel();
commentsOccurencesColumnsCheckbox = new javax.swing.JCheckBox();
centralRepoLabel = new javax.swing.JLabel();
deletedFilesLimitCheckbox = new javax.swing.JCheckBox();
deletedFilesLimitLabel = new javax.swing.JLabel();
jScrollPane1 = new javax.swing.JScrollPane();
timeZoneList = new javax.swing.JList<>();
currentCaseSettingsPanel = new javax.swing.JPanel();
groupByDataSourceCheckbox = new javax.swing.JCheckBox();
currentSessionSettingsPanel = new javax.swing.JPanel();
hideRejectedResultsCheckbox = new javax.swing.JCheckBox();
viewPreferencesScrollPane.setBorder(null);
viewPreferencesScrollPane.setPreferredSize(new java.awt.Dimension(625, 452));
viewPreferencesPanel.setPreferredSize(new java.awt.Dimension(625, 452));
globalSettingsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.globalSettingsPanel.border.title"))); // NOI18N
@ -210,10 +224,10 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
}
});
org.openide.awt.Mnemonics.setLocalizedText(useGMTTimeRadioButton, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.useGMTTimeRadioButton.text")); // NOI18N
useGMTTimeRadioButton.addActionListener(new java.awt.event.ActionListener() {
org.openide.awt.Mnemonics.setLocalizedText(useAnotherTimeRadioButton, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.useAnotherTimeRadioButton.text")); // NOI18N
useAnotherTimeRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
useGMTTimeRadioButtonActionPerformed(evt);
useAnotherTimeRadioButtonActionPerformed(evt);
}
});
@ -244,6 +258,13 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
org.openide.awt.Mnemonics.setLocalizedText(deletedFilesLimitLabel, org.openide.util.NbBundle.getMessage(ViewPreferencesPanel.class, "ViewPreferencesPanel.deletedFilesLimitLabel.text")); // NOI18N
timeZoneList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
timeZoneListValueChanged(evt);
}
});
jScrollPane1.setViewportView(timeZoneList);
javax.swing.GroupLayout globalSettingsPanelLayout = new javax.swing.GroupLayout(globalSettingsPanel);
globalSettingsPanel.setLayout(globalSettingsPanelLayout);
globalSettingsPanelLayout.setHorizontalGroup(
@ -256,41 +277,48 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(commentsOccurencesColumnsCheckbox)
.addComponent(hideOtherUsersTagsCheckbox)
.addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGap(399, 399, 399))))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addComponent(centralRepoLabel)
.addGap(135, 135, 135)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 272, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(hideKnownFilesLabel)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(hideKnownFilesLabel)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dataSourcesHideSlackCheckbox)
.addComponent(viewsHideSlackCheckbox)))
.addComponent(hideSlackFilesLabel))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dataSourcesHideKnownCheckbox)
.addComponent(viewsHideKnownCheckbox)))))
.addGap(18, 18, 18)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(displayTimeLabel)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dataSourcesHideSlackCheckbox)
.addComponent(viewsHideSlackCheckbox)))
.addComponent(hideSlackFilesLabel))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dataSourcesHideKnownCheckbox)
.addComponent(viewsHideKnownCheckbox)))))
.addGap(18, 18, 18)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(displayTimeLabel)
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(keepCurrentViewerRadioButton)
.addComponent(useBestViewerRadioButton)
.addComponent(useGMTTimeRadioButton)
.addComponent(useLocalTimeRadioButton)))
.addComponent(selectFileLabel)))
.addComponent(hideOtherUsersTagsLabel)
.addComponent(centralRepoLabel)
.addComponent(deletedFilesLimitLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 10, Short.MAX_VALUE)))
.addContainerGap())
.addComponent(keepCurrentViewerRadioButton)
.addComponent(useBestViewerRadioButton)
.addComponent(useLocalTimeRadioButton)
.addComponent(useAnotherTimeRadioButton)))
.addComponent(selectFileLabel)))
.addComponent(hideOtherUsersTagsLabel)
.addComponent(deletedFilesLimitLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())))
);
globalSettingsPanelLayout.setVerticalGroup(
globalSettingsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -308,7 +336,17 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(dataSourcesHideSlackCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(viewsHideSlackCheckbox))
.addComponent(viewsHideSlackCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(hideOtherUsersTagsLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(hideOtherUsersTagsCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(centralRepoLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(commentsOccurencesColumnsCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(deletedFilesLimitLabel))
.addGroup(globalSettingsPanelLayout.createSequentialGroup()
.addComponent(selectFileLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -320,17 +358,9 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useLocalTimeRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useGMTTimeRadioButton)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(hideOtherUsersTagsLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(hideOtherUsersTagsCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(centralRepoLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(commentsOccurencesColumnsCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(deletedFilesLimitLabel)
.addComponent(useAnotherTimeRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(deletedFilesLimitCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 33, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0))
@ -415,11 +445,11 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(viewPreferencesScrollPane)
.addComponent(viewPreferencesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(viewPreferencesScrollPane)
.addComponent(viewPreferencesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
}// </editor-fold>//GEN-END:initComponents
@ -445,7 +475,8 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
private void useLocalTimeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useLocalTimeRadioButtonActionPerformed
useLocalTimeRadioButton.setSelected(true);
useGMTTimeRadioButton.setSelected(false);
useAnotherTimeRadioButton.setSelected(false);
timeZoneList.setEnabled(false);
if (immediateUpdates) {
UserPreferences.setDisplayTimesInLocalTime(true);
} else {
@ -453,15 +484,16 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
}
}//GEN-LAST:event_useLocalTimeRadioButtonActionPerformed
private void useGMTTimeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useGMTTimeRadioButtonActionPerformed
private void useAnotherTimeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useAnotherTimeRadioButtonActionPerformed
useLocalTimeRadioButton.setSelected(false);
useGMTTimeRadioButton.setSelected(true);
useAnotherTimeRadioButton.setSelected(true);
timeZoneList.setEnabled(true);
if (immediateUpdates) {
UserPreferences.setDisplayTimesInLocalTime(false);
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_useGMTTimeRadioButtonActionPerformed
}//GEN-LAST:event_useAnotherTimeRadioButtonActionPerformed
private void dataSourcesHideKnownCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dataSourcesHideKnownCheckboxActionPerformed
if (immediateUpdates) {
@ -535,6 +567,14 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
}
}//GEN-LAST:event_deletedFilesLimitCheckboxActionPerformed
private void timeZoneListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_timeZoneListValueChanged
if (immediateUpdates && useAnotherTimeRadioButton.isSelected()) {
UserPreferences.setTimeZoneForDisplays(timeZoneList.getSelectedValue().substring(11).trim());
} else {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}//GEN-LAST:event_timeZoneListValueChanged
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel centralRepoLabel;
@ -553,10 +593,12 @@ public class ViewPreferencesPanel extends JPanel implements OptionsPanel {
private javax.swing.JLabel hideOtherUsersTagsLabel;
private javax.swing.JCheckBox hideRejectedResultsCheckbox;
private javax.swing.JLabel hideSlackFilesLabel;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JRadioButton keepCurrentViewerRadioButton;
private javax.swing.JLabel selectFileLabel;
private javax.swing.JList<String> timeZoneList;
private javax.swing.JRadioButton useAnotherTimeRadioButton;
private javax.swing.JRadioButton useBestViewerRadioButton;
private javax.swing.JRadioButton useGMTTimeRadioButton;
private javax.swing.JRadioButton useLocalTimeRadioButton;
private javax.swing.JPanel viewPreferencesPanel;
private javax.swing.JScrollPane viewPreferencesScrollPane;

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012-2015 Basis Technology Corp.
* Copyright 2012-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -18,14 +18,22 @@
*/
package org.sleuthkit.autopsy.coreutils;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.StringTokenizer;
public class NetworkUtils {
private NetworkUtils() {
}
/**
* Set the host name variable. Sometimes the network can be finicky, so the
* answer returned by getHostName() could throw an exception or be null.
* Have it read the environment variable if getHostName() is unsuccessful.
*
* @return the local host name
*/
public static String getLocalHostName() {
String hostName = "";
@ -41,4 +49,78 @@ public class NetworkUtils {
}
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;
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -20,7 +20,13 @@ package org.sleuthkit.autopsy.coreutils;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
/**
* Utility methods for workig with time zones.
@ -41,7 +47,7 @@ public class TimeZoneUtils {
java.util.TimeZone zone = java.util.TimeZone.getTimeZone(timeZoneId);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int min = (offset % 3600) / 60;
int min = Math.abs((offset % 3600) / 60);
DateFormat dfm = new SimpleDateFormat("z");
dfm.setTimeZone(zone);
@ -60,6 +66,73 @@ public class TimeZoneUtils {
return result;
}
/**
* Generate a time zone string containing the GMT offset and ID.
*
* @param timeZone The time zone.
*
* @return The time zone string.
*/
public static String createTimeZoneString(TimeZone timeZone) {
int offset = timeZone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = Math.abs((offset % 3600) / 60);
return String.format("(GMT%+d:%02d) %s", hour, minutes, timeZone.getID()); //NON-NLS
}
/**
* Generates a list of time zones.
*/
public static List<String> createTimeZoneList() {
/*
* Create a list of time zones.
*/
List<TimeZone> timeZoneList = new ArrayList<>();
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
/*
* DateFormat dfm = new SimpleDateFormat("z");
* dfm.setTimeZone(zone); boolean hasDaylight =
* zone.useDaylightTime(); String first = dfm.format(new Date(2010,
* 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid
* = hour * -1; String result = first + Integer.toString(mid);
* if(hasDaylight){ result = result + second; }
* timeZoneComboBox.addItem(item + " (" + result + ")");
*/
timeZoneList.add(TimeZone.getTimeZone(id));
}
/*
* 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;
}
/**
* Prevents instantiation.
*/

View File

@ -145,7 +145,7 @@ public final class ContentUtils {
try {
if (!shouldDisplayTimesInLocalTime()) {
return TimeZone.getTimeZone("GMT");
return TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays());
} else {
final Content dataSource = content.getDataSource();
if ((dataSource != null) && (dataSource instanceof Image)) {

View File

@ -20,8 +20,7 @@ package org.sleuthkit.autopsy.datasourceprocessors;
import java.io.File;
import java.util.Calendar;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.List;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.event.DocumentEvent;
@ -32,6 +31,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.PathValidator;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
/**
* Allows examiner to supply a raw data source.
@ -82,26 +82,13 @@ final class RawDSInputPanel extends JPanel implements DocumentListener {
* machine time zone to be selected.
*/
private void createTimeZoneList() {
// load and add all timezone
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
TimeZone zone = TimeZone.getTimeZone(id);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id);
timeZoneComboBox.addItem(item);
List<String> timeZoneList = TimeZoneUtils.createTimeZoneList();
for (String timeZone : timeZoneList) {
timeZoneComboBox.addItem(timeZone);
}
// get the current timezone
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
int thisOffset = thisTimeZone.getRawOffset() / 1000;
int thisHour = thisOffset / 3600;
int thisMinutes = (thisOffset % 3600) / 60;
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
// set the selected timezone
timeZoneComboBox.setSelectedItem(formatted);
timeZoneComboBox.setSelectedItem(TimeZoneUtils.createTimeZoneString(Calendar.getInstance().getTimeZone()));
}
/**

View File

@ -167,6 +167,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
public void preferenceChange(PreferenceChangeEvent evt) {
switch (evt.getKey()) {
case UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME:
case UserPreferences.TIME_ZONE_FOR_DISPLAYS:
case UserPreferences.HIDE_KNOWN_FILES_IN_DATA_SRCS_TREE:
case UserPreferences.HIDE_SLACK_FILES_IN_DATA_SRCS_TREE:
case UserPreferences.HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES:

View File

@ -29,7 +29,6 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SimpleTimeZone;
@ -44,6 +43,7 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
/**
* Filters file date properties (modified/created/etc.. times)
@ -144,30 +144,15 @@ class DateSearchFilter extends AbstractFileSearchFilter<DateSearchPanel> {
Case currentCase = Case.getCurrentCaseThrows(); // get the most updated case
Set<TimeZone> caseTimeZones = currentCase.getTimeZones();
Iterator<TimeZone> iterator = caseTimeZones.iterator();
while (iterator.hasNext()) {
TimeZone zone = iterator.next();
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, zone.getID()); //NON-NLS
timeZones.add(item);
for (TimeZone timeZone : caseTimeZones) {
timeZones.add(TimeZoneUtils.createTimeZoneString(timeZone));
}
if (caseTimeZones.size() > 0) {
timeZones.add(SEPARATOR);
}
// load and add all timezone
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
TimeZone zone = TimeZone.getTimeZone(id);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id); //NON-NLS
timeZones.add(item);
}
timeZones.addAll(TimeZoneUtils.createTimeZoneList());
} catch (NoCurrentCaseException ex) {
// No current case.
}

View File

@ -269,8 +269,7 @@ class MSOfficeEmbeddedContentExtractor {
HWPFDocument doc = new HWPFDocument(new ReadContentInputStream(af));
PicturesTable pictureTable = doc.getPicturesTable();
listOfAllPictures = pictureTable.getAllPictures();
} catch (IOException | IllegalArgumentException
| IndexOutOfBoundsException | NullPointerException ex) {
} catch (Exception ex) {
// IOException:
// Thrown when the document has issues being read.
@ -286,10 +285,9 @@ class MSOfficeEmbeddedContentExtractor {
// These get thrown in certain images. The reason is unknown. It is
// likely due to problems with the file formats that POI is poorly
// handling.
return null;
} catch (Throwable ex) {
// instantiating POI containers throw RuntimeExceptions
LOGGER.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docContainer.init.err", af.getName()), ex); //NON-NLS
//Any runtime exception escaping
LOGGER.log(Level.WARNING, "Word document container could not be initialized. Reason: {0}", ex.getMessage()); //NON-NLS
return null;
}
@ -333,8 +331,7 @@ class MSOfficeEmbeddedContentExtractor {
try {
HSLFSlideShow ppt = new HSLFSlideShow(new ReadContentInputStream(af));
listOfAllPictures = ppt.getPictureData();
} catch (IOException | IllegalArgumentException
| IndexOutOfBoundsException ex) {
} catch (Exception ex) {
// IllegalArgumentException:
// This will catch OldFileFormatException, which is thrown when the
// document version is unsupported. The IllegalArgumentException may
@ -346,10 +343,7 @@ class MSOfficeEmbeddedContentExtractor {
// This gets thrown in certain images. The reason is unknown. It is
// likely due to problems with the file formats that POI is poorly
// handling.
return null;
} catch (Throwable ex) {
// instantiating POI containers throw RuntimeExceptions
LOGGER.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptContainer.init.err", af.getName()), ex); //NON-NLS
LOGGER.log(Level.WARNING, "PPT container could not be initialized. Reason: {0}", ex.getMessage()); //NON-NLS
return null;
}
@ -422,9 +416,7 @@ class MSOfficeEmbeddedContentExtractor {
try {
Workbook xls = new HSSFWorkbook(new ReadContentInputStream(af));
listOfAllPictures = xls.getAllPictures();
} catch (IOException | LeftoverDataException
| RecordFormatException | IllegalArgumentException
| IndexOutOfBoundsException ex) {
} catch (Exception ex) {
// IllegalArgumentException:
// This will catch OldFileFormatException, which is thrown when the
// document version is unsupported. The IllegalArgumentException may
@ -443,10 +435,7 @@ class MSOfficeEmbeddedContentExtractor {
// These get thrown in certain images. The reason is unknown. It is
// likely due to problems with the file formats that POI is poorly
// handling.
return null;
} catch (Throwable ex) {
// instantiating POI containers throw RuntimeExceptions
LOGGER.log(Level.SEVERE, String.format("%s%s", NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsContainer.init.err", af.getName()), af.getName()), ex); //NON-NLS
LOGGER.log(Level.WARNING, "Excel (.xls) document container could not be initialized. Reason: {0}", ex.getMessage()); //NON-NLS
return null;
}

View File

@ -180,6 +180,15 @@ class SevenZipExtractor {
* @return true if potential zip bomb, false otherwise
*/
private boolean isZipBombArchiveItemCheck(AbstractFile archiveFile, ISevenZipInArchive inArchive, int inArchiveItemIndex, ConcurrentHashMap<Long, Archive> depthMap, String escapedFilePath) {
//If a file is corrupted as a result of reconstructing it from unallocated space, then
//7zip does a poor job estimating the original uncompressed file size.
//As a result, many corrupted files have wonky compression ratios and could flood the UI
//with false zip bomb notifications. The decision was made to skip compression ratio checks
//for unallocated zip files. Instead, we let the depth be an indicator of a zip bomb.
if(archiveFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)) {
return false;
}
try {
final Long archiveItemSize = (Long) inArchive.getProperty(
inArchiveItemIndex, PropID.SIZE);
@ -540,7 +549,6 @@ class SevenZipExtractor {
inArchive = SevenZip.openInArchive(options, stream, password);
}
numItems = inArchive.getNumberOfItems();
logger.log(Level.INFO, "Count of items in archive: {0}: {1}", new Object[]{escapedArchiveFilePath, numItems}); //NON-NLS
progress.start(numItems);
progressStarted = true;

View File

@ -28,6 +28,7 @@ import com.healthmarketscience.jackcess.util.MemFileChannel;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.BufferUnderflowException;
import java.util.logging.Level;
import org.apache.tika.exception.EncryptedDocumentException;
import org.apache.tika.exception.TikaException;
@ -313,7 +314,12 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
DatabaseBuilder databaseBuilder = new DatabaseBuilder();
databaseBuilder.setChannel(memFileChannel);
databaseBuilder.setCodecProvider(codecProvider);
Database accessDatabase = databaseBuilder.open();
Database accessDatabase;
try {
accessDatabase = databaseBuilder.open();
} catch (IOException | BufferUnderflowException | IndexOutOfBoundsException ignored) {
return passwordProtected;
}
/*
* No exception has been thrown at this point, so the file
* is either a JET database, or an unprotected ACE database.

View File

@ -91,7 +91,7 @@ HashDbImportDatabaseDialog.errorMessage.failedToOpenHashDbMsg=Failed to open has
HashLookupModuleFactory.moduleName.text=Hash Lookup
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.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.settingKnownBadStateErr=Error encountered while setting notable state for {0}.
HashDbIngestModule.lookingUpKnownBadHashValueErr=Error encountered while looking up notable hash value for {0}.

View File

@ -227,7 +227,9 @@ public class HashDbIngestModule implements FileIngestModule {
services.postMessage(IngestMessage.createErrorMessage(
HashLookupModuleFactory.getModuleName(),
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;
}
}

View File

@ -649,6 +649,15 @@ public final class FilesSet implements Serializable {
this.textMatcher = new FilesSet.Rule.RegexMatcher(regex);
}
/**
* Construct a case-insensitive multi-value text condition.
*
* @param values The list of values in which to look for a match.
*/
AbstractTextCondition(List<String> values) {
this.textMatcher = new FilesSet.Rule.CaseInsensitiveMultiValueStringComparisionMatcher(values);
}
/**
* Get the text the condition matches.
*
@ -820,11 +829,11 @@ public final class FilesSet implements Serializable {
*
* @param extension The file name extension to be matched.
*/
public ExtensionCondition(String extension) {
public ExtensionCondition(List<String> extensions) {
// If there is a leading ".", strip it since
// AbstractFile.getFileNameExtension() returns just the
// extension chars and not the dot.
super(extension.startsWith(".") ? extension.substring(1) : extension, false);
super(extensions);
}
/**
@ -948,6 +957,60 @@ public final class FilesSet implements Serializable {
}
}
/**
* A text matcher that looks for a single case-insensitive string match
* in a multi-value list.
*/
private static class CaseInsensitiveMultiValueStringComparisionMatcher implements TextMatcher {
private static final long serialVersionUID = 1L;
private final List<String> valuesToMatch;
/**
* Construct a text matcher that looks for a single case-insensitive
* string match in a multi-value list.
*
* @param valuesToMatch The list of values in which to look for a
* match.
*/
CaseInsensitiveMultiValueStringComparisionMatcher(List<String> valuesToMatch) {
List<String> values = new ArrayList<>(valuesToMatch);
for (int i=0; i < values.size(); i++) {
// Remove leading and trailing whitespace.
String tempValue = values.get(i).trim();
// Strip "." from the start of the extension if it exists.
if (tempValue.startsWith(".")) {
tempValue = tempValue.substring(1);
}
values.set(i, tempValue);
}
this.valuesToMatch = values;
}
@Override
public String getTextToMatch() {
return String.join(",", this.valuesToMatch);
}
@Override
public boolean isRegex() {
return false;
}
@Override
public boolean textMatches(String subject) {
for (String value : valuesToMatch) {
if (value.equalsIgnoreCase(subject)) {
return true;
}
}
return false;
}
}
/**
* A text matcher that does regular expression matching.
*/

View File

@ -29,7 +29,7 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" alignment="0" max="32767" attributes="0"/>
<Component id="jScrollPane1" alignment="0" pref="800" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
@ -173,7 +173,7 @@
<Component id="deleteRuleButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace min="24" pref="47" max="32767" attributes="0"/>
<EmptySpace min="24" max="32767" attributes="0"/>
</Group>
</Group>
</Group>

View File

@ -960,7 +960,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
.addComponent(editRuleButton)
.addGap(18, 18, 18)
.addComponent(deleteRuleButton)))
.addGap(24, 47, Short.MAX_VALUE))))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
);
jPanel1Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {copySetButton, deleteSetButton, editSetButton, exportSetButton, importSetButton, newSetButton});
@ -1060,7 +1060,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 800, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)

View File

@ -47,22 +47,23 @@
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="ruleNameTextField" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Component id="daysIncludedTextField" min="-2" pref="69" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="daysIncludedLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="ruleNameTextField" pref="249" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<Component id="fullNameRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="extensionRadioButton" min="-2" pref="98" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="nameRegexCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace min="-2" pref="1" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="fullNameRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="extensionRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="nameRegexCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<Component id="jLabel5" min="-2" max="-2" attributes="0"/>
@ -205,6 +206,9 @@
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="fullNameRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="extensionRadioButton">
<Properties>
@ -216,6 +220,9 @@
</Property>
<Property name="enabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="extensionRadioButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="nameRegexCheckbox">
<Properties>

View File

@ -18,7 +18,9 @@
*/
package org.sleuthkit.autopsy.modules.interestingitems;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.util.Arrays;
import java.util.List;
import java.util.SortedSet;
import java.util.logging.Level;
@ -31,6 +33,7 @@ import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.corecomponents.TextPrompt;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel.PANEL_TYPE;
@ -46,6 +49,8 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
"FilesSetRulePanel.kiloBytes=Kilobytes",
"FilesSetRulePanel.megaBytes=Megabytes",
"FilesSetRulePanel.gigaBytes=Gigabytes",
"FilesSetRulePanel.nameTextField.fullNameExample=Example: \"file.exe\"",
"FilesSetRulePanel.nameTextField.extensionExample=Examples: \"jpg\" or \"jpg,jpeg,gif\"",
"FilesSetRulePanel.NoConditionError=Must have at least one condition to make a rule.",
"FilesSetRulePanel.NoMimeTypeError=Please select a valid MIME type.",
"FilesSetRulePanel.NoNameError=Name cannot be empty",
@ -62,6 +67,7 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
private static final List<String> ILLEGAL_FILE_PATH_CHARS = FilesSetsManager.getIllegalFilePathChars();
private JButton okButton;
private JButton cancelButton;
private TextPrompt nameTextFieldPrompt;
/**
* Constructs a files set rule panel in create rule mode.
@ -87,6 +93,8 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
this.dateCheckActionPerformed(null);
populateComponentsWithDefaultValues();
this.setButtons(okButton, cancelButton);
updateNameTextFieldPrompt();
}
/**
@ -120,6 +128,34 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
populatePathConditionComponents(rule);
populateDateConditionComponents(rule);
this.setButtons(okButton, cancelButton);
updateNameTextFieldPrompt();
}
/**
* Update the text prompt of the name text field based on the input type
* selection.
*/
private void updateNameTextFieldPrompt() {
/**
* Add text prompt to the text field.
*/
String text;
if (fullNameRadioButton.isSelected()) {
text = Bundle.FilesSetRulePanel_nameTextField_fullNameExample();
} else {
text = Bundle.FilesSetRulePanel_nameTextField_extensionExample();
}
nameTextFieldPrompt = new TextPrompt(text, nameTextField);
/**
* Sets the foreground color and transparency of the text prompt.
*/
nameTextFieldPrompt.setForeground(Color.LIGHT_GRAY);
nameTextFieldPrompt.changeAlpha(0.9f); // Mostly opaque
validate();
repaint();
}
/**
@ -435,7 +471,7 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
if (!this.nameTextField.getText().isEmpty()) {
if (this.nameRegexCheckbox.isSelected()) {
try {
Pattern pattern = Pattern.compile(this.nameTextField.getText());
Pattern pattern = Pattern.compile(this.nameTextField.getText(), Pattern.CASE_INSENSITIVE);
if (this.fullNameRadioButton.isSelected()) {
condition = new FilesSet.Rule.FullNameCondition(pattern);
} else {
@ -449,7 +485,7 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
if (this.fullNameRadioButton.isSelected()) {
condition = new FilesSet.Rule.FullNameCondition(this.nameTextField.getText());
} else {
condition = new FilesSet.Rule.ExtensionCondition(this.nameTextField.getText());
condition = new FilesSet.Rule.ExtensionCondition(Arrays.asList(this.nameTextField.getText().split(",")));
}
} else {
logger.log(Level.SEVERE, "Attempt to get name condition with illegal chars"); // NON-NLS
@ -520,7 +556,7 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
if (!this.pathTextField.getText().isEmpty()) {
if (this.pathRegexCheckBox.isSelected()) {
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) {
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
@ -657,10 +693,20 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
nameButtonGroup.add(fullNameRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(fullNameRadioButton, org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.fullNameRadioButton.text")); // NOI18N
fullNameRadioButton.setEnabled(false);
fullNameRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
fullNameRadioButtonActionPerformed(evt);
}
});
nameButtonGroup.add(extensionRadioButton);
org.openide.awt.Mnemonics.setLocalizedText(extensionRadioButton, org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.extensionRadioButton.text")); // NOI18N
extensionRadioButton.setEnabled(false);
extensionRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
extensionRadioButtonActionPerformed(evt);
}
});
org.openide.awt.Mnemonics.setLocalizedText(nameRegexCheckbox, org.openide.util.NbBundle.getMessage(FilesSetRulePanel.class, "FilesSetRulePanel.nameRegexCheckbox.text")); // NOI18N
nameRegexCheckbox.setEnabled(false);
@ -782,18 +828,19 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
.addComponent(pathSeparatorInfoLabel))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(ruleNameTextField)
.addGroup(layout.createSequentialGroup()
.addComponent(daysIncludedTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 69, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(daysIncludedLabel))
.addComponent(ruleNameTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 249, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(fullNameRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(extensionRadioButton, javax.swing.GroupLayout.PREFERRED_SIZE, 98, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(nameRegexCheckbox)))
.addGap(1, 1, 1))))
.addComponent(daysIncludedLabel)
.addGap(0, 0, Short.MAX_VALUE)))
.addGap(1, 1, 1))
.addGroup(layout.createSequentialGroup()
.addComponent(fullNameRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(extensionRadioButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(nameRegexCheckbox))))
.addComponent(jLabel5)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -952,6 +999,14 @@ final class FilesSetRulePanel extends javax.swing.JPanel {
this.setOkButton();
}//GEN-LAST:event_mimeCheckActionPerformed
private void extensionRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_extensionRadioButtonActionPerformed
updateNameTextFieldPrompt();
}//GEN-LAST:event_extensionRadioButtonActionPerformed
private void fullNameRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fullNameRadioButtonActionPerformed
updateNameTextFieldPrompt();
}//GEN-LAST:event_fullNameRadioButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JRadioButton allRadioButton;
private javax.swing.JCheckBox dateCheck;

View File

@ -25,6 +25,7 @@ import java.io.IOException;
import java.io.Serializable;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -280,7 +281,7 @@ class InterestingItemsFilesSetSettings implements Serializable {
if (elem.getTagName().equals(NAME_RULE_TAG)) {
nameCondition = new FilesSet.Rule.FullNameCondition(content);
} else if (elem.getTagName().equals(EXTENSION_RULE_TAG)) {
nameCondition = new FilesSet.Rule.ExtensionCondition(content);
nameCondition = new FilesSet.Rule.ExtensionCondition(Arrays.asList(content.split(",")));
}
}
}

View File

@ -41,6 +41,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.TimeStampUtils;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DataSource;
/*
* A runnable that adds an archive data source as well as data sources contained
@ -195,10 +196,19 @@ class AddArchiveTask implements Runnable {
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;
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
break;
}

View File

@ -45,6 +45,7 @@ import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
import org.sleuthkit.autopsy.coordinationservice.CoordinationService.CoordinationServiceException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
import org.sleuthkit.autopsy.coreutils.StopWatch;
import org.sleuthkit.autopsy.events.AutopsyEventException;
import org.sleuthkit.autopsy.events.AutopsyEventPublisher;
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.
*/
CaseDeletionResult deleteCase(AutoIngestJob job) {
String caseName = job.getManifest().getCaseName();
Path caseDirectoryPath = job.getCaseDirectoryPath();
Path metadataFilePath = caseDirectoryPath.resolve(caseName + CaseMetadata.getFileExtension());
StopWatch stopWatch = new StopWatch();
stopWatch.start();
synchronized (jobsLock) {
String caseName = job.getManifest().getCaseName();
Path metadataFilePath = job.getCaseDirectoryPath().resolve(caseName + CaseMetadata.getFileExtension());
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 {
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);
} 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;
} 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;
}
// Update the state of completed jobs associated with this case to indicate
// 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())) {
try {
completedJob.setProcessingStatus(DELETED);
AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(completedJob);
coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, completedJob.getManifest().getFilePath().toString(), nodeData.toArray());
} 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;
}
}
}
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.
jobsSnapshot.completedJobs.removeIf((AutoIngestJob completedJob)
stopWatch.reset();
stopWatch.start();
completedJobs.removeIf((AutoIngestJob completedJob)
-> 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.
stopWatch.reset();
stopWatch.start();
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;

View File

@ -25,9 +25,7 @@ import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SimpleTimeZone;
import java.util.SortedSet;
import java.util.TimeZone;
import java.util.TreeSet;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
@ -43,6 +41,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.PathValidator;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
final class MemoryDSInputPanel extends JPanel implements DocumentListener {
@ -132,26 +131,13 @@ final class MemoryDSInputPanel extends JPanel implements DocumentListener {
* machine time zone to be selected.
*/
private void createTimeZoneList() {
// load and add all timezone
String[] ids = SimpleTimeZone.getAvailableIDs();
for (String id : ids) {
TimeZone zone = TimeZone.getTimeZone(id);
int offset = zone.getRawOffset() / 1000;
int hour = offset / 3600;
int minutes = (offset % 3600) / 60;
String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id);
timeZoneComboBox.addItem(item);
List<String> timeZoneList = TimeZoneUtils.createTimeZoneList();
for (String timeZone : timeZoneList) {
timeZoneComboBox.addItem(timeZone);
}
// get the current timezone
TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
int thisOffset = thisTimeZone.getRawOffset() / 1000;
int thisHour = thisOffset / 3600;
int thisMinutes = (thisOffset % 3600) / 60;
String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID());
// set the selected timezone
timeZoneComboBox.setSelectedItem(formatted);
timeZoneComboBox.setSelectedItem(TimeZoneUtils.createTimeZoneString(Calendar.getInstance().getTimeZone()));
}

View File

@ -1,6 +1,6 @@
Manifest-Version: 1.0
OpenIDE-Module: org.sleuthkit.autopsy.imagegallery/2
OpenIDE-Module-Implementation-Version: 4
OpenIDE-Module-Implementation-Version: 5
OpenIDE-Module-Layer: org/sleuthkit/autopsy/imagegallery/layer.xml
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/imagegallery/Bundle.properties

View File

@ -219,8 +219,13 @@ public enum FileTypeUtils {
* type. False if a non image/video mimetype. empty Optional if a
* mimetype could not be detected.
*/
static boolean hasDrawableMIMEType(AbstractFile file) throws FileTypeDetector.FileTypeDetectorInitException {
String mimeType = getFileTypeDetector().getMIMEType(file).toLowerCase();
static boolean hasDrawableMIMEType(AbstractFile file) {
String mimeType = file.getMIMEType();
if (mimeType == null) {
return false;
}
mimeType = mimeType.toLowerCase();
return isDrawableMimeType(mimeType) || (mimeType.equals("audio/x-aiff") && "tiff".equalsIgnoreCase(file.getNameExtension()));
}
@ -234,13 +239,13 @@ public enum FileTypeUtils {
* available, a video extension.
*/
public static boolean hasVideoMIMEType(AbstractFile file) {
try {
String mimeType = getFileTypeDetector().getMIMEType(file).toLowerCase();
return mimeType.startsWith("video/") || videoMimeTypes.contains(mimeType);
} catch (FileTypeDetector.FileTypeDetectorInitException ex) {
LOGGER.log(Level.SEVERE, "Error determining MIME type of " + getContentPathSafe(file), ex);
String mimeType = file.getMIMEType();
if (mimeType == null) {
return false;
}
mimeType = mimeType.toLowerCase();
return mimeType.startsWith("video/") || videoMimeTypes.contains(mimeType);
}
/**

View File

@ -67,7 +67,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.HashSetManager;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase;
@ -253,6 +252,7 @@ public final class ImageGalleryController {
/**
* Should the "forward" button on the history be enabled?
*
* @return
*/
public ReadOnlyBooleanProperty getCanAdvance() {
@ -261,6 +261,7 @@ public final class ImageGalleryController {
/**
* Should the "Back" button on the history be enabled?
*
* @return
*/
public ReadOnlyBooleanProperty getCanRetreat() {
@ -268,10 +269,9 @@ public final class ImageGalleryController {
}
/**
* Display the passed in group. Causes this group to
* get recorded in the history queue and observers of the
* current state will be notified and update their panels/widgets
* appropriately.
* Display the passed in group. Causes this group to get recorded in the
* history queue and observers of the current state will be notified and
* update their panels/widgets appropriately.
*
* @param newState
*/
@ -282,6 +282,7 @@ public final class ImageGalleryController {
/**
* Display the next group in the "forward" history stack
*
* @return
*/
public GroupViewState advance() {
@ -290,6 +291,7 @@ public final class ImageGalleryController {
/**
* Display the previous group in the "back" history stack
*
* @return
*/
public GroupViewState retreat() {
@ -433,10 +435,6 @@ public final class ImageGalleryController {
return drawableDB.getFileFromID(fileID);
}
public ReadOnlyDoubleProperty regroupProgress() {
return groupManager.regroupProgress();
}
public HashSetManager getHashSetManager() {
return hashSetManager;
}
@ -696,8 +694,17 @@ public final class ImageGalleryController {
// Cycle through all of the files returned and call processFile on each
//do in transaction
drawableDbTransaction = taskDB.beginTransaction();
caseDbTransaction = tskCase.beginTransaction();
/* We are going to periodically commit the CaseDB transaction
* and sleep so that the user can have Autopsy do other stuff
* while these bulk tasks are ongoing.
*/
int caseDbCounter = 0;
for (final AbstractFile f : files) {
if (caseDbTransaction == null) {
caseDbTransaction = tskCase.beginTransaction();
}
if (isCancelled() || Thread.interrupted()) {
logger.log(Level.WARNING, "Task cancelled or interrupted: not all contents may be transfered to drawable database."); //NON-NLS
taskCompletionStatus = false;
@ -712,6 +719,14 @@ public final class ImageGalleryController {
progressHandle.progress(f.getName(), workDone);
updateProgress(workDone - 1 / (double) files.size());
updateMessage(f.getName());
// Periodically, commit the transaction (which frees the lock) and sleep
// to allow other threads to get some work done in CaseDB
if ((++caseDbCounter % 200) == 0) {
caseDbTransaction.commit();
caseDbTransaction = null;
Thread.sleep(500); // 1/2 second
}
}
progressHandle.finish();
@ -720,13 +735,16 @@ public final class ImageGalleryController {
updateProgress(1.0);
progressHandle.start();
caseDbTransaction.commit();
caseDbTransaction = null;
if (caseDbTransaction != null) {
caseDbTransaction.commit();
caseDbTransaction = null;
}
// pass true so that groupmanager is notified of the changes
taskDB.commitTransaction(drawableDbTransaction, true);
drawableDbTransaction = null;
} catch (TskCoreException ex) {
} catch (TskCoreException | InterruptedException ex) {
progressHandle.progress(Bundle.BulkTask_stopCopy_status());
logger.log(Level.WARNING, "Stopping copy to drawable db task. Failed to transfer all database contents", ex); //NON-NLS
MessageNotifyUtil.Notify.warn(Bundle.BulkTask_errPopulating_errMsg(), ex.getMessage());
@ -792,20 +810,16 @@ public final class ImageGalleryController {
if (known) {
taskDB.removeFile(f.getId(), tr); //remove known files
} else {
try {
// if mimetype of the file hasn't been ascertained, ingest might not have completed yet.
if (null == f.getMIMEType()) {
// set to false to force the DB to be marked as stale
this.setTaskCompletionStatus(false);
} //supported mimetype => analyzed
else if (FileTypeUtils.hasDrawableMIMEType(f)) {
taskDB.updateFile(DrawableFile.create(f, true, false), tr, caseDbTransaction);
} //unsupported mimtype => analyzed but shouldn't include
else {
taskDB.removeFile(f.getId(), tr);
}
} catch (FileTypeDetector.FileTypeDetectorInitException ex) {
throw new TskCoreException("Failed to initialize FileTypeDetector.", ex);
// if mimetype of the file hasn't been ascertained, ingest might not have completed yet.
if (null == f.getMIMEType()) {
// set to false to force the DB to be marked as stale
this.setTaskCompletionStatus(false);
} //supported mimetype => analyzed
else if (FileTypeUtils.hasDrawableMIMEType(f)) {
taskDB.updateFile(DrawableFile.create(f, true, false), tr, caseDbTransaction);
} //unsupported mimtype => analyzed but shouldn't include
else {
taskDB.removeFile(f.getId(), tr);
}
}
}
@ -840,7 +854,7 @@ public final class ImageGalleryController {
@Override
void processFile(final AbstractFile f, DrawableDB.DrawableTransaction tr, CaseDbTransaction caseDBTransaction) {
taskDB.insertFile(DrawableFile.create(f, false, false), tr, caseDBTransaction);
taskDB.insertBasicFileData(DrawableFile.create(f, false, false), tr, caseDBTransaction);
}
@Override

View File

@ -208,7 +208,7 @@ public class ImageGalleryModule {
}
}
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()) {
DrawableDB drawableDB = controller.getDatabase();
@ -336,21 +336,23 @@ public class ImageGalleryModule {
try {
ImageGalleryController con = getController();
con.setStale(true);
if (con.isListeningEnabled() && ImageGalleryTopComponent.isImageGalleryOpen()) {
if (con.isListeningEnabled()) {
SwingUtilities.invokeLater(() -> {
int showAnswer = JOptionPane.showConfirmDialog(ImageGalleryTopComponent.getTopComponent(),
Bundle.ImageGalleryController_dataSourceAnalyzed_confDlg_msg(),
Bundle.ImageGalleryController_dataSourceAnalyzed_confDlg_title(),
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
if (ImageGalleryTopComponent.isImageGalleryOpen()) {
int showAnswer = JOptionPane.showConfirmDialog(ImageGalleryTopComponent.getTopComponent(),
Bundle.ImageGalleryController_dataSourceAnalyzed_confDlg_msg(),
Bundle.ImageGalleryController_dataSourceAnalyzed_confDlg_title(),
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
switch (showAnswer) {
case JOptionPane.YES_OPTION:
con.rebuildDB();
break;
case JOptionPane.NO_OPTION:
case JOptionPane.CANCEL_OPTION:
default:
break; //do nothing
switch (showAnswer) {
case JOptionPane.YES_OPTION:
con.rebuildDB();
break;
case JOptionPane.NO_OPTION:
case JOptionPane.CANCEL_OPTION:
default:
break; //do nothing
}
}
});
}

View File

@ -698,8 +698,8 @@ public final class DrawableDB {
// query to find the group id from attribute/value
return String.format(" SELECT group_id FROM " + GROUPS_TABLENAME
+ " WHERE attribute = \'%s\' AND value = \'%s\' AND data_source_obj_id = %d",
groupKey.getAttribute().attrName.toString(),
groupKey.getValueDisplayName(),
SleuthkitCase.escapeSingleQuotes(groupKey.getAttribute().attrName.toString()),
SleuthkitCase.escapeSingleQuotes(groupKey.getValueDisplayName()),
(groupKey.getAttribute() == DrawableAttribute.PATH) ? groupKey.getDataSourceObjId() : 0);
}
@ -776,8 +776,8 @@ public final class DrawableDB {
// query to find the group id from attribute/value
String innerQuery = String.format("( SELECT group_id FROM " + GROUPS_TABLENAME
+ " WHERE attribute = \'%s\' AND value = \'%s\' and data_source_obj_id = %d )",
groupKey.getAttribute().attrName.toString(),
groupKey.getValueDisplayName(),
SleuthkitCase.escapeSingleQuotes(groupKey.getAttribute().attrName.toString()),
SleuthkitCase.escapeSingleQuotes(groupKey.getValueDisplayName()),
groupKey.getAttribute() == DrawableAttribute.PATH ? groupKey.getDataSourceObjId() : 0);
String insertSQL = String.format(" (group_id, examiner_id, seen) VALUES (%s, %d, %d)", innerQuery, examinerID, seen ? 1 : 0);
@ -828,12 +828,26 @@ public final class DrawableDB {
}
public void insertFile(DrawableFile f, DrawableTransaction tr, CaseDbTransaction caseDbTransaction) {
insertOrUpdateFile(f, tr, insertFileStmt, caseDbTransaction);
/**
* Insert basic file data (no groups) into the DB during pre-population phase
* @param f
* @param tr
* @param caseDbTransaction
*/
public void insertBasicFileData(DrawableFile f, DrawableTransaction tr, CaseDbTransaction caseDbTransaction) {
insertOrUpdateFile(f, tr, caseDbTransaction, false);
}
/**
* Update an existing entry (or make a new one) into the DB that includes group information.
* Called when a file has been analyzed or during a bulk rebuild
*
* @param f
* @param tr
* @param caseDbTransaction
*/
public void updateFile(DrawableFile f, DrawableTransaction tr, CaseDbTransaction caseDbTransaction) {
insertOrUpdateFile(f, tr, updateFileStmt, caseDbTransaction);
insertOrUpdateFile(f, tr, caseDbTransaction, true);
}
@ -964,14 +978,24 @@ public final class DrawableDB {
*
* @param f The file to insert.
* @param tr a transaction to use, must not be null
* @param stmt the statement that does the actual inserting
* @param caseDbTransaction
* @param addGroups True if groups for file should be inserted into db too
*/
private void insertOrUpdateFile(DrawableFile f, @Nonnull DrawableTransaction tr, @Nonnull PreparedStatement stmt, @Nonnull CaseDbTransaction caseDbTransaction) {
private void insertOrUpdateFile(DrawableFile f, @Nonnull DrawableTransaction tr, @Nonnull CaseDbTransaction caseDbTransaction, boolean addGroups) {
PreparedStatement stmt;
if (tr.isClosed()) {
throw new IllegalArgumentException("can't update database with closed transaction");
}
// assume that we are doing an update if we are adding groups - i.e. not pre-populating
if (addGroups) {
stmt = updateFileStmt;
} else {
stmt = insertFileStmt;
}
// get data from caches. Default to true and force the DB lookup if we don't have caches
boolean hasExif = true;
boolean hasHashSet = true;
@ -984,6 +1008,13 @@ public final class DrawableDB {
}
}
// if we are going to just add basic data, then mark flags that we do not have metadata to prevent lookups
if (addGroups == false) {
hasExif = false;
hasHashSet = false;
hasTag = false;
}
dbWriteLock();
try {
// "INSERT OR IGNORE/ INTO drawable_files (obj_id, data_source_obj_id, path, name, created_time, modified_time, make, model, analyzed)"
@ -1006,51 +1037,55 @@ public final class DrawableDB {
// Update the list of file IDs in memory
addImageFileToList(f.getId());
// Update the hash set tables
if (hasHashSet) {
try {
for (String name : f.getHashSetNames()) {
// update the groups if we are not doing pre-populating
if (addGroups) {
// "insert or ignore into hash_sets (hash_set_name) values (?)"
insertHashSetStmt.setString(1, name);
insertHashSetStmt.executeUpdate();
// Update the hash set tables
if (hasHashSet) {
try {
for (String name : f.getHashSetNames()) {
//TODO: use nested select to get hash_set_id rather than seperate statement/query
//"select hash_set_id from hash_sets where hash_set_name = ?"
selectHashSetStmt.setString(1, name);
try (ResultSet rs = selectHashSetStmt.executeQuery()) {
while (rs.next()) {
int hashsetID = rs.getInt("hash_set_id"); //NON-NLS
//"insert or ignore into hash_set_hits (hash_set_id, obj_id) values (?,?)";
insertHashHitStmt.setInt(1, hashsetID);
insertHashHitStmt.setLong(2, f.getId());
insertHashHitStmt.executeUpdate();
break;
// "insert or ignore into hash_sets (hash_set_name) values (?)"
insertHashSetStmt.setString(1, name);
insertHashSetStmt.executeUpdate();
//TODO: use nested select to get hash_set_id rather than seperate statement/query
//"select hash_set_id from hash_sets where hash_set_name = ?"
selectHashSetStmt.setString(1, name);
try (ResultSet rs = selectHashSetStmt.executeQuery()) {
while (rs.next()) {
int hashsetID = rs.getInt("hash_set_id"); //NON-NLS
//"insert or ignore into hash_set_hits (hash_set_id, obj_id) values (?,?)";
insertHashHitStmt.setInt(1, hashsetID);
insertHashHitStmt.setLong(2, f.getId());
insertHashHitStmt.executeUpdate();
break;
}
}
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "failed to insert/update hash hits for file" + f.getContentPathSafe(), ex); //NON-NLS
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "failed to insert/update hash hits for file" + f.getContentPathSafe(), ex); //NON-NLS
}
}
//and update all groups this file is in
for (DrawableAttribute<?> attr : DrawableAttribute.getGroupableAttrs()) {
// skip attributes that we do not have data for
if ((attr == DrawableAttribute.TAGS) && (hasTag == false)) {
continue;
}
else if ((attr == DrawableAttribute.MAKE || attr == DrawableAttribute.MODEL) && (hasExif == false)) {
continue;
}
Collection<? extends Comparable<?>> vals = attr.getValue(f);
for (Comparable<?> val : vals) {
if (null != val) {
if (attr == DrawableAttribute.PATH) {
insertGroup(f.getAbstractFile().getDataSource().getId(), val.toString(), attr, caseDbTransaction);
}
else {
insertGroup(val.toString(), attr, caseDbTransaction);
//and update all groups this file is in
for (DrawableAttribute<?> attr : DrawableAttribute.getGroupableAttrs()) {
// skip attributes that we do not have data for
if ((attr == DrawableAttribute.TAGS) && (hasTag == false)) {
continue;
}
else if ((attr == DrawableAttribute.MAKE || attr == DrawableAttribute.MODEL) && (hasExif == false)) {
continue;
}
Collection<? extends Comparable<?>> vals = attr.getValue(f);
for (Comparable<?> val : vals) {
if ((null != val) && (val.toString().isEmpty() == false)) {
if (attr == DrawableAttribute.PATH) {
insertGroup(f.getAbstractFile().getDataSource().getId(), val.toString(), attr, caseDbTransaction);
}
else {
insertGroup(val.toString(), attr, caseDbTransaction);
}
}
}
}
@ -1408,7 +1443,7 @@ public final class DrawableDB {
try {
String insertSQL = String.format(" (data_source_obj_id, value, attribute) VALUES (%d, \'%s\', \'%s\')",
ds_obj_id, value, groupBy.attrName.toString());
ds_obj_id, SleuthkitCase.escapeSingleQuotes(value), SleuthkitCase.escapeSingleQuotes(groupBy.attrName.toString()));
if (DbType.POSTGRESQL == tskCase.getDatabaseType()) {
insertSQL += " ON CONFLICT DO NOTHING";

View File

@ -68,13 +68,6 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
DrawableGroup(GroupKey<?> groupKey, Set<Long> filesInGroup, boolean seen) {
this.groupKey = groupKey;
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);
}
@ -183,15 +176,21 @@ public class DrawableGroup implements Comparable<DrawableGroup> {
if (fileIDs.contains(f) == false) {
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) {
fileIDs.removeIf(fileID -> newFileIds.contains(fileID) == false);
invalidateProperties(false);
newFileIds.stream().forEach(this::addFile);
}
synchronized void removeFile(Long f) {
fileIDs.removeAll(f);
if (fileIDs.contains(f)) {
fileIDs.removeAll(f);
invalidateProperties(false);
}
}
private void invalidateProperties(boolean seenChanged) {

View File

@ -50,6 +50,7 @@ import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Service;
@ -266,14 +267,23 @@ public class GroupManager {
try {
Examiner examiner = controller.getSleuthKitCase().getCurrentExaminer();
getDrawableDB().markGroupSeen(group.getGroupKey(), seen, examiner.getId());
group.setSeen(seen);
updateUnSeenGroups(group);
// only update and reshuffle if its new results
if (group.isSeen() != seen) {
group.setSeen(seen);
updateUnSeenGroups(group);
}
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error marking group as seen", ex); //NON-NLS
}
});
}
/**
* Update unseenGroups list accordingly based on the current status of
* 'group'. Removes it if it is seen or adds it if it is unseen.
*
* @param group
*/
synchronized private void updateUnSeenGroups(DrawableGroup group) {
if (group.isSeen()) {
unSeenGroups.removeAll(group);
@ -496,6 +506,10 @@ public class GroupManager {
return regrouper.progressProperty();
}
public ReadOnlyStringProperty regroupMessage() {
return regrouper.messageProperty();
}
@Subscribe
synchronized public void handleTagAdded(ContentTagAddedEvent evt) {
GroupKey<?> newGroupKey = null;
@ -530,15 +544,18 @@ public class GroupManager {
// NOTE: We assume that it has already been determined that GroupKey can be displayed based on Data Source filters
if (group == null) {
//if there wasn't already a group check if there should be one now
// path group, for example, only gets created when all files are analyzed
//if there wasn't already a DrawableGroup, then check if this group is now
// in an appropriate state to get one made.
// Path group, for example, only gets a DrawableGroup created when all files are analyzed
group = popuplateIfAnalyzed(groupKey, null);
} else {
//if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it.
group.addFile(fileID);
}
// reset the seen status for the group
markGroupSeen(group, false);
if (group != null) {
markGroupSeen(group, false);
}
}
@Subscribe
@ -607,6 +624,8 @@ public class GroupManager {
* If the group is analyzed (or other criteria based on grouping) and should
* be shown to the user, then add it to the appropriate data structures so
* that it can be viewed.
*
* @returns null if Group is not ready to be viewed
*/
synchronized private DrawableGroup popuplateIfAnalyzed(GroupKey<?> groupKey, ReGroupTask<?> task) {
/*
@ -716,12 +735,7 @@ public class GroupManager {
*/
@SuppressWarnings({"unchecked", "rawtypes"})
@NbBundle.Messages({"# {0} - groupBy attribute Name",
"# {1} - sortBy name",
"# {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}"})
"ReGroupTask.displayTitle=regrouping by {0}: " })
class ReGroupTask<AttrValType extends Comparable<AttrValType>> extends LoggedTask<Void> {
private final DataSource dataSource;
@ -729,16 +743,14 @@ public class GroupManager {
private final GroupSortBy sortBy;
private final SortOrder sortOrder;
private final ProgressHandle groupProgress;
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.groupBy = groupBy;
this.sortBy = sortBy;
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
@ -747,7 +759,8 @@ public class GroupManager {
if (isCancelled()) {
return null;
}
groupProgress.start();
updateProgress(-1, 1);
analyzedGroups.clear();
unSeenGroups.clear();
@ -755,7 +768,7 @@ public class GroupManager {
// Get the list of group keys
Multimap<DataSource, AttrValType> valsByDataSource = findValuesForAttribute();
groupProgress.switchToDeterminate(valsByDataSource.entries().size());
updateProgress(0, valsByDataSource.entries().size());
int p = 0;
// For each key value, partially create the group and add it to the list.
for (final Map.Entry<DataSource, AttrValType> valForDataSource : valsByDataSource.entries()) {
@ -763,9 +776,8 @@ public class GroupManager {
return null;
}
p++;
updateMessage(Bundle.ReGroupTask_progressUpdate(groupBy.attrName.toString(), valForDataSource.getValue()));
updateMessage(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString()) + valForDataSource.getValue());
updateProgress(p, valsByDataSource.size());
groupProgress.progress(Bundle.ReGroupTask_progressUpdate(groupBy.attrName.toString(), valForDataSource), p);
popuplateIfAnalyzed(new GroupKey<>(groupBy, valForDataSource.getValue(), valForDataSource.getKey()), this);
}
@ -794,8 +806,8 @@ public class GroupManager {
}
}
} finally {
groupProgress.finish();
updateProgress(1, 1);
updateMessage("");
}
return null;
}
@ -813,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.
*
* @param groupBy
*
* @return map of data source (or null if group by attribute ignores
* data sources) to list of unique group values
*/

View File

@ -10,12 +10,21 @@
<?import javafx.scene.layout.HBox?>
<?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>
<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>
<HBox alignment="CENTER_RIGHT" prefHeight="-1.0" prefWidth="-1.0" spacing="5.0" BorderPane.alignment="CENTER_RIGHT">
<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">
<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" />
@ -31,37 +40,27 @@
<Insets />
</HBox.margin>
</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>
<BorderPane.margin>
<Insets left="10.0" />
</BorderPane.margin>
</HBox>
</right>
<left><Label fx:id="staleLabel" text="Some data may be out of date. Enable listening to ingest to update." BorderPane.alignment="CENTER">
<graphic><ImageView fitHeight="16.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="@../images/information.png" />
</image></ImageView>
</graphic>
<BorderPane.margin>
<Insets bottom="5.0" left="5.0" right="10.0" top="5.0" />
</BorderPane.margin></Label>
</left>
<left>
<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="-1.0" prefWidth="-1.0" BorderPane.alignment="CENTER">
<children>
<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" />
<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">
<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>
</StackPane>
</left>
</BorderPane>
</children>
</fx:root>

View File

@ -28,28 +28,26 @@ import javafx.scene.control.Tooltip;
import javafx.scene.layout.AnchorPane;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager;
/**
*
*/
public class StatusBar extends AnchorPane {
private final ImageGalleryController controller;
@FXML
private ProgressBar fileTaskProgresBar;
@FXML
private Label fileUpdateTaskLabel;
@FXML
private Label bgTaskLabel;
private Label regroupLabel;
@FXML
private Label staleLabel;
@FXML
private ProgressBar bgTaskProgressBar;
private ProgressBar regroupProgressBar;
private final ImageGalleryController controller;
private final GroupManager groupManager;
@FXML
@NbBundle.Messages({"StatusBar.fileUpdateTaskLabel.text= File Update Tasks",
@ -58,23 +56,25 @@ public class StatusBar extends AnchorPane {
void initialize() {
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 bgTaskLabel != null : "fx:id=\"bgTaskLabel\" 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 regroupLabel != null : "fx:id=\"regroupLabel\" 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()));
fileTaskProgresBar.progressProperty().bind(controller.getDBTasksQueueSizeProperty().negate());
controller.regroupProgress().addListener((ov, oldSize, newSize) -> {
groupManager.regroupProgress().addListener((ov, oldSize, newSize) -> {
Platform.runLater(() -> {
if (controller.regroupProgress().lessThan(1.0).get()) {
if (groupManager.regroupProgress().lessThan(1.0).get()) {
// Regrouping in progress
bgTaskProgressBar.progressProperty().setValue(-1.0);
bgTaskLabel.setText(Bundle.StatusBar_bgTaskLabel_text());
regroupProgressBar.progressProperty().setValue(groupManager.regroupProgress().doubleValue());
regroupLabel.setText(groupManager.regroupMessage().get());
} else {
// Clear the progress bar
bgTaskProgressBar.progressProperty().setValue(0.0);
bgTaskLabel.setText("");
regroupProgressBar.progressProperty().setValue(0.0);
regroupLabel.setText("");
}
regroupLabel.setTooltip(new Tooltip(regroupLabel.getText()));
});
});
@ -84,6 +84,7 @@ public class StatusBar extends AnchorPane {
public StatusBar(ImageGalleryController controller) {
this.controller = controller;
this.groupManager = controller.getGroupManager();
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("StatusBar.fxml")); //NON-NLS
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
@ -93,6 +94,5 @@ public class StatusBar extends AnchorPane {
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
}

View File

@ -1,3 +1,9 @@
---------------- VERSION 4.9.1 --------------
Bug Fixes:
- 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.
- Other misc Image Gallery fixes.
---------------- VERSION 4.9.0 --------------
New Features:

View File

@ -73,9 +73,7 @@
</run-dependency>
</dependency>
</module-dependencies>
<public-packages>
<package>org.sleuthkit.autopsy.recentactivity</package>
</public-packages>
<public-packages/>
<class-path-extension>
<runtime-relative-path>ext/gson-2.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/gson-2.1.jar</binary-origin>

View File

@ -37,6 +37,7 @@ import java.util.*;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.datamodel.AbstractFile;
@ -309,7 +310,7 @@ final class Chrome extends Extract {
} else {
date = Long.valueOf(0);
}
String domain = Util.extractDomain(url);
String domain = NetworkUtils.extractDomain(url);
try {
Collection<BlackboardAttribute> bbattributes = Arrays.asList(
new BlackboardAttribute(
@ -520,6 +521,7 @@ final class Chrome extends Extract {
try {
BlackboardArtifact bbart = downloadFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD);
bbart.addAttributes(bbattributes);
bbartifacts.add(bbart);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error while trying to insert Chrome download artifact.", ex); //NON-NLS
@ -589,6 +591,7 @@ final class Chrome extends Extract {
List<HashMap<String, Object>> tempList = this.dbConnect(temps, LOGIN_QUERY);
logger.log(Level.INFO, "{0}- Now getting login information from {1} with {2}artifacts identified.", new Object[]{getModuleName(), temps, tempList.size()}); //NON-NLS
for (HashMap<String, Object> result : tempList) {
Collection<BlackboardAttribute> bbattributes = Arrays.asList(
new BlackboardAttribute(
TSK_URL, PARENT_MODULE_NAME,
@ -618,6 +621,7 @@ final class Chrome extends Extract {
try {
BlackboardArtifact bbart = signonFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY);
bbart.addAttributes(bbattributes);
bbartifacts.add(bbart);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error while trying to insert Chrome login artifact.", ex); //NON-NLS

View File

@ -159,6 +159,7 @@ class ExtractIE extends Extract {
try {
BlackboardArtifact bbart = fav.newArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK);
bbart.addAttributes(bbattributes);
bbartifacts.add(bbart);
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error while trying to create Internet Explorer bookmark artifact.", ex); //NON-NLS
@ -596,6 +597,7 @@ class ExtractIE extends Extract {
}
/**
*
* Determine if the URL should be ignored.
*
* @param url The URL to test.

View File

@ -22,14 +22,12 @@
*/
package org.sleuthkit.autopsy.recentactivity;
import com.google.common.collect.Lists;
import static com.google.common.collect.Lists.newArrayList;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@ -492,7 +490,6 @@ final class FirefoxExtractor extends Extract {
errors++;
}
try {
BlackboardArtifact bbart = downloadsFile.newArtifact(TSK_WEB_DOWNLOAD);
bbart.addAttributes(bbattributes);
bbartifacts.add(bbart);
@ -642,10 +639,11 @@ final class FirefoxExtractor extends Extract {
}
/**
* Determine if the URL should be ignored.
*
* @param url The URL to test.
*
*s
* @return True if the URL should be ignored; otherwise false.
*/
private boolean isIgnoredUrl(String url) {

View File

@ -50,11 +50,11 @@ import org.sleuthkit.datamodel.TskCoreException;
/**
*
* @author Alex
*
*/
class Util {
private static Logger logger = Logger.getLogger(Util.class.getName());
private static final Logger logger = Logger.getLogger(Util.class.getName());
private Util() {
}
@ -83,8 +83,10 @@ class Util {
}
/**
//JIRA-2384: There is no utility in apache or guave to do this for us?
* //JIRA-2384: There is no utility in apache or guave to do this for us?
*
* @param url
*
* @return empty string if no domain could be found
*/
private static String getBaseDomain(String url) {
@ -111,7 +113,6 @@ class Util {
}
}
String base = hostB.toString();
// verify there are no special characters in there
if (base.matches(".*[~`!@#$%^&\\*\\(\\)\\+={}\\[\\];:\\?<>,/ ].*")) {
@ -123,6 +124,7 @@ class Util {
/**
*
* @param value
*
* @return empty string if no domain name was found
*/
public static String extractDomain(String value) {
@ -156,18 +158,8 @@ class Util {
}
public static String getFileName(String value) {
String filename = "";
String filematch = "^([a-zA-Z]\\:)(\\\\[^\\\\/:*?<>\"|]*(?<!\\[ \\]))*(\\.[a-zA-Z]{2,6})$"; //NON-NLS
Pattern p = Pattern.compile(filematch, Pattern.CASE_INSENSITIVE | Pattern.DOTALL | Pattern.COMMENTS);
Matcher m = p.matcher(value);
if (m.find()) {
filename = m.group(1);
}
int lastPos = value.lastIndexOf('\\');
filename = (lastPos < 0) ? value : value.substring(lastPos + 1);
return filename.toString();
return (lastPos < 0) ? value : value.substring(lastPos + 1);
}
public static String getPath(String txt) {

View File

@ -1,3 +1,3 @@
<project name="TSK_VERSION">
<property name="TSK_VERSION" value="4.6.3"/>
<property name="TSK_VERSION" value="4.6.4"/>
</project>

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy User Documentation"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 4.9.0
PROJECT_NUMBER = 4.9.1
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 4.9.0
PROJECT_NUMBER = 4.9.1
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears a the top of each page and should give viewer a

View File

@ -4,10 +4,10 @@ app.title=Autopsy
### lowercase version of above
app.name=${branding.token}
### if left unset, version will default to today's date
app.version=4.9.0
app.version=4.9.1
### build.type must be one of: DEVELOPMENT, RELEASE
#build.type=RELEASE
build.type=DEVELOPMENT
build.type=RELEASE
#build.type=DEVELOPMENT
project.org.netbeans.progress=org-netbeans-api-progress
project.org.sleuthkit.autopsy.experimental=Experimental

268
release/update_autopsy_version.pl Executable file
View File

@ -0,0 +1,268 @@
#!/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();

View File

@ -0,0 +1,199 @@
#!/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();