mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
Merge remote-tracking branch 'upstream/develop' into 6050-Update-Android-OruxMaps-to-use-TSK_GPS_TRACK
This commit is contained in:
commit
ab7335758f
@ -45,7 +45,6 @@ file.reference.jericho-html-3.3.jar=release/modules/ext/jericho-html-3.3.jar
|
||||
file.reference.jgraphx-v3.8.0.jar=release/modules/ext/jgraphx-v3.8.0.jar
|
||||
file.reference.jhighlight-1.0.3.jar=release\\modules\\ext\\jhighlight-1.0.3.jar
|
||||
file.reference.jmatio-1.5.jar=release\\modules\\ext\\jmatio-1.5.jar
|
||||
file.reference.jna-5.1.0.jar=release\\modules\\ext\\jna-5.1.0.jar
|
||||
file.reference.json-simple-1.1.1.jar=release\\modules\\ext\\json-simple-1.1.1.jar
|
||||
file.reference.jsoup-1.11.3.jar=release\\modules\\ext\\jsoup-1.11.3.jar
|
||||
file.reference.jul-to-slf4j-1.7.25.jar=release\\modules\\ext\\jul-to-slf4j-1.7.25.jar
|
||||
@ -97,7 +96,6 @@ file.reference.xz-1.8.jar=release\\modules\\ext\\xz-1.8.jar
|
||||
file.reference.zookeeper-3.4.6.jar=release/modules/ext/zookeeper-3.4.6.jar
|
||||
file.reference.SparseBitSet-1.1.jar=release/modules/ext/SparseBitSet-1.1.jar
|
||||
file.reference.commons-validator-1.6.jar=release/modules/ext/commons-validator-1.6.jar
|
||||
file.reference.jna-3.4.0.jar=release/modules/ext/jna-3.4.0.jar
|
||||
file.reference.api-common-1.7.0.jar=release/modules/ext/api-common-1.7.0.jar
|
||||
file.reference.gax-1.44.0.jar=release/modules/ext/gax-1.44.0.jar
|
||||
file.reference.gax-grpc-1.44.0.jar=release/modules/ext/gax-grpc-1.44.0.jar
|
||||
|
@ -615,10 +615,6 @@
|
||||
<runtime-relative-path>ext/commons-validator-1.6.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/commons-validator-1.6.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jna-5.1.0.jar</runtime-relative-path>
|
||||
<binary-origin>release\modules\ext\jna-5.1.0.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jbig2-imageio-3.0.2.jar</runtime-relative-path>
|
||||
<binary-origin>release\modules\ext\jbig2-imageio-3.0.2.jar</binary-origin>
|
||||
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2015-2020 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.datamodel;
|
||||
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
|
||||
/**
|
||||
* This represents a database choices available for central repo.
|
||||
*/
|
||||
@Messages({
|
||||
"CentralRepoDbChoice.Disabled.Text=Disabled",
|
||||
"CentralRepoDbChoice.Sqlite.Text=SQLite",
|
||||
"CentralRepoDbChoice.PostgreSQL_Multiuser.Text=PostgreSQL using multi-user settings",
|
||||
"CentralRepoDbChoice.PostgreSQL.Text=Custom PostgreSQL",
|
||||
})
|
||||
public enum CentralRepoDbChoice {
|
||||
DISABLED("Disabled", Bundle.CentralRepoDbChoice_Disabled_Text(), CentralRepoPlatforms.DISABLED),
|
||||
SQLITE("Sqlite", Bundle.CentralRepoDbChoice_Sqlite_Text(), CentralRepoPlatforms.SQLITE),
|
||||
POSTGRESQL_MULTIUSER("PostgreSQL_Multiuser", Bundle.CentralRepoDbChoice_PostgreSQL_Multiuser_Text(), CentralRepoPlatforms.POSTGRESQL),
|
||||
POSTGRESQL_CUSTOM("PostgreSQL", Bundle.CentralRepoDbChoice_PostgreSQL_Text(), CentralRepoPlatforms.POSTGRESQL);
|
||||
|
||||
public static final CentralRepoDbChoice[] DB_CHOICES = new CentralRepoDbChoice[]{
|
||||
SQLITE, POSTGRESQL_MULTIUSER, POSTGRESQL_CUSTOM
|
||||
};
|
||||
|
||||
|
||||
private final String settingKey;
|
||||
private final String title;
|
||||
private final CentralRepoPlatforms platform;
|
||||
|
||||
CentralRepoDbChoice(String key, String title, CentralRepoPlatforms platform) {
|
||||
this.settingKey = key;
|
||||
this.title = title;
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the value of this setting when saved to central repo properties.
|
||||
* @return The value associated with this choice.
|
||||
*/
|
||||
public String getSettingKey() {
|
||||
return settingKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the human-readable title for this choice.
|
||||
* @return The human-readable title for this choice.
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents the database type (i.e. Postgres, SQLite) associated with this choice.
|
||||
* @return The database type associated with this choice.
|
||||
*/
|
||||
public CentralRepoPlatforms getDbPlatform() {
|
||||
return platform;
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2015-2020 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.datamodel;
|
||||
|
||||
/**
|
||||
* This class is a common interface for settings pertaining to the database in central repository.
|
||||
*/
|
||||
public interface CentralRepoDbConnectivityManager {
|
||||
/**
|
||||
* This method loads the current settings for this connection.
|
||||
*/
|
||||
void loadSettings();
|
||||
|
||||
/**
|
||||
* This method saves the altered settings to disk.
|
||||
*/
|
||||
void saveSettings();
|
||||
|
||||
/**
|
||||
* This method will create a central repository database if necessary.
|
||||
* @return Whether or not the operation was successful.
|
||||
*/
|
||||
boolean createDatabase();
|
||||
|
||||
/**
|
||||
* This method deletes a central repository database (used for deleting a corrupted database).
|
||||
* @return Whether or not the operation was successful.
|
||||
*/
|
||||
boolean deleteDatabase();
|
||||
|
||||
/**
|
||||
* This method uses the current settings and the validation query to test the connection
|
||||
* to the database.
|
||||
*
|
||||
* @return True if successfull connection, else false.
|
||||
*/
|
||||
boolean verifyConnection();
|
||||
|
||||
/**
|
||||
* This method checks to see if the database exists.
|
||||
*
|
||||
* @return True if exists, else false.
|
||||
*/
|
||||
boolean verifyDatabaseExists();
|
||||
|
||||
/**
|
||||
* This method is uses the current settings and the schema version query to test the
|
||||
* database schema.
|
||||
*
|
||||
* @return True if successful connection, else false.
|
||||
*/
|
||||
boolean verifyDatabaseSchema();
|
||||
|
||||
/**
|
||||
* This method tests the connectivity status of this connection and returns the testing result.
|
||||
* @return The result of testing the database connectivity status.
|
||||
*/
|
||||
DatabaseTestResult testStatus();
|
||||
|
||||
}
|
@ -18,26 +18,172 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.centralrepository.datamodel;
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
import java.io.File;
|
||||
import java.sql.SQLException;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
|
||||
/**
|
||||
* Contains business logic for saving and validating settings for central repo
|
||||
* This class contains business logic for saving and validating settings for central repository.
|
||||
*/
|
||||
public class CentralRepoDbManager {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CentralRepoDbManager.class.getName());
|
||||
|
||||
private static final String CENTRAL_REPO_DB_NAME = "central_repository";
|
||||
private static final String CENTRAL_REPOSITORY_SETTINGS_KEY = "CentralRepository";
|
||||
private static final String DB_SELECTED_PLATFORM_KEY = "db.selectedPlatform";
|
||||
private static final String DISABLED_DUE_TO_FAILURE_KEY = "disabledDueToFailure";
|
||||
|
||||
private static volatile CentralRepoDbChoice savedChoice = null;
|
||||
|
||||
private static final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(CentralRepoDbManager.class);
|
||||
|
||||
private static final Object dbChoiceLock = new Object();
|
||||
private static final Object disabledDueToFailureLock = new Object();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* obtains the database connectivity for central repository
|
||||
* This saves the currently selected database choice and clears any disabledDueToFailure flag.
|
||||
* @param choice The choice to save.
|
||||
* @return The newly saved choice.
|
||||
*/
|
||||
public static CentralRepoDbChoice saveDbChoice(CentralRepoDbChoice choice) {
|
||||
return saveDbChoice(choice, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* This saves the currently selected database choice.
|
||||
* @param choice The choice to save.
|
||||
* @param clearDisabledDueToError Whether or not to clear the 'disabledDueToFailure' settings key.
|
||||
* @return The newly saved choice.
|
||||
*/
|
||||
public static CentralRepoDbChoice saveDbChoice(CentralRepoDbChoice choice, boolean clearDisabledDueToError) {
|
||||
synchronized(dbChoiceLock) {
|
||||
// clear disabling due to a failure
|
||||
if (clearDisabledDueToError)
|
||||
setDisabledDueToFailure(false);
|
||||
|
||||
// change the settings
|
||||
CentralRepoDbChoice newChoice = (choice == null) ? CentralRepoDbChoice.DISABLED : choice;
|
||||
CentralRepoDbChoice oldChoice = savedChoice;
|
||||
savedChoice = newChoice;
|
||||
ModuleSettings.setConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DB_SELECTED_PLATFORM_KEY, newChoice.getSettingKey());
|
||||
propertyChangeSupport.firePropertyChange("savedChoice", oldChoice, newChoice);
|
||||
return newChoice;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method indicates whether or not 'PostgreSQL using multi-user settings' is a valid option.
|
||||
* @return True if 'PostgreSQL using multi-user settings' is valid.
|
||||
*/
|
||||
public static boolean isPostgresMultiuserAllowed() {
|
||||
// if multi user mode is not enabled, then this cannot be used
|
||||
if (!UserPreferences.getIsMultiUserModeEnabled())
|
||||
return false;
|
||||
|
||||
// also validate the connection as well
|
||||
PostgresCentralRepoSettings multiUserSettings =
|
||||
new PostgresCentralRepoSettings(PostgresSettingsLoader.MULTIUSER_SETTINGS_LOADER);
|
||||
|
||||
return multiUserSettings.testStatus() == DatabaseTestResult.TESTED_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method loads the selectedPlatform boolean from the config file if it is set.
|
||||
*/
|
||||
public static CentralRepoDbChoice getSavedDbChoice() {
|
||||
synchronized(dbChoiceLock) {
|
||||
if (savedChoice == null) {
|
||||
String selectedPlatformString = ModuleSettings.getConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DB_SELECTED_PLATFORM_KEY); // NON-NLS
|
||||
savedChoice = fromKey(selectedPlatformString);
|
||||
}
|
||||
|
||||
return savedChoice;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method disables the central repository and indicates through a flag that this was due to a failure during database setup.
|
||||
* This is used when re-enabling multi-user as a flag to determine whether or not CR should be re-enabled.
|
||||
*/
|
||||
public static void disableDueToFailure() {
|
||||
CentralRepoDbUtil.setUseCentralRepo(false);
|
||||
setDisabledDueToFailure(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets whether or not the repository has been disabled due to a database setup issue;
|
||||
* This is used when re-enabling multi-user as a flag to determine whether or not CR should be re-enabled.
|
||||
*
|
||||
* @return the CentralRepository object to connect to
|
||||
* @param disabledDueToFailure Whether or not the repository has been disabled due to a database setup issue.
|
||||
*/
|
||||
private static void setDisabledDueToFailure(boolean disabledDueToFailure) {
|
||||
synchronized(disabledDueToFailureLock) {
|
||||
boolean oldValue = isDisabledDueToFailure();
|
||||
ModuleSettings.setConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DISABLED_DUE_TO_FAILURE_KEY, Boolean.toString(disabledDueToFailure));
|
||||
propertyChangeSupport.firePropertyChange("disabledDueToFailure", oldValue, disabledDueToFailure);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method retrieves setting whether or not the repository has been disabled due to a database setup issue;
|
||||
* this is used when re-enabling multi-user as a flag to determine whether or not CR should be re-enabled.
|
||||
*
|
||||
* @return Whether or not the repository has been disabled due to a database setup issue.
|
||||
*/
|
||||
public static boolean isDisabledDueToFailure() {
|
||||
synchronized(disabledDueToFailureLock) {
|
||||
return Boolean.toString(true).equals(ModuleSettings.getConfigSetting(CENTRAL_REPOSITORY_SETTINGS_KEY, DISABLED_DUE_TO_FAILURE_KEY));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds a property change listener.
|
||||
* NOTE: currently only listening for changes in currently saved db choice and disabling due to failure.
|
||||
*
|
||||
* @param listener The listener for the event.
|
||||
*/
|
||||
public static void addPropertyChangeListener(PropertyChangeListener listener) {
|
||||
propertyChangeSupport.addPropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method removes a propert change listener.
|
||||
* @param listener The listener to remove.
|
||||
*/
|
||||
public static void removePropertyChangeListener(PropertyChangeListener listener) {
|
||||
propertyChangeSupport.removePropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static CentralRepoDbChoice fromKey(String keyName) {
|
||||
for (CentralRepoDbChoice dbChoice : CentralRepoDbChoice.values()) {
|
||||
if (dbChoice.getSettingKey().equalsIgnoreCase(keyName)) {
|
||||
return dbChoice;
|
||||
}
|
||||
}
|
||||
|
||||
return CentralRepoDbChoice.DISABLED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This method obtains the database connectivity for central repository.
|
||||
*
|
||||
* @return The CentralRepository object that will be used for connection.
|
||||
* @throws CentralRepoException
|
||||
*/
|
||||
private static CentralRepository obtainCentralRepository() throws CentralRepoException {
|
||||
@ -55,10 +201,10 @@ public class CentralRepoDbManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* obtains central repository lock
|
||||
* This method obtains a central repository lock.
|
||||
*
|
||||
* @param db the database connection
|
||||
* @return the lock if acquired
|
||||
* @param db The database connection.
|
||||
* @return The lock if acquired.
|
||||
* @throws CentralRepoException
|
||||
*/
|
||||
private static CoordinationService.Lock obtainCentralRepoLock(CentralRepository db) throws CentralRepoException {
|
||||
@ -79,10 +225,10 @@ public class CentralRepoDbManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* updates central repository schema if necessary
|
||||
* This method updates the central repository schema if necessary.
|
||||
*
|
||||
* @param db the database connectivity
|
||||
* @param lock the acquired lock
|
||||
* @param db The database connectivity object.
|
||||
* @param lock The acquired lock.
|
||||
* @throws CentralRepoException
|
||||
*/
|
||||
private static void updatedDbSchema(CentralRepository db, CoordinationService.Lock lock) throws CentralRepoException {
|
||||
@ -111,7 +257,7 @@ public class CentralRepoDbManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade the current Central Reposity schema to the newest version. If the
|
||||
* This method upgrades the current Central Reposity schema to the newest version. If the
|
||||
* upgrade fails, the Central Repository will be disabled and the current
|
||||
* settings will be cleared.
|
||||
*/
|
||||
@ -142,8 +288,7 @@ public class CentralRepoDbManager {
|
||||
} catch (CentralRepoException ex2) {
|
||||
logger.log(Level.SEVERE, "Error shutting down central repo connection pool", ex2);
|
||||
}
|
||||
CentralRepoPlatforms.setSelectedPlatform(CentralRepoPlatforms.DISABLED.name());
|
||||
CentralRepoPlatforms.saveSelectedPlatform();
|
||||
saveDbChoice(CentralRepoDbChoice.DISABLED, false);
|
||||
if (innerException == null) {
|
||||
throw new CentralRepoException(message, desc);
|
||||
} else {
|
||||
@ -151,41 +296,56 @@ public class CentralRepoDbManager {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private DatabaseTestResult testingStatus;
|
||||
private CentralRepoPlatforms selectedPlatform;
|
||||
private CentralRepoDbChoice selectedDbChoice;
|
||||
|
||||
private final PostgresCentralRepoSettings dbSettingsPostgres;
|
||||
private final PostgresCentralRepoSettings dbSettingsMultiUser;
|
||||
private final SqliteCentralRepoSettings dbSettingsSqlite;
|
||||
|
||||
private boolean configurationChanged = false;
|
||||
|
||||
public CentralRepoDbManager() {
|
||||
dbSettingsPostgres = new PostgresCentralRepoSettings();
|
||||
selectedDbChoice = getSavedDbChoice();
|
||||
dbSettingsPostgres = new PostgresCentralRepoSettings(PostgresSettingsLoader.CUSTOM_SETTINGS_LOADER);
|
||||
dbSettingsMultiUser = new PostgresCentralRepoSettings(PostgresSettingsLoader.MULTIUSER_SETTINGS_LOADER);
|
||||
dbSettingsSqlite = new SqliteCentralRepoSettings();
|
||||
selectedPlatform = CentralRepoPlatforms.getSelectedPlatform();
|
||||
|
||||
// set the default selected platform for displaying in the ui of EamDbSettingsDialog
|
||||
// if selected option is not applicable
|
||||
if (selectedPlatform == null || selectedPlatform.equals(CentralRepoPlatforms.DISABLED)) {
|
||||
selectedPlatform = CentralRepoPlatforms.POSTGRESQL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method retrieves the current multi-user database settings.
|
||||
* @return The current multi-user database settings.
|
||||
*/
|
||||
public PostgresCentralRepoSettings getDbSettingsMultiUser() {
|
||||
return dbSettingsMultiUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method retrieves the current custom postgres database settings.
|
||||
* @return The current custom postgres database settings.
|
||||
*/
|
||||
public PostgresCentralRepoSettings getDbSettingsPostgres() {
|
||||
return dbSettingsPostgres;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the current SQLite database settings for central repository.
|
||||
* @return The current SQLite database settings
|
||||
*/
|
||||
public SqliteCentralRepoSettings getDbSettingsSqlite() {
|
||||
return dbSettingsSqlite;
|
||||
}
|
||||
|
||||
/**
|
||||
* setup sqlite db with default settings
|
||||
* @throws CentralRepoException if unable to successfully set up database
|
||||
* This method sets up the sqlite database with default settings.
|
||||
* @throws CentralRepoException if unable to successfully set up database.
|
||||
*/
|
||||
public void setupDefaultSqliteDb() throws CentralRepoException {
|
||||
// change in-memory settings to default sqlite
|
||||
selectedPlatform = CentralRepoPlatforms.SQLITE;
|
||||
selectedDbChoice = CentralRepoDbChoice.SQLITE;
|
||||
dbSettingsSqlite.setupDefaultSettings();
|
||||
|
||||
// if db is not present, attempt to create it
|
||||
@ -196,7 +356,7 @@ public class CentralRepoDbManager {
|
||||
}
|
||||
|
||||
// the only successful setup status is tested ok
|
||||
if (curStatus != DatabaseTestResult.TESTEDOK) {
|
||||
if (curStatus != DatabaseTestResult.TESTED_OK) {
|
||||
throw new CentralRepoException("Unable to successfully create sqlite database");
|
||||
}
|
||||
|
||||
@ -206,48 +366,55 @@ public class CentralRepoDbManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if changes to the central repository configuration were
|
||||
* successfully applied
|
||||
* This method returns if changes to the central repository configuration were
|
||||
* successfully applied.
|
||||
*
|
||||
* @return true if the database configuration was successfully changed false
|
||||
* if it was not
|
||||
* @return Returns true if the database configuration was successfully changed false
|
||||
* if it was not.
|
||||
*/
|
||||
public boolean wasConfigurationChanged() {
|
||||
return configurationChanged;
|
||||
}
|
||||
|
||||
private CentralRepoDbSettings getSelectedSettings() throws CentralRepoException {
|
||||
switch (selectedPlatform) {
|
||||
case POSTGRESQL:
|
||||
private CentralRepoDbConnectivityManager getSelectedSettings() throws CentralRepoException {
|
||||
if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_MULTIUSER)
|
||||
return dbSettingsMultiUser;
|
||||
if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM)
|
||||
return dbSettingsPostgres;
|
||||
case SQLITE:
|
||||
if (selectedDbChoice == CentralRepoDbChoice.SQLITE)
|
||||
return dbSettingsSqlite;
|
||||
case DISABLED:
|
||||
if (selectedDbChoice == CentralRepoDbChoice.DISABLED)
|
||||
return null;
|
||||
default:
|
||||
throw new CentralRepoException("Unknown database type: " + selectedPlatform);
|
||||
}
|
||||
|
||||
throw new CentralRepoException("Unknown database type: " + selectedDbChoice);
|
||||
}
|
||||
|
||||
private RdbmsCentralRepoFactory getDbFactory() throws CentralRepoException {
|
||||
switch (selectedPlatform) {
|
||||
case POSTGRESQL:
|
||||
return new RdbmsCentralRepoFactory(selectedPlatform, dbSettingsPostgres);
|
||||
case SQLITE:
|
||||
return new RdbmsCentralRepoFactory(selectedPlatform, dbSettingsSqlite);
|
||||
case DISABLED:
|
||||
if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_MULTIUSER)
|
||||
return new RdbmsCentralRepoFactory(CentralRepoPlatforms.POSTGRESQL, dbSettingsMultiUser);
|
||||
if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM)
|
||||
return new RdbmsCentralRepoFactory(CentralRepoPlatforms.POSTGRESQL, dbSettingsPostgres);
|
||||
if (selectedDbChoice == CentralRepoDbChoice.SQLITE)
|
||||
return new RdbmsCentralRepoFactory(CentralRepoPlatforms.SQLITE, dbSettingsSqlite);
|
||||
if (selectedDbChoice == CentralRepoDbChoice.DISABLED)
|
||||
return null;
|
||||
default:
|
||||
throw new CentralRepoException("Unknown database type: " + selectedPlatform);
|
||||
}
|
||||
|
||||
throw new CentralRepoException("Unknown database type: " + selectedDbChoice);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a central repo database if it does not already exist.
|
||||
* @return True if successful; false if unsuccessful.
|
||||
* @throws CentralRepoException
|
||||
*/
|
||||
public boolean createDb() throws CentralRepoException {
|
||||
CentralRepoDbConnectivityManager selectedDbSettings = getSelectedSettings();
|
||||
if (selectedDbSettings == null)
|
||||
throw new CentralRepoException("Unable to derive connectivity manager from settings: " + selectedDbChoice);
|
||||
|
||||
boolean result = false;
|
||||
boolean dbCreated = true;
|
||||
|
||||
CentralRepoDbSettings selectedDbSettings = getSelectedSettings();
|
||||
|
||||
if (!selectedDbSettings.verifyDatabaseExists()) {
|
||||
dbCreated = selectedDbSettings.createDatabase();
|
||||
}
|
||||
@ -265,7 +432,6 @@ public class CentralRepoDbManager {
|
||||
if (!result) {
|
||||
// Remove the incomplete database
|
||||
if (dbCreated) {
|
||||
// RAMAN TBD: migrate deleteDatabase() to RdbmsCentralRepoFactory
|
||||
selectedDbSettings.deleteDatabase();
|
||||
}
|
||||
|
||||
@ -274,12 +440,12 @@ public class CentralRepoDbManager {
|
||||
throw new CentralRepoException(schemaError);
|
||||
}
|
||||
|
||||
testingStatus = DatabaseTestResult.TESTEDOK;
|
||||
testingStatus = DatabaseTestResult.TESTED_OK;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* saves a new central repository based on current settings
|
||||
* This method saves a new central repository based on current settings.
|
||||
*/
|
||||
@NbBundle.Messages({"CentralRepoDbManager.connectionErrorMsg.text=Failed to connect to central repository database."})
|
||||
public void saveNewCentralRepo() throws CentralRepoException {
|
||||
@ -305,18 +471,18 @@ public class CentralRepoDbManager {
|
||||
// Even if we fail to close the existing connections, make sure that we
|
||||
// save the new connection settings, so an Autopsy restart will correctly
|
||||
// start with the new settings.
|
||||
CentralRepoPlatforms.setSelectedPlatform(selectedPlatform.name());
|
||||
CentralRepoPlatforms.saveSelectedPlatform();
|
||||
CentralRepoDbUtil.setUseCentralRepo(selectedDbChoice != CentralRepoDbChoice.DISABLED);
|
||||
saveDbChoice(selectedDbChoice);
|
||||
|
||||
CentralRepoDbSettings selectedDbSettings = getSelectedSettings();
|
||||
CentralRepoDbConnectivityManager selectedDbSettings = getSelectedSettings();
|
||||
|
||||
// save the new settings
|
||||
selectedDbSettings.saveSettings();
|
||||
// Load those newly saved settings into the postgres db manager instance
|
||||
// in case we are still using the same instance.
|
||||
if (selectedPlatform == CentralRepoPlatforms.POSTGRESQL || selectedPlatform == CentralRepoPlatforms.SQLITE) {
|
||||
if (selectedDbChoice != null && selectedDbChoice != CentralRepoDbChoice.DISABLED) {
|
||||
try {
|
||||
logger.info("Creating central repo db with settings: " + selectedDbSettings);
|
||||
logger.info("Saving central repo settings for db: " + selectedDbSettings);
|
||||
CentralRepository.getInstance().updateSettings();
|
||||
configurationChanged = true;
|
||||
} catch (CentralRepoException ex) {
|
||||
@ -326,80 +492,80 @@ public class CentralRepoDbManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method retrieves the current status.
|
||||
* Note: this could be a dirty value if testing of the connection has not been performed.
|
||||
* @return The current status of the database connection.
|
||||
*/
|
||||
public DatabaseTestResult getStatus() {
|
||||
return testingStatus;
|
||||
}
|
||||
|
||||
public CentralRepoPlatforms getSelectedPlatform() {
|
||||
return selectedPlatform;
|
||||
/**
|
||||
* This method retrieves the currently selected database choice.
|
||||
* NOTE: This choice may not align with the saved setting.
|
||||
* @return The currently selected database choice.
|
||||
*/
|
||||
public CentralRepoDbChoice getSelectedDbChoice() {
|
||||
return selectedDbChoice;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method clears the current database testing status.
|
||||
*/
|
||||
public void clearStatus() {
|
||||
testingStatus = DatabaseTestResult.UNTESTED;
|
||||
}
|
||||
|
||||
public void setSelectedPlatform(CentralRepoPlatforms newSelected) {
|
||||
selectedPlatform = newSelected;
|
||||
/**
|
||||
* This method sets the currently selected database choice and sets the testing status to untested.
|
||||
* @param newSelected The new database choice.
|
||||
*/
|
||||
public void setSelctedDbChoice(CentralRepoDbChoice newSelected) {
|
||||
selectedDbChoice = newSelected;
|
||||
testingStatus = DatabaseTestResult.UNTESTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not the database settings are valid.
|
||||
* This method tests whether or not the settings have been filled in for the UI.
|
||||
* NOTE: This does not check the connectivity status of these settings.
|
||||
*
|
||||
* @return True or false.
|
||||
* @return True if database settings are valid.
|
||||
*/
|
||||
public boolean testDatabaseSettingsAreValid(
|
||||
String tbDbHostname, String tbDbPort, String tbDbUsername, String tfDatabasePath, String jpDbPassword) throws CentralRepoException, NumberFormatException {
|
||||
|
||||
switch (selectedPlatform) {
|
||||
case POSTGRESQL:
|
||||
if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
|
||||
dbSettingsPostgres.setHost(tbDbHostname);
|
||||
dbSettingsPostgres.setPort(Integer.parseInt(tbDbPort));
|
||||
dbSettingsPostgres.setDbName(CENTRAL_REPO_DB_NAME);
|
||||
dbSettingsPostgres.setUserName(tbDbUsername);
|
||||
dbSettingsPostgres.setPassword(jpDbPassword);
|
||||
break;
|
||||
case SQLITE:
|
||||
}
|
||||
else if (selectedDbChoice == CentralRepoDbChoice.SQLITE) {
|
||||
File databasePath = new File(tfDatabasePath);
|
||||
dbSettingsSqlite.setDbName(SqliteCentralRepoSettings.DEFAULT_DBNAME);
|
||||
dbSettingsSqlite.setDbDirectory(databasePath.getPath());
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Central Repo has an unknown selected platform: " + selectedPlatform);
|
||||
}
|
||||
else if (selectedDbChoice != CentralRepoDbChoice.POSTGRESQL_MULTIUSER) {
|
||||
throw new IllegalStateException("Central Repo has an unknown selected platform: " + selectedDbChoice);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tests the current database settings to see if a valid connection can be made.
|
||||
* @return The result of testing the connection.
|
||||
*/
|
||||
public DatabaseTestResult testStatus() {
|
||||
if (selectedPlatform == CentralRepoPlatforms.POSTGRESQL) {
|
||||
if (dbSettingsPostgres.verifyConnection()) {
|
||||
if (dbSettingsPostgres.verifyDatabaseExists()) {
|
||||
if (dbSettingsPostgres.verifyDatabaseSchema()) {
|
||||
testingStatus = DatabaseTestResult.TESTEDOK;
|
||||
} else {
|
||||
testingStatus = DatabaseTestResult.SCHEMA_INVALID;
|
||||
}
|
||||
} else {
|
||||
testingStatus = DatabaseTestResult.DB_DOES_NOT_EXIST;
|
||||
}
|
||||
} else {
|
||||
testingStatus = DatabaseTestResult.CONNECTION_FAILED;
|
||||
}
|
||||
} else if (selectedPlatform == CentralRepoPlatforms.SQLITE) {
|
||||
if (dbSettingsSqlite.dbFileExists()) {
|
||||
if (dbSettingsSqlite.verifyConnection()) {
|
||||
if (dbSettingsSqlite.verifyDatabaseSchema()) {
|
||||
testingStatus = DatabaseTestResult.TESTEDOK;
|
||||
} else {
|
||||
testingStatus = DatabaseTestResult.SCHEMA_INVALID;
|
||||
}
|
||||
} else {
|
||||
testingStatus = DatabaseTestResult.SCHEMA_INVALID;
|
||||
}
|
||||
} else {
|
||||
testingStatus = DatabaseTestResult.DB_DOES_NOT_EXIST;
|
||||
try {
|
||||
CentralRepoDbConnectivityManager manager = getSelectedSettings();
|
||||
if (manager != null)
|
||||
testingStatus = manager.testStatus();
|
||||
}
|
||||
catch (CentralRepoException e) {
|
||||
logger.log(Level.WARNING, "unable to test status of db connection in central repo", e);
|
||||
}
|
||||
|
||||
return testingStatus;
|
||||
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2015-2020 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.datamodel;
|
||||
|
||||
/**
|
||||
* common interface for settings pertaining to the database in central repository
|
||||
*/
|
||||
public interface CentralRepoDbSettings {
|
||||
|
||||
void saveSettings();
|
||||
|
||||
boolean createDatabase();
|
||||
|
||||
boolean deleteDatabase();
|
||||
|
||||
/**
|
||||
* Use the current settings and the validation query to test the connection
|
||||
* to the database.
|
||||
*
|
||||
* @return true if successfull connection, else false.
|
||||
*/
|
||||
boolean verifyConnection();
|
||||
|
||||
/**
|
||||
* Check to see if the database exists.
|
||||
*
|
||||
* @return true if exists, else false
|
||||
*/
|
||||
boolean verifyDatabaseExists();
|
||||
|
||||
/**
|
||||
* Use the current settings and the schema version query to test the
|
||||
* database schema.
|
||||
*
|
||||
* @return true if successful connection, else false.
|
||||
*/
|
||||
boolean verifyDatabaseSchema();
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2020 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.datamodel;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber;
|
||||
|
||||
/**
|
||||
* Common interface to upgrade central repository database schema.
|
||||
*/
|
||||
public interface CentralRepoDbUpgrader {
|
||||
|
||||
/**
|
||||
* Updates the Central Repository schema using the given open connection.
|
||||
*
|
||||
* @param dbSchemaVersion Current schema version.
|
||||
* @param connection Connection to use for upgrade.
|
||||
*
|
||||
* @throws CentralRepoException If there is an error in upgrade.
|
||||
* @throws SQLException If there is any SQL errors.
|
||||
*/
|
||||
void upgradeSchema(CaseDbSchemaVersionNumber dbSchemaVersion, Connection connection) throws CentralRepoException, SQLException;
|
||||
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2020 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.datamodel;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber;
|
||||
|
||||
|
||||
/**
|
||||
* This class updates CR schema to 1.4
|
||||
*
|
||||
* New correlation types for accounts are added, as well as some accounts related new tables are added in this version.
|
||||
*
|
||||
*/
|
||||
public class CentralRepoDbUpgrader13To14 implements CentralRepoDbUpgrader {
|
||||
|
||||
@Override
|
||||
public void upgradeSchema(CaseDbSchemaVersionNumber dbSchemaVersion, Connection connection) throws CentralRepoException, SQLException {
|
||||
|
||||
if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 4)) < 0) {
|
||||
|
||||
try (Statement statement = connection.createStatement();) {
|
||||
|
||||
CentralRepoPlatforms selectedPlatform = CentralRepoDbManager.getSavedDbChoice().getDbPlatform();
|
||||
|
||||
// Create account_types and accounts tables which are referred by X_instances tables
|
||||
statement.execute(RdbmsCentralRepoFactory.getCreateAccountTypesTableStatement(selectedPlatform));
|
||||
statement.execute(RdbmsCentralRepoFactory.getCreateAccountsTableStatement(selectedPlatform));
|
||||
|
||||
for (CorrelationAttributeInstance.Type type : CorrelationAttributeInstance.getDefaultCorrelationTypes()) {
|
||||
String instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
|
||||
|
||||
if (type.getId() >= CorrelationAttributeInstance.ADDITIONAL_TYPES_BASE_ID) {
|
||||
|
||||
// these are new Correlation types - new tables need to be created
|
||||
statement.execute(String.format(RdbmsCentralRepoFactory.getCreateAccountInstancesTableTemplate(selectedPlatform), instance_type_dbname, instance_type_dbname));
|
||||
statement.execute(String.format(RdbmsCentralRepoFactory.getAddCaseIdIndexTemplate(), instance_type_dbname, instance_type_dbname));
|
||||
statement.execute(String.format(RdbmsCentralRepoFactory.getAddDataSourceIdIndexTemplate(), instance_type_dbname, instance_type_dbname));
|
||||
statement.execute(String.format(RdbmsCentralRepoFactory.getAddValueIndexTemplate(), instance_type_dbname, instance_type_dbname));
|
||||
statement.execute(String.format(RdbmsCentralRepoFactory.getAddKnownStatusIndexTemplate(), instance_type_dbname, instance_type_dbname));
|
||||
statement.execute(String.format(RdbmsCentralRepoFactory.getAddObjectIdIndexTemplate(), instance_type_dbname, instance_type_dbname));
|
||||
|
||||
// add new correlation type
|
||||
CentralRepoDbUtil.insertCorrelationType(connection, type);
|
||||
|
||||
} else if (type.getId() == CorrelationAttributeInstance.EMAIL_TYPE_ID || type.getId() == CorrelationAttributeInstance.PHONE_TYPE_ID) {
|
||||
// Alter the existing _instance tables for Phone and Email attributes to add account_id column
|
||||
String sqlStr = String.format(getAlterArtifactInstancesAddAccountIdTemplate(selectedPlatform), instance_type_dbname);
|
||||
statement.execute(sqlStr);
|
||||
|
||||
// SQLite does NOT allow adding a constraint with Alter Table statement.
|
||||
// The alternative would be to create new tables, copy all data over, and delete old tables - potentially a time consuming process.
|
||||
// We decided to not add this constraint for SQLite, since there likely aren't many users using SQLite based Central Repo.
|
||||
if (selectedPlatform == CentralRepoPlatforms.POSTGRESQL) {
|
||||
sqlStr = String.format(getAlterArtifactInstancesAddAccountIdConstraintTemplate(), instance_type_dbname);
|
||||
statement.execute(sqlStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// insert default accounts data
|
||||
RdbmsCentralRepoFactory.insertDefaultAccountsTablesContent(connection, selectedPlatform);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ALTER TABLE SQL string template to add an account_id column to a
|
||||
* TYPE_instances table.
|
||||
*
|
||||
* @param selectedPlatform
|
||||
*
|
||||
* @return SQL string template to alter the table.
|
||||
*/
|
||||
static String getAlterArtifactInstancesAddAccountIdTemplate(CentralRepoPlatforms selectedPlatform) {
|
||||
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
||||
return "ALTER TABLE %s"
|
||||
+ " ADD account_id " + RdbmsCentralRepoFactory.getBigIntType(selectedPlatform) + " DEFAULT NULL";
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns ALTER TABLE SQL string template to add a Foreign Key constraint
|
||||
* to a TYPE_instances table.
|
||||
*
|
||||
* @return SQL string template to alter the table.
|
||||
*/
|
||||
static String getAlterArtifactInstancesAddAccountIdConstraintTemplate() {
|
||||
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
||||
return "ALTER TABLE %s"
|
||||
+ " ADD CONSTRAINT account_id_fk foreign key (account_id) references accounts(id)";
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -123,6 +123,28 @@ public class CentralRepoDbUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the specified correlation type into the database.
|
||||
*
|
||||
* @param conn Open connection to use.
|
||||
* @param correlationType New correlation type to add.
|
||||
*
|
||||
*/
|
||||
public static void insertCorrelationType(Connection conn, CorrelationAttributeInstance.Type correlationType) throws SQLException {
|
||||
|
||||
String sql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?)";
|
||||
try (PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
|
||||
|
||||
preparedStatement.setInt(1, correlationType.getId());
|
||||
preparedStatement.setString(2, correlationType.getDisplayName());
|
||||
preparedStatement.setString(3, correlationType.getDbTableName());
|
||||
preparedStatement.setInt(4, correlationType.isSupported() ? 1 : 0);
|
||||
preparedStatement.setInt(5, correlationType.isEnabled() ? 1 : 0);
|
||||
|
||||
preparedStatement.execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the current schema version into the database.
|
||||
*
|
||||
@ -303,4 +325,17 @@ public class CentralRepoDbUtil {
|
||||
closeStatement(preparedStatement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given correlation attribute type has an account behind it.
|
||||
*
|
||||
* @param type Correlation type to check.
|
||||
*
|
||||
* @return True If the specified correlation type has an account.
|
||||
*/
|
||||
static boolean correlationAttribHasAnAccount(CorrelationAttributeInstance.Type type) {
|
||||
return (type.getId() >= CorrelationAttributeInstance.ADDITIONAL_TYPES_BASE_ID)
|
||||
|| type.getId() == CorrelationAttributeInstance.PHONE_TYPE_ID
|
||||
|| type.getId() == CorrelationAttributeInstance.EMAIL_TYPE_ID;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,102 +18,11 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.centralrepository.datamodel;
|
||||
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
|
||||
/**
|
||||
*
|
||||
* This enum describes the possible database types for central repo.
|
||||
*/
|
||||
public enum CentralRepoPlatforms {
|
||||
DISABLED("Disabled", true),
|
||||
SQLITE("SQLite", false),
|
||||
POSTGRESQL("PostgreSQL", false);
|
||||
|
||||
private final String platformName;
|
||||
private Boolean selected;
|
||||
|
||||
CentralRepoPlatforms(String name, Boolean selected) {
|
||||
this.platformName = name;
|
||||
this.selected = selected;
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the selectedPlatform boolean from the config file, if it is set.
|
||||
*/
|
||||
private void loadSettings() {
|
||||
String selectedPlatformString = ModuleSettings.getConfigSetting("CentralRepository", "db.selectedPlatform"); // NON-NLS
|
||||
|
||||
if (null != selectedPlatformString) {
|
||||
selected = this.toString().equalsIgnoreCase(selectedPlatformString);
|
||||
} else if (this == DISABLED) {
|
||||
selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return platformName;
|
||||
}
|
||||
|
||||
private void setSelected(Boolean selected) {
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
public Boolean isSelected() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
public static CentralRepoPlatforms fromString(String pName) {
|
||||
if (null == pName) {
|
||||
return DISABLED;
|
||||
}
|
||||
|
||||
for (CentralRepoPlatforms p : CentralRepoPlatforms.values()) {
|
||||
if (p.toString().equalsIgnoreCase(pName)) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return DISABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the selected platform to the config file.
|
||||
*/
|
||||
public static void saveSelectedPlatform() {
|
||||
CentralRepoPlatforms selectedPlatform = DISABLED;
|
||||
for (CentralRepoPlatforms p : CentralRepoPlatforms.values()) {
|
||||
if (p.isSelected()) {
|
||||
selectedPlatform = p;
|
||||
}
|
||||
}
|
||||
ModuleSettings.setConfigSetting("CentralRepository", "db.selectedPlatform", selectedPlatform.name()); // NON-NLS
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selected db platform. Other platforms will be set as not
|
||||
* selected.
|
||||
*
|
||||
* @param platformString The name of the selected platform.
|
||||
*/
|
||||
public static void setSelectedPlatform(String platformString) {
|
||||
CentralRepoPlatforms pSelected = CentralRepoPlatforms.fromString(platformString);
|
||||
for (CentralRepoPlatforms p : CentralRepoPlatforms.values()) {
|
||||
p.setSelected(p == pSelected);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the selected platform.
|
||||
*
|
||||
* @return The selected platform, or if not platform is selected, default to
|
||||
* DISABLED.
|
||||
*/
|
||||
public static CentralRepoPlatforms getSelectedPlatform() {
|
||||
for (CentralRepoPlatforms p : CentralRepoPlatforms.values()) {
|
||||
if (p.isSelected()) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return DISABLED;
|
||||
}
|
||||
DISABLED,
|
||||
SQLITE,
|
||||
POSTGRESQL
|
||||
}
|
||||
|
@ -0,0 +1,185 @@
|
||||
/*
|
||||
*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2012-2020 Basis Technology Corp.
|
||||
*
|
||||
* Copyright 2012 42six Solutions.
|
||||
* Contact: aebadirad <at> 42six <dot> com
|
||||
* Project Contact/Architect: 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.datamodel;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.core.UserPreferencesException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
import org.sleuthkit.autopsy.coreutils.TextConverter;
|
||||
import org.sleuthkit.autopsy.coreutils.TextConverterException;
|
||||
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
|
||||
|
||||
/**
|
||||
* This class handles saving and loading of postgres settings for central repository.
|
||||
*/
|
||||
public class CentralRepoPostgresSettingsUtil {
|
||||
private final static Logger LOGGER = Logger.getLogger(CentralRepoPostgresSettingsUtil.class.getName());
|
||||
|
||||
private static final String PASSWORD_KEY = "db.postgresql.password";
|
||||
private static final String BULK_THRESHOLD_KEY = "db.postgresql.bulkThreshold";
|
||||
private static final String PORT_KEY = "db.postgresql.port";
|
||||
private static final String USER_KEY = "db.postgresql.user";
|
||||
private static final String DBNAME_KEY = "db.postgresql.dbName";
|
||||
private static final String HOST_KEY = "db.postgresql.host";
|
||||
|
||||
private static final String MODULE_KEY = "CentralRepository";
|
||||
|
||||
private static CentralRepoPostgresSettingsUtil instance = null;
|
||||
|
||||
/**
|
||||
* This method retrieves a singleton instance of this class.
|
||||
* @return The singleton instance of this class.
|
||||
*/
|
||||
public static synchronized CentralRepoPostgresSettingsUtil getInstance() {
|
||||
if (instance == null)
|
||||
instance = new CentralRepoPostgresSettingsUtil();
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
private CentralRepoPostgresSettingsUtil() {}
|
||||
|
||||
/**
|
||||
* Uses setter object to set a value as specified by 'value'. In the event that 'value'
|
||||
* is null, the setter will not be called. Exceptions that are raised from the setter will
|
||||
* be logged.
|
||||
*
|
||||
* @param setter The setter to call.
|
||||
* @param value The value to use with the setter.
|
||||
*/
|
||||
private void setValOrLog(ValueSetter setter, String value) {
|
||||
// ignore null values as they indicate a setting that is not set yet
|
||||
if (value == null || value.isEmpty())
|
||||
return;
|
||||
|
||||
try {
|
||||
setter.set(value);
|
||||
}
|
||||
catch (CentralRepoException | NumberFormatException e) {
|
||||
LOGGER.log(Level.WARNING, "There was an error in converting central repo postgres settings", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This interface represents a setter that potentially throws an exception.
|
||||
*/
|
||||
private interface ValueSetter {
|
||||
void set(String value) throws CentralRepoException, NumberFormatException;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method loads multi-user settings to be used as a postgres connection to central repository. If
|
||||
* settings could not be loaded, default values will be returned.
|
||||
*
|
||||
* @return The settings loaded from multi-user settings.
|
||||
*/
|
||||
public PostgresConnectionSettings loadMultiUserSettings() {
|
||||
PostgresConnectionSettings settings = new PostgresConnectionSettings();
|
||||
|
||||
CaseDbConnectionInfo muConn;
|
||||
try {
|
||||
muConn = UserPreferences.getDatabaseConnectionInfo();
|
||||
} catch (UserPreferencesException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to import settings from multi-user settings.", ex);
|
||||
return settings;
|
||||
}
|
||||
|
||||
setValOrLog((v) -> settings.setHost(v), muConn.getHost());
|
||||
setValOrLog((v) -> settings.setUserName(v), muConn.getUserName());
|
||||
setValOrLog((v) -> settings.setPassword(v), muConn.getPassword());
|
||||
|
||||
setValOrLog((v) -> settings.setPort(Integer.parseInt(v)), muConn.getPort());
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method loads the custom postgres settings for central repository. If
|
||||
* settings could not be loaded, default values will be returned.
|
||||
*
|
||||
* @return The settings loaded from custom postgres settings.
|
||||
*/
|
||||
public PostgresConnectionSettings loadCustomSettings() {
|
||||
PostgresConnectionSettings settings = new PostgresConnectionSettings();
|
||||
Map<String, String> keyVals = ModuleSettings.getConfigSettings(MODULE_KEY);
|
||||
|
||||
|
||||
setValOrLog((v) -> settings.setHost(v), keyVals.get(HOST_KEY));
|
||||
setValOrLog((v) -> settings.setDbName(v), keyVals.get(DBNAME_KEY));
|
||||
setValOrLog((v) -> settings.setUserName(v), keyVals.get(USER_KEY));
|
||||
|
||||
setValOrLog((v) -> settings.setPort(Integer.parseInt(v)), keyVals.get(PORT_KEY));
|
||||
setValOrLog((v) -> settings.setBulkThreshold(Integer.parseInt(v)), keyVals.get((BULK_THRESHOLD_KEY)));
|
||||
|
||||
String passwordHex = keyVals.get(PASSWORD_KEY);
|
||||
if (passwordHex != null) {
|
||||
String password;
|
||||
try {
|
||||
password = TextConverter.convertHexTextToText(passwordHex);
|
||||
} catch (TextConverterException ex) {
|
||||
LOGGER.log(Level.WARNING, "Failed to convert password from hex text to text.", ex);
|
||||
password = null;
|
||||
}
|
||||
|
||||
final String finalPassword = password;
|
||||
setValOrLog((v) -> settings.setPassword(v), finalPassword);
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method saves the settings for a custom postgres central repository connection.
|
||||
* @param settings The settings to save.
|
||||
*/
|
||||
public void saveCustomSettings(PostgresConnectionSettings settings) {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
map.put(HOST_KEY, settings.getHost());
|
||||
map.put(PORT_KEY, Integer.toString(settings.getPort()));
|
||||
map.put(DBNAME_KEY, settings.getDbName());
|
||||
map.put(BULK_THRESHOLD_KEY, Integer.toString(settings.getBulkThreshold()));
|
||||
map.put(USER_KEY, settings.getUserName());
|
||||
try {
|
||||
map.put(PASSWORD_KEY, TextConverter.convertTextToHexText(settings.getPassword())); // NON-NLS
|
||||
} catch (TextConverterException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to convert password from text to hex text.", ex);
|
||||
}
|
||||
|
||||
ModuleSettings.setConfigSettings(MODULE_KEY, map);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks if saved settings differ from the in-memory object provided in the 'settings' parameter.
|
||||
* @param settings The in-memory object.
|
||||
* @return Whether or not settings parameter differs from saved custom settings.
|
||||
*/
|
||||
public boolean areCustomSettingsChanged(PostgresConnectionSettings settings) {
|
||||
PostgresConnectionSettings saved = loadCustomSettings();
|
||||
return saved.equals(settings);
|
||||
}
|
||||
}
|
@ -42,7 +42,7 @@ public interface CentralRepository {
|
||||
|
||||
CentralRepoPlatforms selectedPlatform = CentralRepoPlatforms.DISABLED;
|
||||
if (CentralRepoDbUtil.allowUseOfCentralRepository()) {
|
||||
selectedPlatform = CentralRepoPlatforms.getSelectedPlatform();
|
||||
selectedPlatform = CentralRepoDbManager.getSavedDbChoice().getDbPlatform();
|
||||
}
|
||||
switch (selectedPlatform) {
|
||||
case POSTGRESQL:
|
||||
@ -93,7 +93,7 @@ public interface CentralRepository {
|
||||
*/
|
||||
static boolean isEnabled() {
|
||||
return CentralRepoDbUtil.allowUseOfCentralRepository()
|
||||
&& CentralRepoPlatforms.getSelectedPlatform() != CentralRepoPlatforms.DISABLED;
|
||||
&& CentralRepoDbManager.getSavedDbChoice() != CentralRepoDbChoice.DISABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -294,8 +294,9 @@ public class CorrelationAttributeInstance implements Serializable {
|
||||
// Create Correlation Types for Accounts.
|
||||
int correlationTypeId = ADDITIONAL_TYPES_BASE_ID;
|
||||
for (Account.Type type : Account.Type.PREDEFINED_ACCOUNT_TYPES) {
|
||||
// Skip Device account type - we dont want to correlate on those.
|
||||
// Skip Phone and Email accounts as there are already Correlation types defined for those.
|
||||
if (type != Account.Type.EMAIL && type != Account.Type.PHONE) {
|
||||
if (type != Account.Type.DEVICE && type != Account.Type.EMAIL && type != Account.Type.PHONE) {
|
||||
defaultCorrelationTypes.add(new CorrelationAttributeInstance.Type(correlationTypeId, type.getDisplayName(), type.getTypeName().toLowerCase() + "_acct", true, true)); //NON-NLS
|
||||
correlationTypeId++;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.CentralRepoAccountType;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
@ -84,23 +85,12 @@ public class CorrelationAttributeUtil {
|
||||
BlackboardArtifact sourceArtifact = getCorrAttrSourceArtifact(artifact);
|
||||
if (sourceArtifact != null) {
|
||||
int artifactTypeID = sourceArtifact.getArtifactTypeID();
|
||||
if (artifactTypeID == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
|
||||
BlackboardAttribute setNameAttr = sourceArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
|
||||
if (setNameAttr != null && CorrelationAttributeUtil.getEmailAddressAttrDisplayName().equals(setNameAttr.getValueString())) {
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, CorrelationAttributeInstance.EMAIL_TYPE_ID);
|
||||
}
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID()
|
||||
if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_WEB_COOKIE.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID()) {
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DOMAIN, CorrelationAttributeInstance.DOMAIN_TYPE_ID);
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_CONTACT.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_CALLLOG.getTypeID()
|
||||
|| artifactTypeID == ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) {
|
||||
makeCorrAttrFromArtifactPhoneAttr(sourceArtifact);
|
||||
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID()) {
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID, CorrelationAttributeInstance.USBID_TYPE_ID);
|
||||
makeCorrAttrFromArtifactAttr(correlationAttrs, sourceArtifact, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MAC_ADDRESS, CorrelationAttributeInstance.MAC_TYPE_ID);
|
||||
@ -169,58 +159,6 @@ public class CorrelationAttributeUtil {
|
||||
return sourceArtifact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a correlation attribute instance from a phone number attribute of an
|
||||
* artifact.
|
||||
*
|
||||
* @param artifact An artifact with a phone number attribute.
|
||||
*
|
||||
* @return The correlation instance artifact or null, if the phone number is
|
||||
* not a valid correlation attribute.
|
||||
*
|
||||
* @throws TskCoreException If there is an error querying the case
|
||||
* database.
|
||||
* @throws CentralRepoException If there is an error querying the central
|
||||
* repository.
|
||||
*/
|
||||
private static CorrelationAttributeInstance makeCorrAttrFromArtifactPhoneAttr(BlackboardArtifact artifact) throws TskCoreException, CentralRepoException {
|
||||
CorrelationAttributeInstance corrAttr = null;
|
||||
|
||||
/*
|
||||
* Extract the phone number from the artifact attribute.
|
||||
*/
|
||||
String value = null;
|
||||
if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER))) {
|
||||
value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)).getValueString();
|
||||
} else if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM))) {
|
||||
value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM)).getValueString();
|
||||
} else if (null != artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO))) {
|
||||
value = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO)).getValueString();
|
||||
}
|
||||
|
||||
/*
|
||||
* Normalize the phone number.
|
||||
*/
|
||||
if (value != null) {
|
||||
String newValue = value.replaceAll("\\D", "");
|
||||
if (value.startsWith("+")) {
|
||||
newValue = "+" + newValue;
|
||||
}
|
||||
value = newValue;
|
||||
|
||||
/*
|
||||
* Validate the phone number. Three to five digit phone numbers may
|
||||
* be valid, but they are too short to use as correlation
|
||||
* attributes.
|
||||
*/
|
||||
if (value.length() > 5) {
|
||||
corrAttr = makeCorrAttr(artifact, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), value);
|
||||
}
|
||||
}
|
||||
|
||||
return corrAttr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a correlation attribute instance for an account artifact.
|
||||
*
|
||||
@ -248,6 +186,9 @@ public class CorrelationAttributeUtil {
|
||||
BlackboardAttribute accountTypeAttribute = acctArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE));
|
||||
String accountTypeStr = accountTypeAttribute.getValueString();
|
||||
|
||||
// do not create any correlation attribute instance for a Device account
|
||||
if (Account.Type.DEVICE.getTypeName().equalsIgnoreCase(accountTypeStr) == false) {
|
||||
|
||||
// Get the corresponding CentralRepoAccountType from the database.
|
||||
CentralRepoAccountType crAccountType = CentralRepository.getInstance().getAccountTypeByName(accountTypeStr);
|
||||
|
||||
@ -268,6 +209,7 @@ public class CorrelationAttributeUtil {
|
||||
corrAttrInstances.add(corrAttr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a correlation attribute instance from a specified attribute of an
|
||||
|
@ -19,13 +19,13 @@
|
||||
package org.sleuthkit.autopsy.centralrepository.datamodel;
|
||||
|
||||
/**
|
||||
* provides the status of the database after attempting to validate central repo settings
|
||||
* This enum provides the status of the database after attempting to validate central repo settings.
|
||||
*/
|
||||
public enum DatabaseTestResult {
|
||||
UNTESTED,
|
||||
CONNECTION_FAILED,
|
||||
SCHEMA_INVALID,
|
||||
DB_DOES_NOT_EXIST,
|
||||
TESTEDOK;
|
||||
TESTED_OK;
|
||||
}
|
||||
|
||||
|
@ -24,15 +24,9 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Pattern;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
import org.sleuthkit.autopsy.coreutils.TextConverter;
|
||||
import org.sleuthkit.autopsy.coreutils.TextConverterException;
|
||||
import static org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepo.SOFTWARE_CR_DB_SCHEMA_VERSION;
|
||||
|
||||
/**
|
||||
* Settings for the Postgres implementation of the Central Repository database
|
||||
@ -40,105 +34,83 @@ import static org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepo
|
||||
* NOTE: This is public scope because the options panel calls it directly to
|
||||
* set/get
|
||||
*/
|
||||
public final class PostgresCentralRepoSettings implements CentralRepoDbSettings {
|
||||
public final class PostgresCentralRepoSettings implements CentralRepoDbConnectivityManager {
|
||||
|
||||
private final static Logger LOGGER = Logger.getLogger(PostgresCentralRepoSettings.class.getName());
|
||||
private final static String DEFAULT_HOST = ""; // NON-NLS
|
||||
private final static int DEFAULT_PORT = 5432;
|
||||
private final static String DEFAULT_DBNAME = "central_repository"; // NON-NLS
|
||||
private final static String DEFAULT_USERNAME = "";
|
||||
private final static String DEFAULT_PASSWORD = "";
|
||||
private final static String VALIDATION_QUERY = "SELECT version()"; // NON-NLS
|
||||
private final static String JDBC_BASE_URI = "jdbc:postgresql://"; // NON-NLS
|
||||
private final static String JDBC_DRIVER = "org.postgresql.Driver"; // NON-NLS
|
||||
private final static String DB_NAMES_REGEX = "[a-z][a-z0-9_]*"; // only lower case
|
||||
private final static String DB_USER_NAMES_REGEX = "[a-zA-Z]\\w*";
|
||||
private String host;
|
||||
private int port;
|
||||
private String dbName;
|
||||
private int bulkThreshold;
|
||||
private String userName;
|
||||
private String password;
|
||||
|
||||
public PostgresCentralRepoSettings() {
|
||||
|
||||
private final PostgresSettingsLoader loader;
|
||||
private PostgresConnectionSettings connSettings;
|
||||
|
||||
private static PostgresSettingsLoader getLoaderFromSaved() throws CentralRepoException {
|
||||
CentralRepoDbChoice choice = CentralRepoDbManager.getSavedDbChoice();
|
||||
if (choice == CentralRepoDbChoice.POSTGRESQL_CUSTOM)
|
||||
return PostgresSettingsLoader.CUSTOM_SETTINGS_LOADER;
|
||||
else if (choice == CentralRepoDbChoice.POSTGRESQL_MULTIUSER)
|
||||
return PostgresSettingsLoader.MULTIUSER_SETTINGS_LOADER;
|
||||
else
|
||||
throw new CentralRepoException("cannot load or save postgres settings for selection: " + choice);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method loads the settings with a custom {@link PostgresSettingsLoader PostgresSettingsLoader} object.
|
||||
* @param loader The loader to be used.
|
||||
*/
|
||||
public PostgresCentralRepoSettings(PostgresSettingsLoader loader) {
|
||||
this.loader = loader;
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the default constructor that loads settings from selected db choice.
|
||||
*/
|
||||
public PostgresCentralRepoSettings() throws CentralRepoException {
|
||||
this(getLoaderFromSaved());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
this.connSettings = loader.loadSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveSettings() {
|
||||
loader.saveSettings(connSettings);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("PostgresCentralRepoSettings: [db type: postgres, host: %s:%d, db name: %s, username: %s]",
|
||||
getHost(), getPort(), getDbName(), getUserName());
|
||||
}
|
||||
|
||||
public void loadSettings() {
|
||||
host = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.host"); // NON-NLS
|
||||
if (host == null || host.isEmpty()) {
|
||||
host = DEFAULT_HOST;
|
||||
|
||||
/**
|
||||
* @return the VALIDATION_QUERY
|
||||
*/
|
||||
String getValidationQuery() {
|
||||
return VALIDATION_QUERY;
|
||||
}
|
||||
|
||||
try {
|
||||
String portString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.port"); // NON-NLS
|
||||
if (portString == null || portString.isEmpty()) {
|
||||
port = DEFAULT_PORT;
|
||||
} else {
|
||||
port = Integer.parseInt(portString);
|
||||
if (port < 0 || port > 65535) {
|
||||
port = DEFAULT_PORT;
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
port = DEFAULT_PORT;
|
||||
/**
|
||||
* @return the POSTGRES_DRIVER
|
||||
*/
|
||||
String getDriver() {
|
||||
return JDBC_DRIVER;
|
||||
}
|
||||
|
||||
dbName = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.dbName"); // NON-NLS
|
||||
if (dbName == null || dbName.isEmpty()) {
|
||||
dbName = DEFAULT_DBNAME;
|
||||
/**
|
||||
* @return the JDBC_BASE_URI
|
||||
*/
|
||||
String getJDBCBaseURI() {
|
||||
return JDBC_BASE_URI;
|
||||
}
|
||||
|
||||
try {
|
||||
String bulkThresholdString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.bulkThreshold"); // NON-NLS
|
||||
if (bulkThresholdString == null || bulkThresholdString.isEmpty()) {
|
||||
this.bulkThreshold = RdbmsCentralRepo.DEFAULT_BULK_THRESHHOLD;
|
||||
} else {
|
||||
this.bulkThreshold = Integer.parseInt(bulkThresholdString);
|
||||
if (getBulkThreshold() <= 0) {
|
||||
this.bulkThreshold = RdbmsCentralRepo.DEFAULT_BULK_THRESHHOLD;
|
||||
}
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
this.bulkThreshold = RdbmsCentralRepo.DEFAULT_BULK_THRESHHOLD;
|
||||
}
|
||||
|
||||
userName = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.user"); // NON-NLS
|
||||
if (userName == null || userName.isEmpty()) {
|
||||
userName = DEFAULT_USERNAME;
|
||||
}
|
||||
|
||||
password = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.password"); // NON-NLS
|
||||
if (password == null || password.isEmpty()) {
|
||||
password = DEFAULT_PASSWORD;
|
||||
} else {
|
||||
try {
|
||||
password = TextConverter.convertHexTextToText(password);
|
||||
} catch (TextConverterException ex) {
|
||||
LOGGER.log(Level.WARNING, "Failed to convert password from hex text to text.", ex);
|
||||
password = DEFAULT_PASSWORD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void saveSettings() {
|
||||
ModuleSettings.setConfigSetting("CentralRepository", "db.postgresql.host", getHost()); // NON-NLS
|
||||
ModuleSettings.setConfigSetting("CentralRepository", "db.postgresql.port", Integer.toString(port)); // NON-NLS
|
||||
ModuleSettings.setConfigSetting("CentralRepository", "db.postgresql.dbName", getDbName()); // NON-NLS
|
||||
ModuleSettings.setConfigSetting("CentralRepository", "db.postgresql.bulkThreshold", Integer.toString(getBulkThreshold())); // NON-NLS
|
||||
ModuleSettings.setConfigSetting("CentralRepository", "db.postgresql.user", getUserName()); // NON-NLS
|
||||
try {
|
||||
ModuleSettings.setConfigSetting("CentralRepository", "db.postgresql.password", TextConverter.convertTextToHexText(getPassword())); // NON-NLS
|
||||
} catch (TextConverterException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to convert password from text to hex text.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full connection URL as a String
|
||||
@ -302,72 +274,32 @@ public final class PostgresCentralRepoSettings implements CentralRepoDbSettings
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
boolean isChanged() {
|
||||
String hostString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.host"); // NON-NLS
|
||||
String portString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.port"); // NON-NLS
|
||||
String dbNameString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.dbName"); // NON-NLS
|
||||
String bulkThresholdString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.bulkThreshold"); // NON-NLS
|
||||
String userNameString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.user"); // NON-NLS
|
||||
String userPasswordString = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.password"); // NON-NLS
|
||||
|
||||
return !host.equals(hostString) || !Integer.toString(port).equals(portString)
|
||||
|| !dbName.equals(dbNameString) || !Integer.toString(bulkThreshold).equals(bulkThresholdString)
|
||||
|| !userName.equals(userNameString) || !password.equals(userPasswordString);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the host
|
||||
*/
|
||||
public String getHost() {
|
||||
return host;
|
||||
return connSettings.getHost();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param host the host to set
|
||||
*/
|
||||
public void setHost(String host) throws CentralRepoException {
|
||||
if (null != host && !host.isEmpty()) {
|
||||
this.host = host;
|
||||
} else {
|
||||
throw new CentralRepoException("Invalid host name. Cannot be empty."); // NON-NLS
|
||||
}
|
||||
connSettings.setHost(host);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the port
|
||||
*/
|
||||
public int getPort() {
|
||||
return port;
|
||||
return connSettings.getPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param port the port to set
|
||||
*/
|
||||
public void setPort(int port) throws CentralRepoException {
|
||||
if (port > 0 && port < 65535) {
|
||||
this.port = port;
|
||||
} else {
|
||||
throw new CentralRepoException("Invalid port. Must be a number greater than 0."); // NON-NLS
|
||||
}
|
||||
connSettings.setPort(port);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -377,95 +309,72 @@ public final class PostgresCentralRepoSettings implements CentralRepoDbSettings
|
||||
* @return the dbName
|
||||
*/
|
||||
public String getDbName() {
|
||||
return dbName.toLowerCase();
|
||||
return connSettings.getDbName() == null ? null : connSettings.getDbName().toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dbName the dbName to set
|
||||
*/
|
||||
public void setDbName(String dbName) throws CentralRepoException {
|
||||
if (dbName == null || dbName.isEmpty()) {
|
||||
throw new CentralRepoException("Invalid database name. Cannot be empty."); // NON-NLS
|
||||
} else if (!Pattern.matches(DB_NAMES_REGEX, dbName)) {
|
||||
throw new CentralRepoException("Invalid database name. Name must start with a lowercase letter and can only contain lowercase letters, numbers, and '_'."); // NON-NLS
|
||||
}
|
||||
|
||||
this.dbName = dbName.toLowerCase();
|
||||
connSettings.setDbName(dbName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the bulkThreshold
|
||||
*/
|
||||
int getBulkThreshold() {
|
||||
return bulkThreshold;
|
||||
return connSettings.getBulkThreshold();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bulkThreshold the bulkThreshold to set
|
||||
*/
|
||||
public void setBulkThreshold(int bulkThreshold) throws CentralRepoException {
|
||||
if (bulkThreshold > 0) {
|
||||
this.bulkThreshold = bulkThreshold;
|
||||
} else {
|
||||
throw new CentralRepoException("Invalid bulk threshold."); // NON-NLS
|
||||
}
|
||||
connSettings.setBulkThreshold(bulkThreshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the userName
|
||||
*/
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
return connSettings.getUserName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param userName the userName to set
|
||||
*/
|
||||
public void setUserName(String userName) throws CentralRepoException {
|
||||
if (userName == null || userName.isEmpty()) {
|
||||
throw new CentralRepoException("Invalid user name. Cannot be empty."); // NON-NLS
|
||||
} else if (!Pattern.matches(DB_USER_NAMES_REGEX, userName)) {
|
||||
throw new CentralRepoException("Invalid user name. Name must start with a letter and can only contain letters, numbers, and '_'."); // NON-NLS
|
||||
}
|
||||
this.userName = userName;
|
||||
connSettings.setUserName(userName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the password
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
return connSettings.getPassword();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param password the password to set
|
||||
*/
|
||||
public void setPassword(String password) throws CentralRepoException {
|
||||
if (password == null || password.isEmpty()) {
|
||||
throw new CentralRepoException("Invalid user password. Cannot be empty."); // NON-NLS
|
||||
}
|
||||
this.password = password;
|
||||
connSettings.setPassword(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the VALIDATION_QUERY
|
||||
*/
|
||||
String getValidationQuery() {
|
||||
return VALIDATION_QUERY;
|
||||
@Override
|
||||
public DatabaseTestResult testStatus() {
|
||||
if (verifyConnection()) {
|
||||
if (verifyDatabaseExists()) {
|
||||
if (verifyDatabaseSchema()) {
|
||||
return DatabaseTestResult.TESTED_OK;
|
||||
} else {
|
||||
return DatabaseTestResult.SCHEMA_INVALID;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the POSTGRES_DRIVER
|
||||
*/
|
||||
String getDriver() {
|
||||
return JDBC_DRIVER;
|
||||
} else {
|
||||
return DatabaseTestResult.DB_DOES_NOT_EXIST;
|
||||
}
|
||||
} else {
|
||||
return DatabaseTestResult.CONNECTION_FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the JDBC_BASE_URI
|
||||
*/
|
||||
String getJDBCBaseURI() {
|
||||
return JDBC_BASE_URI;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2015-2020 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.datamodel;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
* This class is a POJO for postgres settings to be used with central repository.
|
||||
*/
|
||||
public class PostgresConnectionSettings {
|
||||
private final static String DB_NAMES_REGEX = "[a-z][a-z0-9_]*"; // only lower case
|
||||
private final static String DB_USER_NAMES_REGEX = "[a-zA-Z]\\w*";
|
||||
|
||||
public final static String DEFAULT_HOST = ""; // NON-NLS
|
||||
public final static int DEFAULT_PORT = 5432;
|
||||
public final static String DEFAULT_DBNAME = "central_repository"; // NON-NLS
|
||||
public final static String DEFAULT_USERNAME = "";
|
||||
public final static String DEFAULT_PASSWORD = "";
|
||||
|
||||
private static void validateStr(String s, String errMessage) throws CentralRepoException {
|
||||
if (null == s || s.isEmpty())
|
||||
throw new CentralRepoException(errMessage);
|
||||
}
|
||||
|
||||
private static void validateRegex(String s, String pattern, String errMessage) throws CentralRepoException {
|
||||
if (!Pattern.matches(pattern, s))
|
||||
throw new CentralRepoException(errMessage);
|
||||
}
|
||||
|
||||
private static void validateNum(int num, Integer min, Integer max, String errMessage) throws CentralRepoException {
|
||||
if ((min != null && num < min) || (max != null && num > max))
|
||||
throw new CentralRepoException(errMessage);
|
||||
}
|
||||
|
||||
private String host = DEFAULT_HOST;
|
||||
private int port = DEFAULT_PORT;
|
||||
private String dbName = DEFAULT_DBNAME;
|
||||
private int bulkThreshold = RdbmsCentralRepo.DEFAULT_BULK_THRESHHOLD;
|
||||
private String userName = DEFAULT_USERNAME;
|
||||
private String password = DEFAULT_PASSWORD;
|
||||
|
||||
/**
|
||||
* This method retrieves the postgres host.
|
||||
* @return The host for these settings.
|
||||
*/
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the port number for these settings.
|
||||
* @return The port number for these settings.
|
||||
*/
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the database name for these settings.
|
||||
* @return The database name for these settings.
|
||||
*/
|
||||
public String getDbName() {
|
||||
return dbName;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the bulk threshold.
|
||||
* @return The bulk threshold.
|
||||
*/
|
||||
public int getBulkThreshold() {
|
||||
return bulkThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the username to use for this connection.
|
||||
* @return The username to use.
|
||||
*/
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the password to use for this connection.
|
||||
* @return The password to use for this connection.
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method sets the host for this connection.
|
||||
* NOTE: must be non-empty string.
|
||||
* @param host the host to set
|
||||
*/
|
||||
public void setHost(String host) throws CentralRepoException {
|
||||
validateStr(host, "Invalid host name. Cannot be empty.");
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method sets the port for this connection.
|
||||
* @param port The port to set (must be [1,65535]).
|
||||
*/
|
||||
public void setPort(int port) throws CentralRepoException {
|
||||
validateNum(port, 1, 65535, "Invalid port. Must be a number greater than 0.");
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This methods sets the name of the database.
|
||||
* NOTE: this name needs to be a valid postgres database name.
|
||||
* @param dbName The database name.
|
||||
*/
|
||||
public void setDbName(String dbName) throws CentralRepoException {
|
||||
validateStr(dbName, "Invalid database name. Cannot be empty."); // NON-NLS
|
||||
validateRegex(dbName, DB_NAMES_REGEX,
|
||||
"Invalid database name. Name must start with a lowercase letter and can only contain lowercase letters, numbers, and '_'."); // NON-NLS
|
||||
|
||||
this.dbName = dbName.toLowerCase();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method sets the bulk threshold of this connection.
|
||||
* @param bulkThreshold The bulk threshold to set (must be greater than 0).
|
||||
*/
|
||||
public void setBulkThreshold(int bulkThreshold) throws CentralRepoException {
|
||||
validateNum(bulkThreshold, 1, null, "Invalid bulk threshold.");
|
||||
this.bulkThreshold = bulkThreshold;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method sets the username for this connection.
|
||||
* NOTE: must be a valid postgres username.
|
||||
* @param userName The user name to set.
|
||||
*/
|
||||
public void setUserName(String userName) throws CentralRepoException {
|
||||
validateStr(userName, "Invalid user name. Cannot be empty."); // NON-NLS
|
||||
validateRegex(userName, DB_USER_NAMES_REGEX,
|
||||
"Invalid user name. Name must start with a letter and can only contain letters, numbers, and '_'.");
|
||||
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method sets the password for this connection.
|
||||
* @param password The password to set.
|
||||
*/
|
||||
public void setPassword(String password) throws CentralRepoException {
|
||||
validateStr(password, "Invalid user password. Cannot be empty.");
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 7;
|
||||
hash = 43 * hash + Objects.hashCode(this.host);
|
||||
hash = 43 * hash + this.port;
|
||||
hash = 43 * hash + Objects.hashCode(this.dbName);
|
||||
hash = 43 * hash + this.bulkThreshold;
|
||||
hash = 43 * hash + Objects.hashCode(this.userName);
|
||||
hash = 43 * hash + Objects.hashCode(this.password);
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final PostgresConnectionSettings other = (PostgresConnectionSettings) obj;
|
||||
if (this.port != other.port) {
|
||||
return false;
|
||||
}
|
||||
if (this.bulkThreshold != other.bulkThreshold) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.host, other.host)) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.dbName, other.dbName)) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.userName, other.userName)) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(this.password, other.password)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Central Repository
|
||||
*
|
||||
* Copyright 2015-2020 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.datamodel;
|
||||
|
||||
/**
|
||||
* This is an interface to load or save postgres settings.
|
||||
*/
|
||||
public interface PostgresSettingsLoader {
|
||||
/**
|
||||
* This method loads the current settings.
|
||||
* @return The settings that were loaded.
|
||||
*/
|
||||
PostgresConnectionSettings loadSettings();
|
||||
|
||||
/**
|
||||
* This method saves the current settings.
|
||||
* @param settings The settings to save.
|
||||
*/
|
||||
void saveSettings(PostgresConnectionSettings settings);
|
||||
|
||||
PostgresSettingsLoader CUSTOM_SETTINGS_LOADER = new Custom();
|
||||
PostgresSettingsLoader MULTIUSER_SETTINGS_LOADER = new MultiUser();
|
||||
CentralRepoPostgresSettingsUtil SETTINGS_UTIL = CentralRepoPostgresSettingsUtil.getInstance();
|
||||
|
||||
|
||||
/**
|
||||
* This class loads and saves custom postgres settings.
|
||||
*/
|
||||
class Custom implements PostgresSettingsLoader {
|
||||
@Override
|
||||
public PostgresConnectionSettings loadSettings() {
|
||||
return SETTINGS_UTIL.loadCustomSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveSettings(PostgresConnectionSettings settings) {
|
||||
SETTINGS_UTIL.saveCustomSettings(settings);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This class loads multi-user postgres settings to be used with central repo.
|
||||
* NOTE: This class does not save settings on save operation as this is merely a proxy.
|
||||
*/
|
||||
class MultiUser implements PostgresSettingsLoader {
|
||||
|
||||
@Override
|
||||
public PostgresConnectionSettings loadSettings() {
|
||||
return SETTINGS_UTIL.loadMultiUserSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: This action does not do anything. There is no need to save since
|
||||
* this is just a proxy to multi user settings.
|
||||
* @param settings The settings to save.
|
||||
*/
|
||||
@Override
|
||||
public void saveSettings(PostgresConnectionSettings settings) {}
|
||||
}
|
||||
}
|
@ -65,7 +65,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
|
||||
static final String SCHEMA_MINOR_VERSION_KEY = "SCHEMA_MINOR_VERSION";
|
||||
static final String CREATION_SCHEMA_MAJOR_VERSION_KEY = "CREATION_SCHEMA_MAJOR_VERSION";
|
||||
static final String CREATION_SCHEMA_MINOR_VERSION_KEY = "CREATION_SCHEMA_MINOR_VERSION";
|
||||
static final CaseDbSchemaVersionNumber SOFTWARE_CR_DB_SCHEMA_VERSION = new CaseDbSchemaVersionNumber(1, 3);
|
||||
static final CaseDbSchemaVersionNumber SOFTWARE_CR_DB_SCHEMA_VERSION = new CaseDbSchemaVersionNumber(1, 4);
|
||||
|
||||
protected final List<CorrelationAttributeInstance.Type> defaultCorrelationTypes;
|
||||
|
||||
@ -1002,18 +1002,26 @@ abstract class RdbmsCentralRepo implements CentralRepository {
|
||||
public void addArtifactInstance(CorrelationAttributeInstance eamArtifact) throws CentralRepoException {
|
||||
checkAddArtifactInstanceNulls(eamArtifact);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// @@@ We should cache the case and data source IDs in memory
|
||||
String tableName = CentralRepoDbUtil.correlationTypeToInstanceTableName(eamArtifact.getCorrelationType());
|
||||
String sql
|
||||
= "INSERT INTO "
|
||||
boolean artifactHasAnAccount = CentralRepoDbUtil.correlationAttribHasAnAccount(eamArtifact.getCorrelationType());
|
||||
|
||||
String sql;
|
||||
// _instance table for accounts have an additional account_id column
|
||||
if (artifactHasAnAccount) {
|
||||
sql = "INSERT INTO "
|
||||
+ tableName
|
||||
+ "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id, account_id) "
|
||||
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?) "
|
||||
+ getConflictClause();
|
||||
}
|
||||
else {
|
||||
sql = "INSERT INTO "
|
||||
+ tableName
|
||||
+ "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
|
||||
+ "VALUES (?, ?, ?, ?, ?, ?, ?) "
|
||||
+ getConflictClause();
|
||||
}
|
||||
|
||||
try (Connection conn = connect();
|
||||
PreparedStatement preparedStatement = conn.prepareStatement(sql);) {
|
||||
@ -1032,11 +1040,14 @@ abstract class RdbmsCentralRepo implements CentralRepository {
|
||||
}
|
||||
preparedStatement.setLong(7, eamArtifact.getFileObjectId());
|
||||
|
||||
// set in the accountId only for artifacts that represent accounts
|
||||
if (artifactHasAnAccount) {
|
||||
if (eamArtifact.getAccountId() >= 0) {
|
||||
preparedStatement.setLong(8, eamArtifact.getAccountId());
|
||||
} else {
|
||||
preparedStatement.setNull(8, Types.INTEGER);
|
||||
}
|
||||
}
|
||||
|
||||
preparedStatement.executeUpdate();
|
||||
}
|
||||
@ -3553,7 +3564,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
|
||||
conn = connect(false);
|
||||
conn.setAutoCommit(false);
|
||||
statement = conn.createStatement();
|
||||
selectedPlatform = CentralRepoPlatforms.getSelectedPlatform();
|
||||
selectedPlatform = CentralRepoDbManager.getSavedDbChoice().getDbPlatform();
|
||||
int minorVersion = 0;
|
||||
String minorVersionStr = null;
|
||||
resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "'");
|
||||
@ -3808,6 +3819,10 @@ abstract class RdbmsCentralRepo implements CentralRepository {
|
||||
throw new CentralRepoException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.", Bundle.AbstractSqlEamDb_cannotUpgrage_message(selectedPlatform.name()));
|
||||
}
|
||||
}
|
||||
|
||||
// Upgrade to 1.4
|
||||
(new CentralRepoDbUpgrader13To14()).upgradeSchema(dbSchemaVersion, conn);
|
||||
|
||||
updateSchemaVersion(conn);
|
||||
conn.commit();
|
||||
logger.log(Level.INFO, String.format("Central Repository schema updated to version %s", SOFTWARE_CR_DB_SCHEMA_VERSION));
|
||||
|
@ -83,6 +83,7 @@ public class RdbmsCentralRepoFactory {
|
||||
public boolean initializeDatabaseSchema() {
|
||||
|
||||
String createArtifactInstancesTableTemplate = getCreateArtifactInstancesTableTemplate(selectedPlatform);
|
||||
String createAccountInstancesTableTemplate = getCreateAccountInstancesTableTemplate(selectedPlatform);
|
||||
|
||||
String instancesCaseIdIdx = getAddCaseIdIndexTemplate();
|
||||
String instancesDatasourceIdIdx = getAddDataSourceIdIndexTemplate();
|
||||
@ -147,7 +148,13 @@ public class RdbmsCentralRepoFactory {
|
||||
reference_type_dbname = CentralRepoDbUtil.correlationTypeToReferenceTableName(type);
|
||||
instance_type_dbname = CentralRepoDbUtil.correlationTypeToInstanceTableName(type);
|
||||
|
||||
stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname));
|
||||
// use the correct create table template, based on whether the attribute type represents an account or not.
|
||||
String createTableTemplate = (CentralRepoDbUtil.correlationAttribHasAnAccount(type))
|
||||
? createAccountInstancesTableTemplate
|
||||
: createArtifactInstancesTableTemplate;
|
||||
|
||||
stmt.execute(String.format(createTableTemplate, instance_type_dbname, instance_type_dbname));
|
||||
|
||||
stmt.execute(String.format(instancesCaseIdIdx, instance_type_dbname, instance_type_dbname));
|
||||
stmt.execute(String.format(instancesDatasourceIdIdx, instance_type_dbname, instance_type_dbname));
|
||||
stmt.execute(String.format(instancesValueIdx, instance_type_dbname, instance_type_dbname));
|
||||
@ -193,7 +200,7 @@ public class RdbmsCentralRepoFactory {
|
||||
|
||||
result = CentralRepoDbUtil.insertDefaultCorrelationTypes(conn)
|
||||
&& CentralRepoDbUtil.insertDefaultOrganization(conn) &&
|
||||
insertDefaultAccountsTablesContent(conn);
|
||||
RdbmsCentralRepoFactory.insertDefaultAccountsTablesContent(conn, selectedPlatform );
|
||||
// @TODO: uncomment when ready to create/populate persona tables
|
||||
// && insertDefaultPersonaTablesContent(conn);
|
||||
|
||||
@ -357,7 +364,7 @@ public class RdbmsCentralRepoFactory {
|
||||
+ ")";
|
||||
}
|
||||
/**
|
||||
* Get the template String for creating a new _instances table in a Sqlite
|
||||
* Get the template String for creating a new _instances table for non account artifacts in
|
||||
* central repository. %s will exist in the template where the name of the
|
||||
* new table will be added.
|
||||
*
|
||||
@ -365,6 +372,31 @@ public class RdbmsCentralRepoFactory {
|
||||
*/
|
||||
static String getCreateArtifactInstancesTableTemplate(CentralRepoPlatforms selectedPlatform) {
|
||||
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
||||
|
||||
return "CREATE TABLE IF NOT EXISTS %s ("
|
||||
+ getNumericPrimaryKeyClause("id", selectedPlatform)
|
||||
+ "case_id integer NOT NULL,"
|
||||
+ "data_source_id integer NOT NULL,"
|
||||
+ "value text NOT NULL,"
|
||||
+ "file_path text NOT NULL,"
|
||||
+ "known_status integer NOT NULL,"
|
||||
+ "comment text,"
|
||||
+ "file_obj_id " + getBigIntType(selectedPlatform) + " ,"
|
||||
+ "CONSTRAINT %s_multi_unique UNIQUE(data_source_id, value, file_path)" + getOnConflictIgnoreClause(selectedPlatform) + ","
|
||||
+ "foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,"
|
||||
+ "foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL)";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the template String for creating a new _instances table for Accounts in
|
||||
* central repository. %s will exist in the template where the name of the
|
||||
* new table will be added.
|
||||
*
|
||||
* @return a String which is a template for creating a _instances table
|
||||
*/
|
||||
static String getCreateAccountInstancesTableTemplate(CentralRepoPlatforms selectedPlatform) {
|
||||
// Each "%s" will be replaced with the relevant TYPE_instances table name.
|
||||
|
||||
return "CREATE TABLE IF NOT EXISTS %s ("
|
||||
+ getNumericPrimaryKeyClause("id", selectedPlatform)
|
||||
+ "case_id integer NOT NULL,"
|
||||
@ -532,7 +564,7 @@ public class RdbmsCentralRepoFactory {
|
||||
*
|
||||
* @return SQL clause.
|
||||
*/
|
||||
private static String getBigIntType(CentralRepoPlatforms selectedPlatform) {
|
||||
static String getBigIntType(CentralRepoPlatforms selectedPlatform) {
|
||||
switch (selectedPlatform) {
|
||||
case POSTGRESQL:
|
||||
return " BIGINT ";
|
||||
@ -766,33 +798,6 @@ public class RdbmsCentralRepoFactory {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inserts the default content in accounts related tables.
|
||||
*
|
||||
* @param conn Database connection to use.
|
||||
*
|
||||
* @return True if success, false otherwise.
|
||||
*/
|
||||
private boolean insertDefaultAccountsTablesContent(Connection conn) {
|
||||
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
// Populate the account_types table
|
||||
for (Account.Type type : Account.Type.PREDEFINED_ACCOUNT_TYPES) {
|
||||
int correlationTypeId = getCorrelationTypeIdForAccountType(conn, type);
|
||||
if (correlationTypeId > 0) {
|
||||
String sqlString = String.format("INSERT INTO account_types (type_name, display_name, correlation_type_id) VALUES ('%s', '%s', %d)" + getOnConflictDoNothingClause(selectedPlatform),
|
||||
type.getTypeName(), type.getDisplayName(), correlationTypeId);
|
||||
stmt.execute(sqlString);
|
||||
}
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.SEVERE, String.format("Failed to populate default data in Accounts tables."), ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the default content in persona related tables.
|
||||
*
|
||||
@ -800,7 +805,7 @@ public class RdbmsCentralRepoFactory {
|
||||
*
|
||||
* @return True if success, false otherwise.
|
||||
*/
|
||||
private boolean insertDefaultPersonaTablesContent(Connection conn) {
|
||||
private static boolean insertDefaultPersonaTablesContent(Connection conn, CentralRepoPlatforms selectedPlatform) {
|
||||
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
// populate the confidence table
|
||||
@ -825,6 +830,37 @@ public class RdbmsCentralRepoFactory {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the default content in accounts related tables.
|
||||
*
|
||||
* @param conn Database connection to use.
|
||||
*
|
||||
* @return True if success, false otherwise.
|
||||
*/
|
||||
static boolean insertDefaultAccountsTablesContent(Connection conn, CentralRepoPlatforms selectedPlatform) {
|
||||
|
||||
try (Statement stmt = conn.createStatement();) {
|
||||
|
||||
// Populate the account_types table
|
||||
for (Account.Type type : Account.Type.PREDEFINED_ACCOUNT_TYPES) {
|
||||
if (type != Account.Type.DEVICE) {
|
||||
int correlationTypeId = getCorrelationTypeIdForAccountType(conn, type);
|
||||
if (correlationTypeId > 0) {
|
||||
String sqlString = String.format("INSERT INTO account_types (type_name, display_name, correlation_type_id) VALUES ('%s', '%s', %d)" + getOnConflictDoNothingClause(selectedPlatform),
|
||||
type.getTypeName(), type.getDisplayName(), correlationTypeId);
|
||||
stmt.execute(sqlString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.SEVERE, String.format("Failed to populate default data in account_types table."), ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the correlation type id for the given account type,
|
||||
* from the correlation_types table.
|
||||
@ -834,7 +870,7 @@ public class RdbmsCentralRepoFactory {
|
||||
* '
|
||||
* @return correlation type id.
|
||||
*/
|
||||
private int getCorrelationTypeIdForAccountType(Connection conn, Account.Type accountType) {
|
||||
static int getCorrelationTypeIdForAccountType(Connection conn, Account.Type accountType) {
|
||||
|
||||
int typeId = -1;
|
||||
if (accountType == Account.Type.EMAIL) {
|
||||
|
@ -37,7 +37,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
* NOTE: This is public scope because the options panel calls it directly to
|
||||
* set/get
|
||||
*/
|
||||
public final class SqliteCentralRepoSettings implements CentralRepoDbSettings {
|
||||
public final class SqliteCentralRepoSettings implements CentralRepoDbConnectivityManager {
|
||||
|
||||
public final static String DEFAULT_DBNAME = "central_repository.db"; // NON-NLS
|
||||
private final static Logger LOGGER = Logger.getLogger(SqliteCentralRepoSettings.class.getName());
|
||||
@ -115,13 +115,11 @@ public final class SqliteCentralRepoSettings implements CentralRepoDbSettings {
|
||||
return (!dbFile.isDirectory());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean verifyDatabaseExists() {
|
||||
return dbDirectoryExists();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verify that the db directory path exists.
|
||||
*
|
||||
@ -143,6 +141,7 @@ public final class SqliteCentralRepoSettings implements CentralRepoDbSettings {
|
||||
|
||||
/**
|
||||
* creates database directory for sqlite database if it does not exist
|
||||
*
|
||||
* @return whether or not operation occurred successfully
|
||||
*/
|
||||
@Override
|
||||
@ -150,7 +149,6 @@ public final class SqliteCentralRepoSettings implements CentralRepoDbSettings {
|
||||
return createDbDirectory();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the db directory if it does not exist.
|
||||
*
|
||||
@ -354,4 +352,21 @@ public final class SqliteCentralRepoSettings implements CentralRepoDbSettings {
|
||||
String getJDBCBaseURI() {
|
||||
return JDBC_BASE_URI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DatabaseTestResult testStatus() {
|
||||
if (dbFileExists()) {
|
||||
if (verifyConnection()) {
|
||||
if (verifyDatabaseSchema()) {
|
||||
return DatabaseTestResult.TESTED_OK;
|
||||
} else {
|
||||
return DatabaseTestResult.SCHEMA_INVALID;
|
||||
}
|
||||
} else {
|
||||
return DatabaseTestResult.SCHEMA_INVALID;
|
||||
}
|
||||
} else {
|
||||
return DatabaseTestResult.DB_DOES_NOT_EXIST;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbManager;
|
||||
import org.sleuthkit.autopsy.centralrepository.eventlisteners.IngestEventsListener;
|
||||
import org.sleuthkit.autopsy.core.RuntimeProperties;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
@ -274,7 +275,7 @@ final class CentralRepoIngestModule implements FileIngestModule {
|
||||
|
||||
// Don't allow sqlite central repo databases to be used for multi user cases
|
||||
if ((autopsyCase.getCaseType() == Case.CaseType.MULTI_USER_CASE)
|
||||
&& (CentralRepoPlatforms.getSelectedPlatform() == CentralRepoPlatforms.SQLITE)) {
|
||||
&& (CentralRepoDbManager.getSavedDbChoice().getDbPlatform() == CentralRepoPlatforms.SQLITE)) {
|
||||
logger.log(Level.SEVERE, "Cannot run correlation engine on a multi-user case with a SQLite central repository.");
|
||||
throw new IngestModuleException("Cannot run on a multi-user case with a SQLite central repository."); // NON-NLS
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ EamDbSettingsDialog.okButton.createDbDialog.title=Database Does Not Exist
|
||||
EamDbSettingsDialog.okButton.createDbError.title=Unable to Create Database
|
||||
EamDbSettingsDialog.okButton.createPostgresDbError.message=Unable to create Postgres Database, please ensure address, port, and login credentials are correct for Postgres server and try again.
|
||||
EamDbSettingsDialog.okButton.createSQLiteDbError.message=Unable to create SQLite Database, please ensure location exists and you have write permissions and try again.
|
||||
EamDbSettingsDialog.okButton.databaseConnectionFailed.message=Unable to connect to database please check your settings and try again.
|
||||
EamDbSettingsDialog.okButton.databaseConnectionFailed.message=Unable to connect to database. Please check your settings and try again.
|
||||
EamDbSettingsDialog.okButton.databaseConnectionFailed.title=Database Connection Failed
|
||||
EamDbSettingsDialog.okButton.errorMsg.text=Please restart Autopsy to begin using the new database platform.
|
||||
EamDbSettingsDialog.okButton.errorTitle.text=Restart Required.
|
||||
@ -33,6 +33,12 @@ EamDbSettingsDialog.validation.finished=Click OK to save your database settings
|
||||
EamDbSettingsDialog.validation.incompleteFields=Fill in all values for the selected database.
|
||||
EamOptionsController.moduleErr=Error processing value changes.
|
||||
EamOptionsController.moduleErr.msg=Value change processing failed.
|
||||
GlobalSettingsPanel.onMultiUserChange.disabledMu.description=The Central Repository will be reconfigured to use a local SQLite database.
|
||||
GlobalSettingsPanel.onMultiUserChange.disabledMu.description2=Press Configure PostgreSQL to change to a PostgreSQL database.
|
||||
GlobalSettingsPanel.onMultiUserChange.disabledMu.title=Central Repository Change Necessary
|
||||
GlobalSettingsPanel.onMultiUserChange.enable.description=Do you want to update the Central Repository to use this PostgreSQL database?
|
||||
GlobalSettingsPanel.onMultiUserChange.enable.description2=The Central Repository stores hash values and accounts from past cases.
|
||||
GlobalSettingsPanel.onMultiUserChange.enable.title=Use with Central Repository?
|
||||
GlobalSettingsPanel.updateFailed.title=Central repository disabled
|
||||
GlobalSettingsPanel.validationErrMsg.ingestRunning=You cannot change settings while ingest is running.
|
||||
GlobalSettingsPanel.validationerrMsg.mustConfigure=Configure the database to enable this module.
|
||||
|
@ -138,16 +138,16 @@
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="tfDatabasePath" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="bnDatabasePathFileOpen" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="cbDatabaseType" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<Component id="lbSingleUserSqLite" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="cbDatabaseType" min="-2" pref="210" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="lbSingleUserSqLite" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="jpDbPassword" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="tbDbUsername" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
@ -320,7 +320,7 @@
|
||||
<Component class="javax.swing.JComboBox" name="cbDatabaseType">
|
||||
<Properties>
|
||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="new javax.swing.DefaultComboBoxModel<>(new org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms[]{org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms.POSTGRESQL, org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms.SQLITE})" type="code"/>
|
||||
<Connection code="new javax.swing.DefaultComboBoxModel<>(org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbChoice.DB_CHOICES)" type="code"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[120, 20]"/>
|
||||
@ -330,7 +330,7 @@
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbDatabaseTypeActionPerformed"/>
|
||||
</Events>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms>"/>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbChoice>"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="lbSingleUserSqLite">
|
||||
|
@ -19,17 +19,24 @@
|
||||
package org.sleuthkit.autopsy.centralrepository.optionspanel;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.HeadlessException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.ListCellRenderer;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
@ -38,6 +45,7 @@ import org.netbeans.spi.options.OptionsPanelController;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbChoice;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbManager;
|
||||
import org.sleuthkit.autopsy.corecomponents.TextPrompt;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
@ -45,8 +53,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.DatabaseTestResult;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteCentralRepoSettings;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepoFactory;
|
||||
|
||||
/**
|
||||
* Configuration dialog for Central Repository database settings.
|
||||
@ -57,9 +63,40 @@ public class EamDbSettingsDialog extends JDialog {
|
||||
private static final Logger logger = Logger.getLogger(EamDbSettingsDialog.class.getName());
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* This class handles displaying and rendering drop down menu for database choices in central repo.
|
||||
*/
|
||||
private class DbChoiceRenderer extends JLabel implements ListCellRenderer<CentralRepoDbChoice>, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(
|
||||
JList<? extends CentralRepoDbChoice> list, CentralRepoDbChoice value,
|
||||
int index, boolean isSelected, boolean cellHasFocus) {
|
||||
|
||||
// disable cell if it is the db connection from multi user settings
|
||||
// and that option is not enabled in multi user settings
|
||||
setText(value.getTitle());
|
||||
setEnabled(isDbChoiceSelectable(value));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final Collection<JTextField> textBoxes;
|
||||
private final TextBoxChangedListener textBoxChangedListener;
|
||||
private final CentralRepoDbManager manager = new CentralRepoDbManager();
|
||||
private final boolean isMultiUserSelectable = CentralRepoDbManager.isPostgresMultiuserAllowed();
|
||||
private final DbChoiceRenderer DB_CHOICE_RENDERER = new DbChoiceRenderer();
|
||||
|
||||
public EamDbSettingsDialog() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
private boolean isDbChoiceSelectable(CentralRepoDbChoice item) {
|
||||
return (item != CentralRepoDbChoice.POSTGRESQL_MULTIUSER || isMultiUserSelectable);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@ -69,7 +106,7 @@ public class EamDbSettingsDialog extends JDialog {
|
||||
"EamDbSettingsDialog.lbSingleUserSqLite.text=SQLite should only be used by one examiner at a time.",
|
||||
"EamDbSettingsDialog.lbDatabaseType.text=Database Type :",
|
||||
"EamDbSettingsDialog.fcDatabasePath.title=Select location for central_repository.db"})
|
||||
public EamDbSettingsDialog() {
|
||||
public EamDbSettingsDialog(CentralRepoDbChoice initialMenuItem) {
|
||||
super((JFrame) WindowManager.getDefault().getMainWindow(),
|
||||
Bundle.EamDbSettingsDialog_title_text(),
|
||||
true);
|
||||
@ -95,29 +132,43 @@ public class EamDbSettingsDialog extends JDialog {
|
||||
return "Directories and Central Repository databases";
|
||||
}
|
||||
});
|
||||
cbDatabaseType.setSelectedItem(manager.getSelectedPlatform());
|
||||
customizeComponents();
|
||||
|
||||
setupDbChoice(initialMenuItem);
|
||||
valid();
|
||||
display();
|
||||
}
|
||||
|
||||
|
||||
private void setupDbChoice(CentralRepoDbChoice initialMenuItem) {
|
||||
// setup initially selected item
|
||||
CentralRepoDbChoice toSelect = (initialMenuItem == null) ?
|
||||
(Arrays.asList(CentralRepoDbChoice.DB_CHOICES).contains(manager.getSelectedDbChoice())) ?
|
||||
manager.getSelectedDbChoice() :
|
||||
CentralRepoDbChoice.DB_CHOICES[0] :
|
||||
initialMenuItem;
|
||||
|
||||
cbDatabaseType.setRenderer(DB_CHOICE_RENDERER);
|
||||
changeDbSelection(toSelect);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* prompts user based on testing status (i.e. failure to connect, invalid schema, db does not exist, etc.)
|
||||
* @return whether or not the ultimate status after prompts is okay to continue
|
||||
* This method prompts user based on testing status (i.e. failure to connect, invalid schema, db does not exist, etc.).
|
||||
* @param manager The manager to use when setting up the database.
|
||||
* @param dialog If non-null value, validates settings and updates 'okay' button enabled state.
|
||||
* @return Whether or not the ultimate status after prompts is okay to continue.
|
||||
*/
|
||||
@NbBundle.Messages({"EamDbSettingsDialog.okButton.corruptDatabaseExists.title=Error Loading Database",
|
||||
"EamDbSettingsDialog.okButton.corruptDatabaseExists.message=Database exists but is not the right format. Manually delete it or choose a different path (if applicable).",
|
||||
"EamDbSettingsDialog.okButton.createDbDialog.title=Database Does Not Exist",
|
||||
"EamDbSettingsDialog.okButton.createDbDialog.message=Database does not exist, would you like to create it?",
|
||||
"EamDbSettingsDialog.okButton.databaseConnectionFailed.title=Database Connection Failed",
|
||||
"EamDbSettingsDialog.okButton.databaseConnectionFailed.message=Unable to connect to database please check your settings and try again.",
|
||||
"EamDbSettingsDialog.okButton.databaseConnectionFailed.message=Unable to connect to database. Please check your settings and try again.",
|
||||
"EamDbSettingsDialog.okButton.createSQLiteDbError.message=Unable to create SQLite Database, please ensure location exists and you have write permissions and try again.",
|
||||
"EamDbSettingsDialog.okButton.createPostgresDbError.message=Unable to create Postgres Database, please ensure address, port, and login credentials are correct for Postgres server and try again.",
|
||||
"EamDbSettingsDialog.okButton.createDbError.title=Unable to Create Database"})
|
||||
private boolean promptTestStatusWarnings() {
|
||||
private static boolean promptTestStatusWarnings(CentralRepoDbManager manager, EamDbSettingsDialog dialog) {
|
||||
if (manager.getStatus() == DatabaseTestResult.CONNECTION_FAILED) {
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
Bundle.EamDbSettingsDialog_okButton_databaseConnectionFailed_message(),
|
||||
@ -135,37 +186,50 @@ public class EamDbSettingsDialog extends JDialog {
|
||||
Bundle.EamDbSettingsDialog_okButton_createDbDialog_message(),
|
||||
Bundle.EamDbSettingsDialog_okButton_createDbDialog_title(),
|
||||
JOptionPane.YES_NO_OPTION)) {
|
||||
try {
|
||||
manager.createDb();
|
||||
onUserPromptCreateDb(manager, dialog);
|
||||
}
|
||||
catch (CentralRepoException e) {
|
||||
// in the event that there is a failure to connect, notify user with corresponding message
|
||||
String errorMessage;
|
||||
switch (manager.getSelectedPlatform()) {
|
||||
case POSTGRESQL:
|
||||
errorMessage = Bundle.EamDbSettingsDialog_okButton_createPostgresDbError_message();
|
||||
break;
|
||||
case SQLITE:
|
||||
errorMessage = Bundle.EamDbSettingsDialog_okButton_createSQLiteDbError_message();
|
||||
break;
|
||||
default:
|
||||
errorMessage = "";
|
||||
break;
|
||||
}
|
||||
|
||||
return (manager.getStatus() == DatabaseTestResult.TESTED_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a new database needs to be created on user selecting cr, this code will be ran when user selects create cr.
|
||||
* @param manager The manager handling the database creation.
|
||||
* @param dialog The dialog that prompted database creation.
|
||||
*/
|
||||
private static void onUserPromptCreateDb(CentralRepoDbManager manager, EamDbSettingsDialog dialog) {
|
||||
try {
|
||||
manager.createDb();
|
||||
} catch (CentralRepoException e) {
|
||||
onPromptStatusError(manager);
|
||||
}
|
||||
if (dialog != null)
|
||||
dialog.valid();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When an error occurs while going through promptTestStatusWarning, this method is called.
|
||||
* @param manager1 The manager to use as service class.
|
||||
* @throws HeadlessException
|
||||
*/
|
||||
private static void onPromptStatusError(CentralRepoDbManager manager1) {
|
||||
// in the event that there is a failure to connect, notify user with corresponding message
|
||||
String errorMessage = "";
|
||||
if (manager1 == null || manager1.getSelectedDbChoice() == null) {
|
||||
errorMessage = "";
|
||||
} else if (manager1.getSelectedDbChoice().getDbPlatform() == CentralRepoPlatforms.POSTGRESQL) {
|
||||
errorMessage = Bundle.EamDbSettingsDialog_okButton_createPostgresDbError_message();
|
||||
} else if (manager1.getSelectedDbChoice().getDbPlatform() == CentralRepoPlatforms.SQLITE) {
|
||||
errorMessage = Bundle.EamDbSettingsDialog_okButton_createSQLiteDbError_message();
|
||||
}
|
||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||
errorMessage,
|
||||
Bundle.EamDbSettingsDialog_okButton_createDbError_title(),
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
}
|
||||
|
||||
valid();
|
||||
}
|
||||
}
|
||||
|
||||
return (manager.getStatus() == DatabaseTestResult.TESTEDOK);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
@ -281,7 +345,7 @@ public class EamDbSettingsDialog extends JDialog {
|
||||
|
||||
jpDbPassword.setPreferredSize(new java.awt.Dimension(509, 20));
|
||||
|
||||
cbDatabaseType.setModel(new javax.swing.DefaultComboBoxModel<>(new CentralRepoPlatforms[]{CentralRepoPlatforms.POSTGRESQL, CentralRepoPlatforms.SQLITE}));
|
||||
cbDatabaseType.setModel(new javax.swing.DefaultComboBoxModel<>(org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbChoice.DB_CHOICES));
|
||||
cbDatabaseType.setPreferredSize(new java.awt.Dimension(120, 20));
|
||||
cbDatabaseType.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
@ -323,18 +387,18 @@ public class EamDbSettingsDialog extends JDialog {
|
||||
.addComponent(lbUserName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(lbPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
|
||||
.addComponent(lbDatabaseDesc, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(lbDatabaseDesc, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 94, Short.MAX_VALUE)
|
||||
.addComponent(lbUserPassword, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
|
||||
.addGap(10, 10, 10)
|
||||
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addGroup(pnSQLiteSettingsLayout.createSequentialGroup()
|
||||
.addComponent(tfDatabasePath, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(bnDatabasePathFileOpen))
|
||||
.addGroup(pnSQLiteSettingsLayout.createSequentialGroup()
|
||||
.addComponent(cbDatabaseType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(lbSingleUserSqLite, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addComponent(cbDatabaseType, javax.swing.GroupLayout.PREFERRED_SIZE, 210, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(lbSingleUserSqLite, javax.swing.GroupLayout.PREFERRED_SIZE, 1, Short.MAX_VALUE))
|
||||
.addComponent(jpDbPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(tbDbUsername, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(tbDbPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
@ -414,15 +478,20 @@ public class EamDbSettingsDialog extends JDialog {
|
||||
setTextPrompts();
|
||||
setTextBoxListeners();
|
||||
manager.clearStatus();
|
||||
if (manager.getSelectedPlatform() == CentralRepoPlatforms.SQLITE) {
|
||||
if (manager.getSelectedDbChoice() == CentralRepoDbChoice.SQLITE) {
|
||||
updatePostgresFields(false);
|
||||
updateSqliteFields(true);
|
||||
}
|
||||
else {
|
||||
else if (manager.getSelectedDbChoice() == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
|
||||
updatePostgresFields(true);
|
||||
updateSqliteFields(false);
|
||||
}
|
||||
displayDatabaseSettings(CentralRepoPlatforms.POSTGRESQL.equals(manager.getSelectedPlatform()));
|
||||
else {
|
||||
updatePostgresFields(false);
|
||||
updateSqliteFields(false);
|
||||
}
|
||||
|
||||
displayDatabaseSettings(manager.getSelectedDbChoice());
|
||||
}
|
||||
|
||||
private void display() {
|
||||
@ -452,14 +521,40 @@ public class EamDbSettingsDialog extends JDialog {
|
||||
"EamDbSettingsDialog.okButton.errorMsg.text=Please restart Autopsy to begin using the new database platform.",
|
||||
"EamDbSettingsDialog.okButton.connectionErrorMsg.text=Failed to connect to central repository database."})
|
||||
private void bnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOkActionPerformed
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
manager.testStatus();
|
||||
valid();
|
||||
testStatusAndCreate(this, manager, this);
|
||||
dispose();
|
||||
}//GEN-LAST:event_bnOkActionPerformed
|
||||
|
||||
boolean testedOk = promptTestStatusWarnings();
|
||||
|
||||
/**
|
||||
* This method tests status for central repo db / creation and prompts user accordingly.
|
||||
* @param parent The parent component (the anchor for displaying dialogs).
|
||||
* @param manager The central repo db manager with settings to be tested and saved.
|
||||
* @return Whether or not central repo db was successfully be created or found.
|
||||
*/
|
||||
public static boolean testStatusAndCreate(Component parent, CentralRepoDbManager manager) {
|
||||
return testStatusAndCreate(parent, manager, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method tests status for central repo db / creation and prompts user accordingly.
|
||||
* @param parent The parent component (the anchor for displaying dialogs).
|
||||
* @param manager The central repo db manager with settings to be tested and saved.
|
||||
* @param dialog The db settings dialog; if non-null, will validate okay button state.
|
||||
* @return Whether or not central repo db was successfully be created or found.
|
||||
*/
|
||||
private static boolean testStatusAndCreate(Component parent, CentralRepoDbManager manager, EamDbSettingsDialog dialog) {
|
||||
parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
manager.testStatus();
|
||||
|
||||
if (dialog != null)
|
||||
dialog.valid();
|
||||
|
||||
boolean testedOk = promptTestStatusWarnings(manager, dialog);
|
||||
if (!testedOk) {
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
return;
|
||||
parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
return false;
|
||||
}
|
||||
|
||||
try{
|
||||
@ -467,25 +562,26 @@ public class EamDbSettingsDialog extends JDialog {
|
||||
}
|
||||
catch (CentralRepoException e) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
JOptionPane.showMessageDialog(this,
|
||||
JOptionPane.showMessageDialog(parent,
|
||||
Bundle.EamDbSettingsDialog_okButton_errorMsg_text(),
|
||||
Bundle.EamDbSettingsDialog_okButton_errorTitle_text(),
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
});
|
||||
|
||||
parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
dispose();
|
||||
}//GEN-LAST:event_bnOkActionPerformed
|
||||
|
||||
parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if changes to the central repository configuration were
|
||||
* successfully applied
|
||||
* This method returns if changes to the central repository configuration were
|
||||
* successfully applied.
|
||||
*
|
||||
* @return true if the database configuration was successfully changed false
|
||||
* if it was not
|
||||
* @return True if the database configuration was successfully changed; false
|
||||
* if it was not.
|
||||
*/
|
||||
public boolean wasConfigurationChanged() {
|
||||
return manager.wasConfigurationChanged();
|
||||
@ -497,22 +593,38 @@ public class EamDbSettingsDialog extends JDialog {
|
||||
|
||||
|
||||
private void cbDatabaseTypeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbDatabaseTypeActionPerformed
|
||||
manager.setSelectedPlatform((CentralRepoPlatforms) cbDatabaseType.getSelectedItem());
|
||||
customizeComponents();
|
||||
CentralRepoDbChoice selectedItem = (CentralRepoDbChoice) cbDatabaseType.getSelectedItem();
|
||||
changeDbSelection(selectedItem);
|
||||
}//GEN-LAST:event_cbDatabaseTypeActionPerformed
|
||||
|
||||
private void changeDbSelection(CentralRepoDbChoice selectedItem) {
|
||||
if (isDbChoiceSelectable(selectedItem)) {
|
||||
manager.setSelctedDbChoice(selectedItem);
|
||||
cbDatabaseType.setSelectedItem(selectedItem);
|
||||
}
|
||||
else {
|
||||
cbDatabaseType.setSelectedItem(manager.getSelectedDbChoice());
|
||||
}
|
||||
|
||||
customizeComponents();
|
||||
}
|
||||
|
||||
private void updateFullDbPath() {
|
||||
dataBaseFileTextArea.setText(tfDatabasePath.getText() + File.separator + SqliteCentralRepoSettings.DEFAULT_DBNAME);
|
||||
dataBaseFileTextArea.setCaretPosition(dataBaseFileTextArea.getText().length());
|
||||
}
|
||||
|
||||
private void displayDatabaseSettings(boolean isPostgres) {
|
||||
lbDatabasePath.setVisible(!isPostgres);
|
||||
tfDatabasePath.setVisible(!isPostgres);
|
||||
lbDatabaseDesc.setVisible(!isPostgres);
|
||||
dataBaseFileTextArea.setVisible(!isPostgres);
|
||||
lbSingleUserSqLite.setVisible(!isPostgres);
|
||||
bnDatabasePathFileOpen.setVisible(!isPostgres);
|
||||
private void displayDatabaseSettings(CentralRepoDbChoice choice) {
|
||||
boolean isSqlite = choice == CentralRepoDbChoice.SQLITE;
|
||||
boolean isPostgres = choice == CentralRepoDbChoice.POSTGRESQL_CUSTOM;
|
||||
|
||||
lbDatabasePath.setVisible(isSqlite);
|
||||
tfDatabasePath.setVisible(isSqlite);
|
||||
lbDatabaseDesc.setVisible(isSqlite);
|
||||
dataBaseFileTextArea.setVisible(isSqlite);
|
||||
lbSingleUserSqLite.setVisible(isSqlite);
|
||||
bnDatabasePathFileOpen.setVisible(isSqlite);
|
||||
|
||||
lbHostName.setVisible(isPostgres);
|
||||
tbDbHostname.setVisible(isPostgres);
|
||||
lbPort.setVisible(isPostgres);
|
||||
@ -610,14 +722,14 @@ public class EamDbSettingsDialog extends JDialog {
|
||||
@Messages({"EamDbSettingsDialog.validation.incompleteFields=Fill in all values for the selected database."})
|
||||
private boolean databaseFieldsArePopulated() {
|
||||
boolean result = true;
|
||||
if (manager.getSelectedPlatform() == CentralRepoPlatforms.POSTGRESQL) {
|
||||
if (manager.getSelectedDbChoice() == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
|
||||
result = !tbDbHostname.getText().trim().isEmpty()
|
||||
&& !tbDbPort.getText().trim().isEmpty()
|
||||
// && !tbDbName.getText().trim().isEmpty()
|
||||
&& !tbDbUsername.getText().trim().isEmpty()
|
||||
&& 0 < jpDbPassword.getPassword().length;
|
||||
}
|
||||
else if (manager.getSelectedPlatform() == CentralRepoPlatforms.SQLITE) {
|
||||
else if (manager.getSelectedDbChoice() == CentralRepoDbChoice.SQLITE) {
|
||||
result = !tfDatabasePath.getText().trim().isEmpty();
|
||||
}
|
||||
|
||||
@ -722,7 +834,7 @@ public class EamDbSettingsDialog extends JDialog {
|
||||
private javax.swing.JButton bnDatabasePathFileOpen;
|
||||
private javax.swing.ButtonGroup bnGrpDatabasePlatforms;
|
||||
private javax.swing.JButton bnOk;
|
||||
private javax.swing.JComboBox<CentralRepoPlatforms> cbDatabaseType;
|
||||
private javax.swing.JComboBox<org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbChoice> cbDatabaseType;
|
||||
private javax.swing.JScrollPane dataBaseFileScrollPane;
|
||||
private javax.swing.JTextArea dataBaseFileTextArea;
|
||||
private javax.swing.JFileChooser fcDatabasePath;
|
||||
|
@ -61,7 +61,7 @@
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="pnDatabaseConfiguration" alignment="0" max="32767" attributes="0"/>
|
||||
<Component id="pnCorrelationProperties" alignment="0" pref="1012" max="32767" attributes="0"/>
|
||||
<Component id="pnCorrelationProperties" alignment="0" pref="1016" max="32767" attributes="0"/>
|
||||
<Component id="organizationPanel" alignment="1" max="32767" attributes="0"/>
|
||||
<Component id="casesPanel" alignment="0" max="32767" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
@ -258,7 +258,7 @@
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Component id="correlationPropertiesScrollPane" pref="32" max="32767" attributes="0"/>
|
||||
<Component id="correlationPropertiesScrollPane" pref="25" max="32767" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="bnManageTypes" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
|
||||
|
@ -33,15 +33,17 @@ import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbManager;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms;
|
||||
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
|
||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms;
|
||||
import static org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms.DISABLED;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbChoice;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.PostgresCentralRepoSettings;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteCentralRepoSettings;
|
||||
import java.awt.Component;
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* Main settings panel for the Central Repository
|
||||
@ -54,12 +56,16 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.STARTED, IngestManager.IngestJobEvent.CANCELLED, IngestManager.IngestJobEvent.COMPLETED);
|
||||
private final IngestJobEventPropertyChangeListener ingestJobEventListener;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates new form EamOptionsPanel
|
||||
*/
|
||||
public GlobalSettingsPanel() {
|
||||
ingestJobEventListener = new IngestJobEventPropertyChangeListener();
|
||||
|
||||
// listen for change events in currently saved choice
|
||||
CentralRepoDbManager.addPropertyChangeListener((PropertyChangeEvent evt) -> ingestStateUpdated(Case.isCaseOpen()));
|
||||
initComponents();
|
||||
customizeComponents();
|
||||
addIngestJobEventsListener();
|
||||
@ -69,6 +75,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void customizeComponents() {
|
||||
setName(NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.pnCorrelationProperties.border.title"));
|
||||
}
|
||||
@ -78,26 +85,163 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
ingestStateUpdated(Case.isCaseOpen());
|
||||
}
|
||||
|
||||
@Messages({"GlobalSettingsPanel.updateFailed.title=Central repository disabled"})
|
||||
private void updateDatabase() {
|
||||
updateDatabase(this);
|
||||
}
|
||||
|
||||
if (CentralRepoPlatforms.getSelectedPlatform().equals(DISABLED)) {
|
||||
/**
|
||||
* This method invokes central repository database choice selection as well as input for necessary configuration.
|
||||
* @param parent The parent component for displaying dialogs.
|
||||
* @param initialSelection If non-null, the menu item will be set to this choice; if null,
|
||||
* the currently selected db choice will be selected.
|
||||
* @return True if there was a change.
|
||||
*/
|
||||
private static boolean invokeCrChoice(Component parent, CentralRepoDbChoice initialSelection) {
|
||||
EamDbSettingsDialog dialog = (initialSelection != null) ?
|
||||
new EamDbSettingsDialog(initialSelection) :
|
||||
new EamDbSettingsDialog();
|
||||
|
||||
if (dialog.wasConfigurationChanged()) {
|
||||
updateDatabase(parent);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When multi user settings are updated, this function triggers pertinent updates for central repository.
|
||||
* NOTE: If multi user settings were previously enabled and multi user settings are currently selected, this function assumes
|
||||
* there is a change in the postgres connectivity.
|
||||
*
|
||||
* @param parent The swing component that serves as a parent for dialogs that may arise.
|
||||
* @param muPreviouslySelected If multi user settings were previously enabled.
|
||||
* @param muCurrentlySelected If multi user settings are currently enabled as of most recent change.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"GlobalSettingsPanel.onMultiUserChange.enable.title=Use with Central Repository?",
|
||||
"GlobalSettingsPanel.onMultiUserChange.enable.description=Do you want to update the Central Repository to use this PostgreSQL database?",
|
||||
"GlobalSettingsPanel.onMultiUserChange.enable.description2=The Central Repository stores hash values and accounts from past cases."
|
||||
})
|
||||
public static void onMultiUserChange(Component parent, boolean muPreviouslySelected, boolean muCurrentlySelected) {
|
||||
boolean crEnabled = CentralRepoDbUtil.allowUseOfCentralRepository();
|
||||
boolean crMultiUser = CentralRepoDbManager.getSavedDbChoice() == CentralRepoDbChoice.POSTGRESQL_MULTIUSER;
|
||||
boolean crDisabledDueToFailure = CentralRepoDbManager.isDisabledDueToFailure();
|
||||
|
||||
if (!muPreviouslySelected && muCurrentlySelected) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(parent,
|
||||
"<html><body>" +
|
||||
"<div style='width: 400px;'>" +
|
||||
"<p>" + NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.enable.description") + "</p>" +
|
||||
"<p style='margin-top: 10px'>" + NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.enable.description2") + "</p>" +
|
||||
"</div>" +
|
||||
"</body></html>",
|
||||
NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.enable.title"),
|
||||
JOptionPane.YES_NO_OPTION)) {
|
||||
|
||||
// setup database for CR
|
||||
CentralRepoDbUtil.setUseCentralRepo(true);
|
||||
CentralRepoDbManager.saveDbChoice(CentralRepoDbChoice.POSTGRESQL_MULTIUSER);
|
||||
handleDbChange(parent);
|
||||
}
|
||||
});
|
||||
}
|
||||
// moving from selected to not selected && 'PostgreSQL using multi-user settings' is selected
|
||||
else if (muPreviouslySelected && !muCurrentlySelected && crEnabled && crMultiUser) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
askForCentralRepoDbChoice(parent);
|
||||
});
|
||||
}
|
||||
// changing multi-user settings connection && 'PostgreSQL using multi-user settings' is selected &&
|
||||
// central repo either enabled or was disabled due to error
|
||||
else if (muPreviouslySelected && muCurrentlySelected && crMultiUser && (crEnabled || crDisabledDueToFailure)) {
|
||||
// test databse for CR change
|
||||
CentralRepoDbUtil.setUseCentralRepo(true);
|
||||
handleDbChange(parent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is called when a user must select a new database other than using database from multi user settings.
|
||||
* @param parent The parent component to use for displaying dialogs in reference.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"GlobalSettingsPanel.onMultiUserChange.disabledMu.title=Central Repository Change Necessary",
|
||||
"GlobalSettingsPanel.onMultiUserChange.disabledMu.description=The Central Repository will be reconfigured to use a local SQLite database.",
|
||||
"GlobalSettingsPanel.onMultiUserChange.disabledMu.description2=Press Configure PostgreSQL to change to a PostgreSQL database."
|
||||
})
|
||||
private static void askForCentralRepoDbChoice(Component parent) {
|
||||
// disable central repository until user makes choice
|
||||
CentralRepoDbUtil.setUseCentralRepo(false);
|
||||
CentralRepoDbManager.saveDbChoice(CentralRepoDbChoice.DISABLED, false);
|
||||
|
||||
Object[] options = {
|
||||
"Use SQLite",
|
||||
"Configure PostgreSQL",
|
||||
"Disable Central Repository"
|
||||
};
|
||||
|
||||
int result = JOptionPane.showOptionDialog(
|
||||
parent,
|
||||
"<html><body>" +
|
||||
"<div style='width: 400px;'>" +
|
||||
"<p>" + NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.disabledMu.description") + "</p>" +
|
||||
"<p style='margin-top: 10px'>" + NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.disabledMu.description2") + "</p>" +
|
||||
"</div>" +
|
||||
"</body></html>",
|
||||
NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.onMultiUserChange.disabledMu.title"),
|
||||
JOptionPane.YES_NO_CANCEL_OPTION,
|
||||
JOptionPane.PLAIN_MESSAGE,
|
||||
null,
|
||||
options,
|
||||
options[0]
|
||||
);
|
||||
|
||||
if (JOptionPane.YES_OPTION == result) {
|
||||
invokeCrChoice(parent, CentralRepoDbChoice.SQLITE);
|
||||
}
|
||||
else if (JOptionPane.NO_OPTION == result) {
|
||||
invokeCrChoice(parent, CentralRepoDbChoice.POSTGRESQL_CUSTOM);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void handleDbChange(Component parent) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
boolean successful = EamDbSettingsDialog.testStatusAndCreate(parent, new CentralRepoDbManager());
|
||||
if (successful) {
|
||||
updateDatabase(parent);
|
||||
}
|
||||
else {
|
||||
// disable central repository due to error
|
||||
CentralRepoDbManager.disableDueToFailure();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Messages({"GlobalSettingsPanel.updateFailed.title=Central repository disabled"})
|
||||
private static void updateDatabase(Component parent) {
|
||||
if (CentralRepoDbChoice.DISABLED.equals(CentralRepoDbManager.getSavedDbChoice())) {
|
||||
return;
|
||||
}
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
|
||||
try {
|
||||
CentralRepoDbManager.upgradeDatabase();
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
} catch (CentralRepoException ex) {
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
JOptionPane.showMessageDialog(this,
|
||||
parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
JOptionPane.showMessageDialog(parent,
|
||||
ex.getUserMessage(),
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
NbBundle.getMessage(GlobalSettingsPanel.class,
|
||||
"GlobalSettingsPanel.updateFailed.title"),
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
} finally {
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
}
|
||||
}
|
||||
|
||||
@ -425,9 +569,8 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
|
||||
private void bnDbConfigureActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnDbConfigureActionPerformed
|
||||
store();
|
||||
EamDbSettingsDialog dialog = new EamDbSettingsDialog();
|
||||
if (dialog.wasConfigurationChanged()) {
|
||||
updateDatabase();
|
||||
boolean changed = invokeCrChoice(this, null);
|
||||
if (changed) {
|
||||
load(); // reload db settings content and update buttons
|
||||
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||
}
|
||||
@ -446,6 +589,16 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
private void cbUseCentralRepoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbUseCentralRepoActionPerformed
|
||||
//if saved setting is disabled checkbox should be disabled already
|
||||
store();
|
||||
|
||||
// if moving to using CR, multi-user mode is disabled and selection is multiuser settings, set to disabled
|
||||
if (cbUseCentralRepo.isSelected() &&
|
||||
!CentralRepoDbManager.isPostgresMultiuserAllowed() &&
|
||||
CentralRepoDbManager.getSavedDbChoice() == CentralRepoDbChoice.POSTGRESQL_MULTIUSER) {
|
||||
|
||||
CentralRepoDbManager.saveDbChoice(CentralRepoDbChoice.DISABLED);
|
||||
}
|
||||
|
||||
|
||||
updateDatabase();
|
||||
load();
|
||||
this.ingestStateUpdated(Case.isCaseOpen());
|
||||
@ -457,31 +610,35 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
public void load() {
|
||||
tbOops.setText("");
|
||||
enableButtonSubComponents(false);
|
||||
CentralRepoPlatforms selectedPlatform = CentralRepoPlatforms.getSelectedPlatform();
|
||||
CentralRepoDbChoice selectedChoice = CentralRepoDbManager.getSavedDbChoice();
|
||||
cbUseCentralRepo.setSelected(CentralRepoDbUtil.allowUseOfCentralRepository()); // NON-NLS
|
||||
switch (selectedPlatform) {
|
||||
case POSTGRESQL:
|
||||
PostgresCentralRepoSettings dbSettingsPg = new PostgresCentralRepoSettings();
|
||||
lbDbPlatformValue.setText(CentralRepoPlatforms.POSTGRESQL.toString());
|
||||
lbDbNameValue.setText(dbSettingsPg.getDbName());
|
||||
lbDbLocationValue.setText(dbSettingsPg.getHost());
|
||||
enableButtonSubComponents(cbUseCentralRepo.isSelected());
|
||||
break;
|
||||
case SQLITE:
|
||||
SqliteCentralRepoSettings dbSettingsSqlite = new SqliteCentralRepoSettings();
|
||||
lbDbPlatformValue.setText(CentralRepoPlatforms.SQLITE.toString());
|
||||
lbDbNameValue.setText(dbSettingsSqlite.getDbName());
|
||||
lbDbLocationValue.setText(dbSettingsSqlite.getDbDirectory());
|
||||
enableButtonSubComponents(cbUseCentralRepo.isSelected());
|
||||
break;
|
||||
default:
|
||||
lbDbPlatformValue.setText(CentralRepoPlatforms.DISABLED.toString());
|
||||
|
||||
lbDbPlatformValue.setText(selectedChoice.getTitle());
|
||||
CentralRepoPlatforms selectedDb = selectedChoice.getDbPlatform();
|
||||
|
||||
if (selectedChoice == null || selectedDb == CentralRepoPlatforms.DISABLED) {
|
||||
lbDbNameValue.setText("");
|
||||
lbDbLocationValue.setText("");
|
||||
tbOops.setText(Bundle.GlobalSettingsPanel_validationerrMsg_mustConfigure());
|
||||
break;
|
||||
}
|
||||
|
||||
else {
|
||||
enableButtonSubComponents(cbUseCentralRepo.isSelected());
|
||||
if (selectedDb == CentralRepoPlatforms.POSTGRESQL) {
|
||||
try {
|
||||
PostgresCentralRepoSettings dbSettingsPg = new PostgresCentralRepoSettings();
|
||||
lbDbNameValue.setText(dbSettingsPg.getDbName());
|
||||
lbDbLocationValue.setText(dbSettingsPg.getHost());
|
||||
}
|
||||
catch (CentralRepoException e) {
|
||||
logger.log(Level.WARNING, "Unable to load settings into global panel for postgres settings", e);
|
||||
}
|
||||
}
|
||||
else if (selectedDb == CentralRepoPlatforms.SQLITE) {
|
||||
SqliteCentralRepoSettings dbSettingsSqlite = new SqliteCentralRepoSettings();
|
||||
lbDbNameValue.setText(dbSettingsSqlite.getDbName());
|
||||
lbDbLocationValue.setText(dbSettingsSqlite.getDbDirectory());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -490,12 +647,12 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that the dialog/panel is filled out correctly for our usage.
|
||||
* This method validates that the dialog/panel is filled out correctly for our usage.
|
||||
*
|
||||
* @return true if it's okay, false otherwise.
|
||||
* @return True if it is okay, false otherwise.
|
||||
*/
|
||||
public boolean valid() {
|
||||
return !cbUseCentralRepo.isSelected() || !lbDbPlatformValue.getText().equals(DISABLED.toString());
|
||||
return !cbUseCentralRepo.isSelected() || !lbDbPlatformValue.getText().equals(CentralRepoDbChoice.DISABLED.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -574,9 +731,9 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
||||
enableButtonSubComponents(cbUseCentralRepo.isSelected());
|
||||
} else {
|
||||
load();
|
||||
enableDatabaseConfigureButton(cbUseCentralRepo.isSelected() && !caseIsOpen);
|
||||
}
|
||||
|
||||
enableDatabaseConfigureButton(cbUseCentralRepo.isSelected() && !caseIsOpen);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -343,6 +343,7 @@ public class CommandLineIngestManager {
|
||||
* @param baseCaseName Case name
|
||||
* @param rootOutputDirectory Full path to directory in which case
|
||||
* output folder will be created
|
||||
* @param caseType Type of case being created
|
||||
*
|
||||
* @throws CaseActionException
|
||||
*/
|
||||
|
@ -19,6 +19,7 @@
|
||||
package org.sleuthkit.autopsy.communications.relationships;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.sleuthkit.autopsy.communications.Utils;
|
||||
import static org.sleuthkit.autopsy.communications.relationships.RelationshipsNodeUtilities.getAttributeDisplayString;
|
||||
@ -67,14 +68,6 @@ final class CallLogNode extends BlackboardArtifactNode {
|
||||
return sheet;
|
||||
}
|
||||
|
||||
String phoneNumber = getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM);
|
||||
if(phoneNumber == null || phoneNumber.isEmpty()) {
|
||||
phoneNumber = getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO);
|
||||
}
|
||||
if(phoneNumber == null || phoneNumber.isEmpty()) {
|
||||
phoneNumber = getAttributeDisplayString(artifact, TSK_PHONE_NUMBER);
|
||||
}
|
||||
|
||||
long duration = -1;
|
||||
try{
|
||||
duration = getCallDuration(artifact);
|
||||
@ -84,7 +77,7 @@ final class CallLogNode extends BlackboardArtifactNode {
|
||||
|
||||
sheetSet.put(createNode(TSK_DATETIME_START, artifact));
|
||||
sheetSet.put(createNode(TSK_DIRECTION, artifact));
|
||||
sheetSet.put(new NodeProperty<>(TSK_PHONE_NUMBER.getLabel(), TSK_PHONE_NUMBER.getDisplayName(), "", phoneNumber));
|
||||
sheetSet.put(new NodeProperty<>(TSK_PHONE_NUMBER.getLabel(), TSK_PHONE_NUMBER.getDisplayName(), "", getPhoneNumber(artifact)));
|
||||
if(duration != -1) {
|
||||
sheetSet.put(new NodeProperty<>("duration", "Duration", "", Long.toString(duration)));
|
||||
}
|
||||
@ -107,6 +100,59 @@ final class CallLogNode extends BlackboardArtifactNode {
|
||||
return endAttribute.getValueLong() - startAttribute.getValueLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phone number to display in the To/From column. The number is
|
||||
* picked from one of the 3 possible phone number attributes, based on the
|
||||
* direction of the call.
|
||||
*
|
||||
* @param artifact Call log artifact.
|
||||
*
|
||||
* @return Phone number to display.
|
||||
*/
|
||||
private String getPhoneNumber(BlackboardArtifact artifact) {
|
||||
String direction = getAttributeDisplayString(artifact, TSK_DIRECTION);
|
||||
|
||||
String phoneNumberToReturn;
|
||||
String fromPhoneNumber = getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_FROM);
|
||||
String toPhoneNumber = getAttributeDisplayString(artifact, TSK_PHONE_NUMBER_TO);
|
||||
String phoneNumber = getAttributeDisplayString(artifact, TSK_PHONE_NUMBER);
|
||||
switch (direction.toLowerCase()) {
|
||||
case "incoming": // NON-NLS
|
||||
phoneNumberToReturn = getFirstNonBlank(fromPhoneNumber, phoneNumber, toPhoneNumber);
|
||||
break;
|
||||
case "outgoing": // NON-NLS
|
||||
phoneNumberToReturn = getFirstNonBlank(toPhoneNumber, phoneNumber, fromPhoneNumber);
|
||||
break;
|
||||
default:
|
||||
phoneNumberToReturn = getFirstNonBlank(toPhoneNumber, fromPhoneNumber, phoneNumber );
|
||||
break;
|
||||
}
|
||||
|
||||
return phoneNumberToReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given string arguments in order and returns the first non blank string.
|
||||
* Returns a blank string if all the input strings are blank.
|
||||
*
|
||||
* @param string1 First string to check
|
||||
* @param string2 Second string to check
|
||||
* @param string3 Third string to check
|
||||
*
|
||||
* @retunr first non blank string if there is one, blank string otherwise.
|
||||
*
|
||||
*/
|
||||
private String getFirstNonBlank(String string1, String string2, String string3 ) {
|
||||
|
||||
if (!StringUtils.isBlank(string1)) {
|
||||
return string1;
|
||||
} else if (!StringUtils.isBlank(string2)) {
|
||||
return string2;
|
||||
} else if (!StringUtils.isBlank(string3)) {
|
||||
return string3;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
/**
|
||||
* Circumvent DataResultFilterNode's slightly odd delegation to
|
||||
* BlackboardArtifactNode.getSourceName().
|
||||
|
@ -41,6 +41,7 @@ MediaFileViewer.AccessibleContext.accessibleDescription=
|
||||
MediaFileViewer.title=Media
|
||||
MediaFileViewer.toolTip=Displays supported multimedia files (images, videos, audio)
|
||||
MediaPlayerPanel.noSupport=File not supported.
|
||||
MediaPlayerPanel.playbackDisabled=A problem was encountered with the video and audio playback service. Video and audio playback will be disabled for the remainder of the session.
|
||||
MediaPlayerPanel.timeFormat=%02d:%02d:%02d
|
||||
MediaPlayerPanel.unknownTime=Unknown
|
||||
MediaViewImagePanel.createTagOption=Create
|
||||
@ -168,7 +169,7 @@ MediaPlayerPanel.playBackSpeedLabel.text=Speed:
|
||||
SQLiteViewer.readTable.errorText=Error getting rows for table: {0}
|
||||
# {0} - tableName
|
||||
SQLiteViewer.selectTable.errorText=Error getting row count for table: {0}
|
||||
TextTranslatableComponent.setPanelContent.onSetContentError=Unable to display text at this time.
|
||||
TextTranslatableComponent.setTranslated.onTranslateError=Unable to translate text at this time.
|
||||
TranslatablePanel.comboBoxOption.originalText=Original Text
|
||||
TranslatablePanel.comboBoxOption.translatedText=Translated Text
|
||||
# {0} - exception message
|
||||
TranslatablePanel.onSetContentError.text=There was an error displaying the text: {0}
|
||||
|
@ -194,6 +194,6 @@ class MediaFileViewer extends javax.swing.JPanel implements FileTypeViewer {
|
||||
|
||||
@Override
|
||||
public boolean isSupported(AbstractFile file){
|
||||
return true;
|
||||
return mediaPlayerPanel.isSupported(file) || imagePanel.isSupported(file);
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" max="-2" attributes="0">
|
||||
<Component id="progressLabel" max="32767" attributes="0"/>
|
||||
<Component id="playBackPanel" pref="0" max="32767" attributes="0"/>
|
||||
<Component id="playBackPanel" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
@ -129,12 +129,6 @@
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MediaPlayerPanel.playButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[53, 29]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[53, 29]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[49, 29]"/>
|
||||
</Property>
|
||||
|
@ -74,7 +74,9 @@ import org.freedesktop.gstreamer.Format;
|
||||
import org.freedesktop.gstreamer.GstException;
|
||||
import org.freedesktop.gstreamer.event.SeekFlags;
|
||||
import org.freedesktop.gstreamer.event.SeekType;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
import org.sleuthkit.autopsy.contentviewers.utils.GstLoader;
|
||||
import org.sleuthkit.autopsy.contentviewers.utils.GstLoader.GstStatus;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
|
||||
/**
|
||||
* This is a video player that is part of the Media View layered pane. It uses
|
||||
@ -213,6 +215,8 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
//and the TrackListener on the slider itself.
|
||||
private final Semaphore sliderLock;
|
||||
|
||||
private static volatile boolean IS_GST_ENABLED = true;
|
||||
|
||||
/**
|
||||
* Creates a new MediaPlayerPanel
|
||||
*/
|
||||
@ -222,18 +226,10 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
//True for fairness. In other words,
|
||||
//acquire() calls are processed in order of invocation.
|
||||
sliderLock = new Semaphore(1, true);
|
||||
|
||||
/**
|
||||
* See JIRA-5888 for details. Initializing gstreamer here is more stable
|
||||
* on Windows.
|
||||
*/
|
||||
if (PlatformUtil.isWindowsOS()) {
|
||||
Gst.init();
|
||||
}
|
||||
}
|
||||
|
||||
private void customizeComponents() {
|
||||
progressSlider.setEnabled(false); // disable slider; enable after user plays vid
|
||||
enableComponents(false);
|
||||
progressSlider.setMinimum(0);
|
||||
progressSlider.setMaximum(PROGRESS_SLIDER_SIZE);
|
||||
progressSlider.setValue(0);
|
||||
@ -241,7 +237,7 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
progressSlider.addChangeListener(new ChangeListener() {
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
if (progressSlider.getValueIsAdjusting()) {
|
||||
if (progressSlider.getValueIsAdjusting() && gstPlayBin != null) {
|
||||
long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
|
||||
double relativePosition = progressSlider.getValue() * 1.0 / PROGRESS_SLIDER_SIZE;
|
||||
long newStartTime = (long) (relativePosition * duration);
|
||||
@ -267,17 +263,20 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (gstPlayBin != null) {
|
||||
previousState = gstPlayBin.getState();
|
||||
gstPlayBin.pause();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
if(previousState.equals(State.PLAYING)) {
|
||||
if (previousState.equals(State.PLAYING) && gstPlayBin != null) {
|
||||
gstPlayBin.play();
|
||||
}
|
||||
previousState = State.NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
}
|
||||
@ -293,7 +292,7 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
});
|
||||
//Manage the audio level when the user is adjusting the volume slider
|
||||
audioSlider.addChangeListener((ChangeEvent event) -> {
|
||||
if (audioSlider.getValueIsAdjusting()) {
|
||||
if (audioSlider.getValueIsAdjusting() && gstPlayBin != null) {
|
||||
double audioPercent = (audioSlider.getValue() * 2.0) / 100.0;
|
||||
gstPlayBin.setVolume(audioPercent);
|
||||
}
|
||||
@ -327,12 +326,14 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
endOfStreamListener = new Bus.EOS() {
|
||||
@Override
|
||||
public void endOfStream(GstObject go) {
|
||||
if (gstPlayBin != null) {
|
||||
gstPlayBin.seek(ClockTime.ZERO);
|
||||
/**
|
||||
* Keep the video from automatically playing
|
||||
*/
|
||||
Gst.getExecutor().submit(() -> gstPlayBin.pause());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -385,13 +386,16 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
}
|
||||
timer.stop();
|
||||
if (gstPlayBin != null) {
|
||||
Gst.getExecutor().submit(() -> {
|
||||
gstPlayBin.stop();
|
||||
gstPlayBin.getBus().disconnect(endOfStreamListener);
|
||||
gstPlayBin.getBus().disconnect(stateChangeListener);
|
||||
gstPlayBin.getBus().disconnect(errorListener);
|
||||
gstPlayBin.getBus().dispose();
|
||||
gstPlayBin.dispose();
|
||||
fxAppSink.clear();
|
||||
gstPlayBin = null;
|
||||
});
|
||||
}
|
||||
videoPanel.removeAll();
|
||||
resetComponents();
|
||||
@ -420,6 +424,10 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
|
||||
@Override
|
||||
public boolean isSupported(AbstractFile file) {
|
||||
if (!IS_GST_ENABLED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String extension = file.getNameExtension();
|
||||
/**
|
||||
* Although it seems too restrictive, requiring both a supported
|
||||
@ -537,6 +545,11 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
/*
|
||||
* Initialize the playback components if the extraction was successful.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"MediaPlayerPanel.playbackDisabled=A problem was encountered with"
|
||||
+ " the video and audio playback service. Video and audio "
|
||||
+ "playback will be disabled for the remainder of the session."
|
||||
})
|
||||
@Override
|
||||
protected void done() {
|
||||
try {
|
||||
@ -546,13 +559,16 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize Gstreamer. It is safe to call this for every file.
|
||||
// It was moved here from the constructor because having it happen
|
||||
// earlier resulted in conflicts on Linux. See JIRA-5888.
|
||||
if (!PlatformUtil.isWindowsOS()) {
|
||||
Gst.init();
|
||||
GstStatus loadStatus = GstLoader.tryLoad();
|
||||
if (loadStatus == GstStatus.FAILURE) {
|
||||
MessageNotifyUtil.Message.error(Bundle.MediaPlayerPanel_playbackDisabled());
|
||||
|
||||
// This will disable the panel for future use.
|
||||
IS_GST_ENABLED = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Gst.getExecutor().submit(() -> {
|
||||
//Video is ready for playback. Create new components
|
||||
gstPlayBin = new PlayBin("VideoPlayer", tempFile.toURI());
|
||||
//Configure event handling
|
||||
@ -570,17 +586,22 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
videoPanel.setLayout(new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
|
||||
videoPanel.add(fxPanel);
|
||||
fxAppSink = new JavaFxAppSink("JavaFxAppSink", fxPanel);
|
||||
if (gstPlayBin != null) {
|
||||
gstPlayBin.setVideoSink(fxAppSink);
|
||||
|
||||
}
|
||||
if (this.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (gstPlayBin != null) {
|
||||
gstPlayBin.setVolume((audioSlider.getValue() * 2.0) / 100.0);
|
||||
gstPlayBin.pause();
|
||||
}
|
||||
|
||||
timer.start();
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
enableComponents(true);
|
||||
});
|
||||
});
|
||||
} catch (CancellationException ex) {
|
||||
logger.log(Level.INFO, "Media buffering was canceled."); //NON-NLS
|
||||
} catch (InterruptedException ex) {
|
||||
@ -598,14 +619,17 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (!progressSlider.getValueIsAdjusting()) {
|
||||
if (!progressSlider.getValueIsAdjusting() && gstPlayBin != null) {
|
||||
Gst.getExecutor().submit(() -> {
|
||||
try {
|
||||
sliderLock.acquireUninterruptibly();
|
||||
long position = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
||||
long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
|
||||
/**
|
||||
* Duration may not be known until there is video data in the
|
||||
* pipeline. We start this updater when data-flow has just been
|
||||
* initiated so buffering may still be in progress.
|
||||
* Duration may not be known until there is video data
|
||||
* in the pipeline. We start this updater when data-flow
|
||||
* has just been initiated so buffering may still be in
|
||||
* progress.
|
||||
*/
|
||||
if (duration >= 0 && position >= 0) {
|
||||
double relativePosition = (double) position / duration;
|
||||
@ -615,8 +639,11 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
updateTimeLabel(position, duration);
|
||||
});
|
||||
} finally {
|
||||
sliderLock.release();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -655,8 +682,8 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the View to be an oval rather than the underlying
|
||||
* rectangle Controller.
|
||||
* Modifies the View to be an oval rather than the underlying rectangle
|
||||
* Controller.
|
||||
*/
|
||||
@Override
|
||||
public void paintThumb(Graphics graphic) {
|
||||
@ -705,11 +732,12 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
@Override
|
||||
protected TrackListener createTrackListener(JSlider slider) {
|
||||
/**
|
||||
* This track listener will force the thumb to be snapped to the mouse
|
||||
* location. This makes grabbing and dragging the JSlider much easier.
|
||||
* Using the default track listener, the user would have to click
|
||||
* exactly on the slider thumb to drag it. Now the thumb positions
|
||||
* itself under the mouse so that it can always be dragged.
|
||||
* This track listener will force the thumb to be snapped to the
|
||||
* mouse location. This makes grabbing and dragging the JSlider much
|
||||
* easier. Using the default track listener, the user would have to
|
||||
* click exactly on the slider thumb to drag it. Now the thumb
|
||||
* positions itself under the mouse so that it can always be
|
||||
* dragged.
|
||||
*/
|
||||
return new TrackListener() {
|
||||
@Override
|
||||
@ -982,6 +1010,8 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void rewindButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rewindButtonActionPerformed
|
||||
Gst.getExecutor().submit(() -> {
|
||||
if (gstPlayBin != null) {
|
||||
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
||||
//Skip 30 seconds.
|
||||
long rewindDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
|
||||
@ -997,9 +1027,13 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
SeekType.SET, newTime,
|
||||
//Do nothing for the end position
|
||||
SeekType.NONE, -1);
|
||||
}
|
||||
});
|
||||
}//GEN-LAST:event_rewindButtonActionPerformed
|
||||
|
||||
private void fastForwardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fastForwardButtonActionPerformed
|
||||
private void fastForwardButtonActionPerformed(java.awt.event.ActionEvent evt) {
|
||||
Gst.getExecutor().submit(() -> {
|
||||
if (gstPlayBin != null) {
|
||||
long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
|
||||
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
||||
//Skip 30 seconds.
|
||||
@ -1029,9 +1063,13 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
SeekType.SET, newTime,
|
||||
//Do nothing for the end position
|
||||
SeekType.NONE, -1);
|
||||
}//GEN-LAST:event_fastForwardButtonActionPerformed
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void playButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_playButtonActionPerformed
|
||||
private void playButtonActionPerformed(java.awt.event.ActionEvent evt) {
|
||||
Gst.getExecutor().submit(() -> {
|
||||
if (gstPlayBin != null) {
|
||||
if (gstPlayBin.isPlaying()) {
|
||||
gstPlayBin.pause();
|
||||
} else {
|
||||
@ -1049,9 +1087,13 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
SeekType.NONE, -1);
|
||||
gstPlayBin.play();
|
||||
}
|
||||
}//GEN-LAST:event_playButtonActionPerformed
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void playBackSpeedComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_playBackSpeedComboBoxActionPerformed
|
||||
private void playBackSpeedComboBoxActionPerformed(java.awt.event.ActionEvent evt) {
|
||||
Gst.getExecutor().submit(() -> {
|
||||
if (gstPlayBin != null) {
|
||||
double playBackRate = getPlayBackRate();
|
||||
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
||||
gstPlayBin.seek(playBackRate,
|
||||
@ -1063,7 +1105,9 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
||||
//playback rate.
|
||||
SeekType.SET, currentTime,
|
||||
SeekType.NONE, 0);
|
||||
}//GEN-LAST:event_playBackSpeedComboBoxActionPerformed
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JLabel VolumeIcon;
|
||||
|
@ -1,8 +1,9 @@
|
||||
ContextViewer.jSourceGoToResultButton.text=Go to Result
|
||||
ContextViewer.jSourceTextLabel.text=jLabel2
|
||||
ContextViewer.jSourceNameLabel.text=jSourceNameLabel
|
||||
ContextViewer.jSourceLabel.text=Source
|
||||
ContextViewer.jUsageGoToResultButton.text=Go to Result
|
||||
ContextViewer.jUsageLabel.text=Usage
|
||||
ContextViewer.jUsageNameLabel.text=jSourceNameLabel
|
||||
ContextViewer.jUsageTextLabel.text=jLabel2
|
||||
ContextUsagePanel.jUsageGoToResultButton.text=Go to Result
|
||||
ContextSourcePanel.jSourceGoToResultButton.text=Go to Result
|
||||
ContextUsagePanel.jUsageTextLabel.text=Label2
|
||||
ContextUsagePanel.jUsageNameLabel.text=jUsageLabel
|
||||
ContextSourcePanel.jSourceTextLabel.text=Label2
|
||||
ContextSourcePanel.jSourceNameLabel.text=jSourceNameLabel
|
||||
ContextViewer.jSourceLabel.text=Usage
|
||||
ContextViewer.jUsageLabel.text=Source
|
||||
ContextViewer.jUnknownLabel.text=Unknown
|
||||
|
@ -1,16 +1,17 @@
|
||||
ContextUsagePanel.jUsageGoToResultButton.text=Go to Result
|
||||
ContextSourcePanel.jSourceGoToResultButton.text=Go to Result
|
||||
ContextUsagePanel.jUsageTextLabel.text=Label2
|
||||
ContextUsagePanel.jUsageNameLabel.text=jUsageLabel
|
||||
ContextSourcePanel.jSourceTextLabel.text=Label2
|
||||
ContextSourcePanel.jSourceNameLabel.text=jSourceNameLabel
|
||||
ContextViewer.attachmentSource=Attached to:
|
||||
ContextViewer.downloadedOn=On
|
||||
ContextViewer.downloadSource=Downloaded from:
|
||||
ContextViewer.downloadURL=URL
|
||||
ContextViewer.email=Email
|
||||
ContextViewer.jSourceGoToResultButton.text=Go to Result
|
||||
ContextViewer.jSourceTextLabel.text=jLabel2
|
||||
ContextViewer.jSourceNameLabel.text=jSourceNameLabel
|
||||
ContextViewer.jSourceLabel.text=Source
|
||||
ContextViewer.jUsageGoToResultButton.text=Go to Result
|
||||
ContextViewer.jUsageLabel.text=Usage
|
||||
ContextViewer.jUsageNameLabel.text=jSourceNameLabel
|
||||
ContextViewer.jUsageTextLabel.text=jLabel2
|
||||
ContextViewer.jSourceLabel.text=Usage
|
||||
ContextViewer.jUsageLabel.text=Source
|
||||
ContextViewer.jUnknownLabel.text=Unknown
|
||||
ContextViewer.message=Message
|
||||
ContextViewer.messageFrom=From
|
||||
ContextViewer.messageOn=On
|
||||
@ -20,3 +21,4 @@ ContextViewer.recentDocs=Recent Documents:
|
||||
ContextViewer.title=Context
|
||||
ContextViewer.toolTip=Displays context for selected file.
|
||||
ContextViewer.unknown=Opened at unknown time
|
||||
ContextViewer.unknownSource=Unknown
|
||||
|
@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<Properties>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="ff" green="ff" red="ff" type="rgb"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[495, 75]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<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="50" max="-2" attributes="0"/>
|
||||
<Component id="jSourceNameLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="36" max="-2" attributes="0"/>
|
||||
<Component id="jSourceTextLabel" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="260" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="90" max="-2" attributes="0"/>
|
||||
<Component id="jSourceGoToResultButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="jSourceNameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jSourceTextLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jSourceGoToResultButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JButton" name="jSourceGoToResultButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextSourcePanel.jSourceGoToResultButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jSourceGoToResultButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jSourceNameLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextSourcePanel.jSourceNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jSourceTextLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextSourcePanel.jSourceTextLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 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.contentviewers.contextviewer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
|
||||
|
||||
/**
|
||||
* Displays additional context for the selected file, such as its source, and
|
||||
* usage, if known.
|
||||
*
|
||||
*/
|
||||
public final class ContextSourcePanel extends javax.swing.JPanel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// defines a list of artifacts that provide context for a file
|
||||
private static final List<BlackboardArtifact.ARTIFACT_TYPE> SOURCE_CONTEXT_ARTIFACTS = new ArrayList<>();
|
||||
static {
|
||||
SOURCE_CONTEXT_ARTIFACTS.add(TSK_ASSOCIATED_OBJECT);
|
||||
}
|
||||
|
||||
private final BlackboardArtifact sourceContextArtifact;
|
||||
|
||||
/**
|
||||
* Creates new form ContextViewer
|
||||
*/
|
||||
public ContextSourcePanel(String sourceName, String sourceText, BlackboardArtifact associatedArtifact) {
|
||||
|
||||
initComponents();
|
||||
sourceContextArtifact = associatedArtifact;
|
||||
setSourceName(sourceName);
|
||||
setSourceText(sourceText);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
jSourceGoToResultButton = new javax.swing.JButton();
|
||||
jSourceNameLabel = new javax.swing.JLabel();
|
||||
jSourceTextLabel = new javax.swing.JLabel();
|
||||
|
||||
setBackground(new java.awt.Color(255, 255, 255));
|
||||
setPreferredSize(new java.awt.Dimension(495, 75));
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jSourceGoToResultButton, org.openide.util.NbBundle.getMessage(ContextSourcePanel.class, "ContextSourcePanel.jSourceGoToResultButton.text")); // NOI18N
|
||||
jSourceGoToResultButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
jSourceGoToResultButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jSourceNameLabel, org.openide.util.NbBundle.getMessage(ContextSourcePanel.class, "ContextSourcePanel.jSourceNameLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jSourceTextLabel, org.openide.util.NbBundle.getMessage(ContextSourcePanel.class, "ContextSourcePanel.jSourceTextLabel.text")); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(50, 50, 50)
|
||||
.addComponent(jSourceNameLabel)
|
||||
.addGap(36, 36, 36)
|
||||
.addComponent(jSourceTextLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGap(260, 260, 260))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(90, 90, 90)
|
||||
.addComponent(jSourceGoToResultButton)
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(2, 2, 2)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(jSourceNameLabel)
|
||||
.addComponent(jSourceTextLabel))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jSourceGoToResultButton)
|
||||
.addGap(0, 0, 0))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void jSourceGoToResultButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jSourceGoToResultButtonActionPerformed
|
||||
|
||||
final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance();
|
||||
|
||||
// Navigate to the source context artifact.
|
||||
if (sourceContextArtifact != null) {
|
||||
dtc.viewArtifact(sourceContextArtifact);
|
||||
}
|
||||
}//GEN-LAST:event_jSourceGoToResultButtonActionPerformed
|
||||
|
||||
/**
|
||||
* Sets the source label string.
|
||||
*
|
||||
* @param nameLabel String value for source label.
|
||||
*/
|
||||
private void setSourceName(String nameLabel) {
|
||||
jSourceNameLabel.setText(nameLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source text string.
|
||||
*
|
||||
* @param text String value for source text.
|
||||
*/
|
||||
private void setSourceText(String text) {
|
||||
jSourceTextLabel.setText(text);
|
||||
showSourceButton(!text.isEmpty());
|
||||
showSourceText(true);
|
||||
}
|
||||
|
||||
private void showSourceText(boolean show) {
|
||||
jSourceTextLabel.setVisible(show);
|
||||
}
|
||||
|
||||
private void showSourceButton(boolean show) {
|
||||
jSourceGoToResultButton.setVisible(show);
|
||||
jSourceGoToResultButton.setEnabled(show);
|
||||
}
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton jSourceGoToResultButton;
|
||||
private javax.swing.JLabel jSourceNameLabel;
|
||||
private javax.swing.JLabel jSourceTextLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<Properties>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="ff" green="ff" red="ff" type="rgb"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[495, 75]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<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="50" max="-2" attributes="0"/>
|
||||
<Component id="jUsageNameLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="jUsageTextLabel" pref="240" max="32767" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="36" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="90" max="-2" attributes="0"/>
|
||||
<Component id="jUsageGoToResultButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jUsageTextLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jUsageNameLabel" alignment="1" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jUsageGoToResultButton" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JButton" name="jUsageGoToResultButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextUsagePanel.jUsageGoToResultButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jUsageGoToResultButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jUsageNameLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextUsagePanel.jUsageNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jUsageTextLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextUsagePanel.jUsageTextLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 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.contentviewers.contextviewer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
|
||||
|
||||
/**
|
||||
* Displays additional context for the selected file, such as its source, and
|
||||
* usage, if known.
|
||||
*
|
||||
*/
|
||||
public final class ContextUsagePanel extends javax.swing.JPanel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// defines a list of artifacts that provide context for a file
|
||||
private static final List<BlackboardArtifact.ARTIFACT_TYPE> SOURCE_CONTEXT_ARTIFACTS = new ArrayList<>();
|
||||
static {
|
||||
SOURCE_CONTEXT_ARTIFACTS.add(TSK_ASSOCIATED_OBJECT);
|
||||
}
|
||||
|
||||
private final BlackboardArtifact sourceContextArtifact;
|
||||
|
||||
/**
|
||||
* Creates new form ContextViewer
|
||||
*/
|
||||
public ContextUsagePanel(String sourceName, String sourceText, BlackboardArtifact associatedArtifact) {
|
||||
|
||||
initComponents();
|
||||
sourceContextArtifact = associatedArtifact;
|
||||
setUsageName(sourceName);
|
||||
setUsageText(sourceText);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
|
||||
jUsageGoToResultButton = new javax.swing.JButton();
|
||||
jUsageNameLabel = new javax.swing.JLabel();
|
||||
jUsageTextLabel = new javax.swing.JLabel();
|
||||
|
||||
setBackground(new java.awt.Color(255, 255, 255));
|
||||
setPreferredSize(new java.awt.Dimension(495, 75));
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jUsageGoToResultButton, org.openide.util.NbBundle.getMessage(ContextUsagePanel.class, "ContextUsagePanel.jUsageGoToResultButton.text")); // NOI18N
|
||||
jUsageGoToResultButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
jUsageGoToResultButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jUsageNameLabel, org.openide.util.NbBundle.getMessage(ContextUsagePanel.class, "ContextUsagePanel.jUsageNameLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jUsageTextLabel, org.openide.util.NbBundle.getMessage(ContextUsagePanel.class, "ContextUsagePanel.jUsageTextLabel.text")); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(50, 50, 50)
|
||||
.addComponent(jUsageNameLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(jUsageTextLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 240, Short.MAX_VALUE)
|
||||
.addGap(36, 36, 36))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(90, 90, 90)
|
||||
.addComponent(jUsageGoToResultButton)
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(2, 2, 2)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jUsageTextLabel)
|
||||
.addComponent(jUsageNameLabel, javax.swing.GroupLayout.Alignment.TRAILING))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jUsageGoToResultButton))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void jUsageGoToResultButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jUsageGoToResultButtonActionPerformed
|
||||
final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance();
|
||||
|
||||
// Navigate to the source context artifact.
|
||||
if (sourceContextArtifact != null) {
|
||||
dtc.viewArtifact(sourceContextArtifact);
|
||||
}
|
||||
}//GEN-LAST:event_jUsageGoToResultButtonActionPerformed
|
||||
|
||||
/**
|
||||
* Sets the usage label string.
|
||||
*
|
||||
* @param nameLabel String value for usage label.
|
||||
*/
|
||||
private void setUsageName(String nameLabel) {
|
||||
jUsageNameLabel.setText(nameLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Usage text string.
|
||||
*
|
||||
* @param text String value for Usage text.
|
||||
*/
|
||||
private void setUsageText(String text) {
|
||||
jUsageTextLabel.setText(text);
|
||||
showUsageButton(!text.isEmpty());
|
||||
showUsageText(true);
|
||||
}
|
||||
|
||||
private void showUsageText(boolean show) {
|
||||
jUsageTextLabel.setVisible(show);
|
||||
}
|
||||
|
||||
private void showUsageButton(boolean show) {
|
||||
jUsageGoToResultButton.setVisible(show);
|
||||
jUsageGoToResultButton.setEnabled(show);
|
||||
}
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton jUsageGoToResultButton;
|
||||
private javax.swing.JLabel jUsageNameLabel;
|
||||
private javax.swing.JLabel jUsageTextLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
@ -1,11 +1,145 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<NonVisualComponents>
|
||||
<Container class="javax.swing.JPanel" name="jSourcePanel">
|
||||
<Properties>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="ff" green="ff" id="window" palette="3" red="ff" type="palette"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="40" max="-2" attributes="0"/>
|
||||
<Component id="jSourceLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="304" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
|
||||
<Component id="jSourceLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="jSourceLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="14" style="1"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jSourceLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="jUsagePanel">
|
||||
<Properties>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="ff" green="ff" id="window" palette="3" red="ff" type="palette"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="40" max="-2" attributes="0"/>
|
||||
<Component id="jUsageLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="298" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
||||
<Component id="jUsageLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="jUsageLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="14" style="1"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jUsageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="jUnknownPanel">
|
||||
<Properties>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="ff" green="ff" red="ff" type="rgb"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="50" max="-2" attributes="0"/>
|
||||
<Component id="jUnknownLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
||||
<Component id="jUnknownLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="jUnknownLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jUnknownLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</NonVisualComponents>
|
||||
<Properties>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="ff" green="ff" red="ff" type="rgb"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[495, 358]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
@ -21,138 +155,24 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="jSourceLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jUsageLabel" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="6" pref="6" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="jSourceNameLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jSourceTextLabel" pref="192" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="jUsageNameLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jUsageTextLabel" pref="192" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="36" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="-2" pref="45" max="-2" attributes="0"/>
|
||||
<Component id="jUsageGoToResultButton" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="46" max="-2" attributes="0"/>
|
||||
<Component id="jSourceGoToResultButton" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="jScrollPane" alignment="0" pref="509" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jSourceLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="jSourceNameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jSourceTextLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Component id="jSourceGoToResultButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jUsageLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="jUsageNameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="jUsageTextLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jUsageGoToResultButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="62" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="jScrollPane" alignment="0" pref="335" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JButton" name="jSourceGoToResultButton">
|
||||
<Container class="javax.swing.JScrollPane" name="jScrollPane">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jSourceGoToResultButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||
<Color blue="ff" green="ff" red="ff" type="rgb"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jSourceGoToResultButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jSourceLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="14" style="1"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jSourceLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jSourceNameLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jSourceNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jSourceTextLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jSourceTextLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="jUsageGoToResultButton">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jUsageGoToResultButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jUsageGoToResultButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jUsageLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Dialog" size="14" style="1"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jUsageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jUsageNameLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jUsageNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="jUsageTextLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jUsageTextLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
@ -24,6 +24,8 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.BoxLayout;
|
||||
import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.NbBundle;
|
||||
@ -32,7 +34,6 @@ import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
|
||||
@ -55,19 +56,20 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
||||
|
||||
// defines a list of artifacts that provide context for a file
|
||||
private static final List<BlackboardArtifact.ARTIFACT_TYPE> SOURCE_CONTEXT_ARTIFACTS = new ArrayList<>();
|
||||
private final List<javax.swing.JPanel> contextSourcePanels = new ArrayList<>();
|
||||
private final List<javax.swing.JPanel> contextUsagePanels = new ArrayList<>();
|
||||
|
||||
static {
|
||||
SOURCE_CONTEXT_ARTIFACTS.add(TSK_ASSOCIATED_OBJECT);
|
||||
}
|
||||
|
||||
private BlackboardArtifact sourceContextArtifact;
|
||||
|
||||
/**
|
||||
* Creates new form ContextViewer
|
||||
*/
|
||||
public ContextViewer() {
|
||||
|
||||
initComponents();
|
||||
jScrollPane.setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -79,119 +81,96 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
jSourceGoToResultButton = new javax.swing.JButton();
|
||||
jSourceLabel = new javax.swing.JLabel();
|
||||
jSourceNameLabel = new javax.swing.JLabel();
|
||||
jSourceTextLabel = new javax.swing.JLabel();
|
||||
jUsageGoToResultButton = new javax.swing.JButton();
|
||||
jUsageLabel = new javax.swing.JLabel();
|
||||
jUsageNameLabel = new javax.swing.JLabel();
|
||||
jUsageTextLabel = new javax.swing.JLabel();
|
||||
jSourcePanel = new javax.swing.JPanel();
|
||||
javax.swing.JLabel jSourceLabel = new javax.swing.JLabel();
|
||||
jUsagePanel = new javax.swing.JPanel();
|
||||
javax.swing.JLabel jUsageLabel = new javax.swing.JLabel();
|
||||
jUnknownPanel = new javax.swing.JPanel();
|
||||
javax.swing.JLabel jUnknownLabel = new javax.swing.JLabel();
|
||||
jScrollPane = new javax.swing.JScrollPane();
|
||||
|
||||
setBackground(new java.awt.Color(255, 255, 255));
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jSourceGoToResultButton, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jSourceGoToResultButton.text")); // NOI18N
|
||||
jSourceGoToResultButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
jSourceGoToResultButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
jSourcePanel.setBackground(javax.swing.UIManager.getDefaults().getColor("window"));
|
||||
|
||||
jSourceLabel.setFont(new java.awt.Font("Dialog", 1, 14)); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jSourceLabel, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jSourceLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jSourceNameLabel, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jSourceNameLabel.text")); // NOI18N
|
||||
javax.swing.GroupLayout jSourcePanelLayout = new javax.swing.GroupLayout(jSourcePanel);
|
||||
jSourcePanel.setLayout(jSourcePanelLayout);
|
||||
jSourcePanelLayout.setHorizontalGroup(
|
||||
jSourcePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jSourcePanelLayout.createSequentialGroup()
|
||||
.addGap(40, 40, 40)
|
||||
.addComponent(jSourceLabel)
|
||||
.addContainerGap(304, Short.MAX_VALUE))
|
||||
);
|
||||
jSourcePanelLayout.setVerticalGroup(
|
||||
jSourcePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jSourcePanelLayout.createSequentialGroup()
|
||||
.addGap(5, 5, 5)
|
||||
.addComponent(jSourceLabel)
|
||||
.addGap(2, 2, 2))
|
||||
);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jSourceTextLabel, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jSourceTextLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jUsageGoToResultButton, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jUsageGoToResultButton.text")); // NOI18N
|
||||
jUsageGoToResultButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
jUsageGoToResultButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
jUsagePanel.setBackground(javax.swing.UIManager.getDefaults().getColor("window"));
|
||||
|
||||
jUsageLabel.setFont(new java.awt.Font("Dialog", 1, 14)); // NOI18N
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jUsageLabel, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jUsageLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jUsageNameLabel, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jUsageNameLabel.text")); // NOI18N
|
||||
javax.swing.GroupLayout jUsagePanelLayout = new javax.swing.GroupLayout(jUsagePanel);
|
||||
jUsagePanel.setLayout(jUsagePanelLayout);
|
||||
jUsagePanelLayout.setHorizontalGroup(
|
||||
jUsagePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jUsagePanelLayout.createSequentialGroup()
|
||||
.addGap(40, 40, 40)
|
||||
.addComponent(jUsageLabel)
|
||||
.addContainerGap(298, Short.MAX_VALUE))
|
||||
);
|
||||
jUsagePanelLayout.setVerticalGroup(
|
||||
jUsagePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jUsagePanelLayout.createSequentialGroup()
|
||||
.addGap(2, 2, 2)
|
||||
.addComponent(jUsageLabel)
|
||||
.addGap(2, 2, 2))
|
||||
);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jUsageTextLabel, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jUsageTextLabel.text")); // NOI18N
|
||||
jUnknownPanel.setBackground(new java.awt.Color(255, 255, 255));
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(jUnknownLabel, org.openide.util.NbBundle.getMessage(ContextViewer.class, "ContextViewer.jUnknownLabel.text")); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout jUnknownPanelLayout = new javax.swing.GroupLayout(jUnknownPanel);
|
||||
jUnknownPanel.setLayout(jUnknownPanelLayout);
|
||||
jUnknownPanelLayout.setHorizontalGroup(
|
||||
jUnknownPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jUnknownPanelLayout.createSequentialGroup()
|
||||
.addGap(50, 50, 50)
|
||||
.addComponent(jUnknownLabel)
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
jUnknownPanelLayout.setVerticalGroup(
|
||||
jUnknownPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jUnknownPanelLayout.createSequentialGroup()
|
||||
.addGap(2, 2, 2)
|
||||
.addComponent(jUnknownLabel)
|
||||
.addGap(2, 2, 2))
|
||||
);
|
||||
|
||||
setBackground(new java.awt.Color(255, 255, 255));
|
||||
setPreferredSize(new java.awt.Dimension(495, 358));
|
||||
|
||||
jScrollPane.setBackground(new java.awt.Color(255, 255, 255));
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jSourceLabel)
|
||||
.addComponent(jUsageLabel)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(6, 6, 6)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(jSourceNameLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jSourceTextLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 192, Short.MAX_VALUE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(jUsageNameLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jUsageTextLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 192, Short.MAX_VALUE)))))
|
||||
.addGap(36, 36, 36))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(45, 45, 45)
|
||||
.addComponent(jUsageGoToResultButton))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(46, 46, 46)
|
||||
.addComponent(jSourceGoToResultButton)))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addComponent(jScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 509, Short.MAX_VALUE)
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(jSourceLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(jSourceNameLabel)
|
||||
.addComponent(jSourceTextLabel))
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(jSourceGoToResultButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jUsageLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(jUsageNameLabel)
|
||||
.addComponent(jUsageTextLabel))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jUsageGoToResultButton)
|
||||
.addGap(0, 62, Short.MAX_VALUE))
|
||||
.addComponent(jScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 335, Short.MAX_VALUE)
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void jSourceGoToResultButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jSourceGoToResultButtonActionPerformed
|
||||
|
||||
final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance();
|
||||
|
||||
// Navigate to the source context artifact.
|
||||
if (sourceContextArtifact != null) {
|
||||
dtc.viewArtifact(sourceContextArtifact);
|
||||
}
|
||||
|
||||
}//GEN-LAST:event_jSourceGoToResultButtonActionPerformed
|
||||
|
||||
private void jUsageGoToResultButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jUsageGoToResultButtonActionPerformed
|
||||
final DirectoryTreeTopComponent dtc = DirectoryTreeTopComponent.findInstance();
|
||||
|
||||
// Navigate to the source context artifact.
|
||||
if (sourceContextArtifact != null) {
|
||||
dtc.viewArtifact(sourceContextArtifact);
|
||||
}
|
||||
}//GEN-LAST:event_jUsageGoToResultButtonActionPerformed
|
||||
|
||||
@Override
|
||||
public void setNode(Node selectedNode) {
|
||||
if ((selectedNode == null) || (!isSupported(selectedNode))) {
|
||||
@ -234,9 +213,8 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
||||
|
||||
@Override
|
||||
public void resetComponent() {
|
||||
jSourceGoToResultButton.setVisible(false);
|
||||
setSourceName("");
|
||||
setSourceText("");
|
||||
contextSourcePanels.clear();
|
||||
contextUsagePanels.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -268,6 +246,9 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
||||
return 1;
|
||||
}
|
||||
|
||||
@NbBundle.Messages({
|
||||
"ContextViewer.unknownSource=Unknown ",
|
||||
})
|
||||
/**
|
||||
* Looks for context providing artifacts for the given file and populates
|
||||
* the source context.
|
||||
@ -291,14 +272,32 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
||||
addSourceEntry(contextArtifact);
|
||||
}
|
||||
}
|
||||
jSourceGoToResultButton.setVisible(true);
|
||||
jUsageGoToResultButton.setVisible(true);
|
||||
if (foundASource == false) {
|
||||
setSourceName("Unknown");
|
||||
showSourceText(false);
|
||||
setUsageName("Unknown");
|
||||
showUsageText(false);
|
||||
javax.swing.JPanel contextContainer = new javax.swing.JPanel();
|
||||
contextContainer.add(jSourcePanel);
|
||||
contextContainer.setLayout(new BoxLayout(contextContainer, BoxLayout.Y_AXIS));
|
||||
if (contextSourcePanels.isEmpty()) {
|
||||
contextContainer.add(jUnknownPanel);
|
||||
} else {
|
||||
for (javax.swing.JPanel sourcePanel : contextSourcePanels) {
|
||||
contextContainer.add(sourcePanel);
|
||||
}
|
||||
}
|
||||
contextContainer.add(jUsagePanel);
|
||||
if (contextUsagePanels.isEmpty()) {
|
||||
contextContainer.add(jUnknownPanel);
|
||||
} else {
|
||||
for (javax.swing.JPanel usagePanel : contextUsagePanels) {
|
||||
contextContainer.add(usagePanel);
|
||||
}
|
||||
}
|
||||
contextContainer.setEnabled(foundASource);
|
||||
contextContainer.setVisible(foundASource);
|
||||
jScrollPane.getViewport().setView(contextContainer);
|
||||
jScrollPane.setEnabled(foundASource);
|
||||
jScrollPane.setVisible(foundASource);
|
||||
jScrollPane.repaint();
|
||||
jScrollPane.revalidate();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -312,10 +311,6 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
private void addSourceEntry(BlackboardArtifact artifact) throws TskCoreException {
|
||||
setSourceName("Unknown");
|
||||
showSourceText(false);
|
||||
setUsageName("Unknown");
|
||||
showUsageText(false);
|
||||
|
||||
if (BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT.getTypeID() == artifact.getArtifactTypeID()) {
|
||||
BlackboardAttribute associatedArtifactAttribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
|
||||
@ -323,9 +318,6 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
||||
long artifactId = associatedArtifactAttribute.getValueLong();
|
||||
BlackboardArtifact associatedArtifact = artifact.getSleuthkitCase().getBlackboardArtifact(artifactId);
|
||||
|
||||
//save the artifact for "Go to Result" button
|
||||
sourceContextArtifact = associatedArtifact;
|
||||
|
||||
setSourceFields(associatedArtifact);
|
||||
}
|
||||
}
|
||||
@ -347,74 +339,27 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
||||
private void setSourceFields(BlackboardArtifact associatedArtifact) throws TskCoreException {
|
||||
if (BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() == associatedArtifact.getArtifactTypeID()
|
||||
|| BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID() == associatedArtifact.getArtifactTypeID()) {
|
||||
|
||||
setSourceName(Bundle.ContextViewer_attachmentSource());
|
||||
setSourceText(msgArtifactToAbbreviatedString(associatedArtifact));
|
||||
String sourceName = Bundle.ContextViewer_attachmentSource();
|
||||
String sourceText = msgArtifactToAbbreviatedString(associatedArtifact);
|
||||
javax.swing.JPanel sourcePanel = new ContextSourcePanel(sourceName, sourceText, associatedArtifact);
|
||||
contextSourcePanels.add(sourcePanel);
|
||||
|
||||
} else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() == associatedArtifact.getArtifactTypeID()
|
||||
|| BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE.getTypeID() == associatedArtifact.getArtifactTypeID()) {
|
||||
String sourceName = Bundle.ContextViewer_downloadSource();
|
||||
String sourceText = webDownloadArtifactToString(associatedArtifact);
|
||||
javax.swing.JPanel sourcePanel = new ContextSourcePanel(sourceName, sourceText, associatedArtifact);
|
||||
contextSourcePanels.add(sourcePanel);
|
||||
|
||||
setSourceName(Bundle.ContextViewer_downloadSource());
|
||||
setSourceText(webDownloadArtifactToString(associatedArtifact));
|
||||
} else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() == associatedArtifact.getArtifactTypeID()) {
|
||||
setUsageName(Bundle.ContextViewer_recentDocs());
|
||||
setUsageText(recentDocArtifactToString(associatedArtifact));
|
||||
String sourceName = Bundle.ContextViewer_recentDocs();
|
||||
String sourceText = recentDocArtifactToString(associatedArtifact);
|
||||
javax.swing.JPanel usagePanel = new ContextUsagePanel(sourceName, sourceText, associatedArtifact);
|
||||
contextUsagePanels.add(usagePanel);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source label string.
|
||||
*
|
||||
* @param nameLabel String value for source label.
|
||||
*/
|
||||
private void setSourceName(String nameLabel) {
|
||||
jSourceNameLabel.setText(nameLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the usage label string.
|
||||
*
|
||||
* @param nameLabel String value for usage label.
|
||||
*/
|
||||
private void setUsageName(String nameLabel) {
|
||||
jUsageNameLabel.setText(nameLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source text string.
|
||||
*
|
||||
* @param text String value for source text.
|
||||
*/
|
||||
private void setSourceText(String text) {
|
||||
jSourceTextLabel.setText(text);
|
||||
showSourceText(!text.isEmpty());
|
||||
}
|
||||
|
||||
private void showSourceText(boolean show) {
|
||||
jSourceTextLabel.setVisible(show);
|
||||
jSourceGoToResultButton.setEnabled(show);
|
||||
jSourceLabel.setVisible(show);
|
||||
jUsageLabel.setVisible(show);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Usage text string.
|
||||
*
|
||||
* @param text String value for Usage text.
|
||||
*/
|
||||
private void setUsageText(String text) {
|
||||
jUsageTextLabel.setText(text);
|
||||
showUsageText(!text.isEmpty());
|
||||
}
|
||||
|
||||
private void showUsageText(boolean show) {
|
||||
jUsageTextLabel.setVisible(show);
|
||||
jUsageGoToResultButton.setEnabled(show);
|
||||
jUsageLabel.setVisible(show);
|
||||
jSourceLabel.setVisible(show);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a display string with download source URL from the given
|
||||
* artifact.
|
||||
@ -554,13 +499,9 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton jSourceGoToResultButton;
|
||||
private javax.swing.JLabel jSourceLabel;
|
||||
private javax.swing.JLabel jSourceNameLabel;
|
||||
private javax.swing.JLabel jSourceTextLabel;
|
||||
private javax.swing.JButton jUsageGoToResultButton;
|
||||
private javax.swing.JLabel jUsageLabel;
|
||||
private javax.swing.JLabel jUsageNameLabel;
|
||||
private javax.swing.JLabel jUsageTextLabel;
|
||||
private javax.swing.JScrollPane jScrollPane;
|
||||
private javax.swing.JPanel jSourcePanel;
|
||||
private javax.swing.JPanel jUnknownPanel;
|
||||
private javax.swing.JPanel jUsagePanel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
||||
|
74
Core/src/org/sleuthkit/autopsy/contentviewers/utils/GstLoader.java
Executable file
74
Core/src/org/sleuthkit/autopsy/contentviewers/utils/GstLoader.java
Executable file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 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.contentviewers.utils;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import org.freedesktop.gstreamer.Gst;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
/**
|
||||
* A utility class that loads the gstreamer bindings.
|
||||
*/
|
||||
public final class GstLoader {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(GstLoader.class.getName());
|
||||
private static GstStatus status;
|
||||
|
||||
/**
|
||||
* Attempts to load the gstreamer bindings. Only one attempt will be
|
||||
* performed per Autopsy process. Clients should not attempt to interact
|
||||
* with the gstreamer bindings unless the load was successful.
|
||||
*
|
||||
* @return Status - SUCCESS or FAILURE
|
||||
*/
|
||||
public synchronized static GstStatus tryLoad() {
|
||||
// Null is our 'unknown' status. Prior to the first call, the status
|
||||
// is unknown.
|
||||
if (status != null) {
|
||||
return status;
|
||||
}
|
||||
|
||||
try {
|
||||
// Setting the following property causes the GST
|
||||
// Java bindings to call dispose() on the GST
|
||||
// service thread instead of running it in the GST
|
||||
// Native Object Reaper thread.
|
||||
System.setProperty("glib.reapOnEDT", "true");
|
||||
Gst.init();
|
||||
status = GstStatus.SUCCESS;
|
||||
} catch (Throwable ex) {
|
||||
status = GstStatus.FAILURE;
|
||||
logger.log(Level.WARNING, "Failed to load gsteamer bindings", ex);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* The various init statuses that tryLoad can return.
|
||||
*/
|
||||
public enum GstStatus {
|
||||
SUCCESS, FAILURE
|
||||
}
|
||||
|
||||
private GstLoader() {
|
||||
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@ import javax.swing.event.DocumentListener;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
|
||||
import org.sleuthkit.datamodel.TskData.DbType;
|
||||
import org.sleuthkit.autopsy.centralrepository.optionspanel.GlobalSettingsPanel;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
@ -684,20 +685,30 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
return (isUserSet == isPwSet);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void store() {
|
||||
boolean prevSelected = UserPreferences.getIsMultiUserModeEnabled();
|
||||
CaseDbConnectionInfo prevConn = null;
|
||||
try {
|
||||
prevConn = UserPreferences.getDatabaseConnectionInfo();
|
||||
} catch (UserPreferencesException ex) {
|
||||
logger.log(Level.SEVERE, "There was an error while fetching previous connection settings while trying to save", ex); //NON-NLS
|
||||
}
|
||||
|
||||
boolean multiUserCasesEnabled = cbEnableMultiUser.isSelected();
|
||||
UserPreferences.setIsMultiUserModeEnabled(multiUserCasesEnabled);
|
||||
if (multiUserCasesEnabled == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
CaseDbConnectionInfo info = null;
|
||||
|
||||
if (multiUserCasesEnabled == true) {
|
||||
|
||||
/*
|
||||
* Currently only supporting multi-user cases with PostgreSQL case
|
||||
* databases.
|
||||
*/
|
||||
DbType dbType = DbType.POSTGRESQL;
|
||||
CaseDbConnectionInfo info = new CaseDbConnectionInfo(
|
||||
info = new CaseDbConnectionInfo(
|
||||
tbDbHostname.getText().trim(),
|
||||
tbDbPort.getText().trim(),
|
||||
tbDbUsername.getText().trim(),
|
||||
@ -730,9 +741,36 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
||||
|
||||
UserPreferences.setIndexingServerHost(tbSolrHostname.getText().trim());
|
||||
UserPreferences.setIndexingServerPort(Integer.parseInt(tbSolrPort.getText().trim()));
|
||||
|
||||
}
|
||||
|
||||
// trigger changes to whether or not user can use multi user settings for central repository
|
||||
if (prevSelected != multiUserCasesEnabled || !areCaseDbConnectionEqual(prevConn, info))
|
||||
GlobalSettingsPanel.onMultiUserChange(this, prevSelected, multiUserCasesEnabled);
|
||||
}
|
||||
|
||||
private static boolean arePropsEqual(Object a, Object b) {
|
||||
if (a == null || b == null) {
|
||||
return (a == null && b == null);
|
||||
}
|
||||
else {
|
||||
return a.equals(b);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean areCaseDbConnectionEqual(CaseDbConnectionInfo a, CaseDbConnectionInfo b) {
|
||||
if (a == null || b == null) {
|
||||
return (a == null && b == null);
|
||||
}
|
||||
|
||||
return
|
||||
arePropsEqual(a.getDbType(), b.getDbType()) &&
|
||||
arePropsEqual(a.getHost(), b.getHost()) &&
|
||||
arePropsEqual(a.getPassword(), b.getPassword()) &&
|
||||
arePropsEqual(a.getPort(), b.getPort()) &&
|
||||
arePropsEqual(a.getUserName(), b.getUserName());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validates that the form is filled out correctly for our usage.
|
||||
*
|
||||
|
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
@ -28,7 +29,6 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.openide.nodes.Sheet;
|
||||
@ -66,6 +66,7 @@ import org.sleuthkit.datamodel.Tag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||
import org.sleuthkit.autopsy.texttranslation.utils.FileNameTranslationUtil;
|
||||
|
||||
/**
|
||||
* An abstract node that encapsulates AbstractFile data
|
||||
@ -490,40 +491,19 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates this nodes content name. Doesn't attempt translation if the
|
||||
* name is in english or if there is now translation service available.
|
||||
* Translates the name of the file this node represents. An empty string
|
||||
* will be returned if the translation fails for any reason.
|
||||
*
|
||||
* @return The translated file name or the empty string.
|
||||
*/
|
||||
String getTranslatedFileName() {
|
||||
//If already in complete English, don't translate.
|
||||
if (content.getName().matches("^\\p{ASCII}+$")) {
|
||||
return "";
|
||||
}
|
||||
TextTranslationService tts = TextTranslationService.getInstance();
|
||||
if (tts.hasProvider()) {
|
||||
//Seperate out the base and ext from the contents file name.
|
||||
String base = FilenameUtils.getBaseName(content.getName());
|
||||
try {
|
||||
String translation = tts.translate(base);
|
||||
String ext = FilenameUtils.getExtension(content.getName());
|
||||
|
||||
//If we have no extension, then we shouldn't add the .
|
||||
String extensionDelimiter = (ext.isEmpty()) ? "" : ".";
|
||||
|
||||
//Talk directly to this nodes pcl, fire an update when the translation
|
||||
//is complete.
|
||||
if (!translation.isEmpty()) {
|
||||
return translation + extensionDelimiter + ext;
|
||||
}
|
||||
} catch (NoServiceProviderException noServiceEx) {
|
||||
logger.log(Level.WARNING, "Translate unsuccessful because no TextTranslator "
|
||||
+ "implementation was provided.", noServiceEx.getMessage());
|
||||
} catch (TranslationException noTranslationEx) {
|
||||
logger.log(Level.WARNING, "Could not successfully translate file name "
|
||||
+ content.getName(), noTranslationEx.getMessage());
|
||||
}
|
||||
}
|
||||
return FileNameTranslationUtil.translate(content.getName());
|
||||
} catch (NoServiceProviderException | TranslationException ex) {
|
||||
logger.log(Level.WARNING, MessageFormat.format("Error translating file name (objID={0}))", content.getId()), ex);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all tags from the case database that are associated with the file
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2018 Basis Technology Corp.
|
||||
* Copyright 2013-2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -24,13 +24,11 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction;
|
||||
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
@ -46,14 +44,14 @@ import static org.sleuthkit.autopsy.datamodel.Bundle.*;
|
||||
* tag name nodes have tag type child nodes; tag type nodes are the parents of
|
||||
* either content or blackboard artifact tag nodes.
|
||||
*/
|
||||
public class BlackboardArtifactTagNode extends DisplayableItemNode {
|
||||
public class BlackboardArtifactTagNode extends TagNode {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(BlackboardArtifactTagNode.class.getName());
|
||||
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/green-tag-icon-16.png"; //NON-NLS
|
||||
private final BlackboardArtifactTag tag;
|
||||
|
||||
public BlackboardArtifactTagNode(BlackboardArtifactTag tag) {
|
||||
super(Children.LEAF, Lookups.fixed(tag, tag.getArtifact(), tag.getContent()));
|
||||
super(Lookups.fixed(tag, tag.getArtifact(), tag.getContent()), tag.getContent());
|
||||
super.setName(tag.getContent().getName());
|
||||
super.setDisplayName(tag.getContent().getName());
|
||||
this.setIconBaseWithExtension(ICON_PATH);
|
||||
@ -75,6 +73,7 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode {
|
||||
NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.srcFile.text"),
|
||||
"",
|
||||
tag.getContent().getName()));
|
||||
addOriginalNameProp(properties);
|
||||
String contentPath;
|
||||
try {
|
||||
contentPath = tag.getContent().getUniquePath();
|
||||
@ -82,7 +81,6 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode {
|
||||
Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + tag.getContent().getId() + ")", ex); //NON-NLS
|
||||
contentPath = NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.unavail.text");
|
||||
}
|
||||
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.srcFilePath.text"),
|
||||
NbBundle.getMessage(this.getClass(), "BlackboardArtifactTagNode.createSheet.srcFilePath.text"),
|
||||
@ -119,7 +117,6 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode {
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, MessageFormat.format("Error getting arttribute(s) from blackboard artifact{0}.", artifact.getArtifactID()), ex); //NON-NLS
|
||||
MessageNotifyUtil.Notify.error(Bundle.BlackboardArtifactNode_getAction_errorTitle(), Bundle.BlackboardArtifactNode_getAction_resultErrorMessage());
|
||||
}
|
||||
|
||||
// if the artifact links to another file, add an action to go to that file
|
||||
@ -130,7 +127,6 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode {
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.SEVERE, MessageFormat.format("Error getting linked file from blackboard artifact{0}.", artifact.getArtifactID()), ex); //NON-NLS
|
||||
MessageNotifyUtil.Notify.error(Bundle.BlackboardArtifactNode_getAction_errorTitle(), Bundle.BlackboardArtifactNode_getAction_linkedFileMessage());
|
||||
}
|
||||
//if this artifact has associated content, add the action to view the content in the timeline
|
||||
AbstractFile file = getLookup().lookup(AbstractFile.class);
|
||||
@ -148,11 +144,6 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
|
@ -11,8 +11,6 @@ ArtifactTypeNode.createSheet.childCnt.name=Child Count
|
||||
ArtifactTypeNode.createSheet.childCnt.displayName=Child Count
|
||||
ArtifactTypeNode.createSheet.childCnt.desc=no description
|
||||
BlackboardArtifactNode.noDesc.text=no description
|
||||
BlackboardArtifactNode.createSheet.srcFile.name=Source File
|
||||
BlackboardArtifactNode.createSheet.srcFile.displayName=Source File
|
||||
BlackboardArtifactNode.createSheet.ext.name=Extension
|
||||
BlackboardArtifactNode.createSheet.ext.displayName=Extension
|
||||
BlackboardArtifactNode.createSheet.mimeType.name=MIME Type
|
||||
|
@ -74,13 +74,12 @@ BlackboardArtifactNode.createSheet.path.displayName=Path
|
||||
BlackboardArtifactNode.createSheet.path.name=Path
|
||||
BlackboardArtifactNode.createSheet.score.displayName=S
|
||||
BlackboardArtifactNode.createSheet.score.name=S
|
||||
BlackboardArtifactNode.createSheet.srcFile.displayName=Source File
|
||||
BlackboardArtifactNode.createSheet.srcFile.name=Source File
|
||||
BlackboardArtifactNode.createSheet.srcFile.origDisplayName=Original Name
|
||||
BlackboardArtifactNode.createSheet.srcFile.origName=Original Name
|
||||
BlackboardArtifactNode.createSheet.taggedItem.description=Result or associated file has been tagged.
|
||||
BlackboardArtifactNode.createSheet.tags.displayName=Tags
|
||||
# {0} - artifactDisplayName
|
||||
BlackboardArtifactNode.displayName.artifact={0} Artifact
|
||||
BlackboardArtifactNode.getAction.errorTitle=Error getting actions
|
||||
BlackboardArtifactNode.getAction.linkedFileMessage=There was a problem getting actions for the selected result. The 'View File in Timeline' action will not be available.
|
||||
BlackboardArtifactNode.getAction.resultErrorMessage=There was a problem getting actions for the selected result. The 'View Result in Timeline' action will not be available.
|
||||
BlackboardArtifactTagNode.createSheet.userName.text=User Name
|
||||
BlackboardArtifactTagNode.viewSourceArtifact.text=View Source Result
|
||||
Category.five=CAT-5: Non-pertinent
|
||||
@ -91,6 +90,7 @@ Category.two=CAT-2: Child Exploitation (Non-Illegal/Age Difficult)
|
||||
Category.zero=CAT-0: Uncategorized
|
||||
ContentTagNode.createSheet.artifactMD5.displayName=MD5 Hash
|
||||
ContentTagNode.createSheet.artifactMD5.name=MD5 Hash
|
||||
ContentTagNode.createSheet.origFileName=Original Name
|
||||
ContentTagNode.createSheet.userName.text=User Name
|
||||
DeletedContent.allDelFilter.text=All
|
||||
DeletedContent.createSheet.filterType.desc=no description
|
||||
@ -178,8 +178,6 @@ ArtifactTypeNode.createSheet.childCnt.name=Child Count
|
||||
ArtifactTypeNode.createSheet.childCnt.displayName=Child Count
|
||||
ArtifactTypeNode.createSheet.childCnt.desc=no description
|
||||
BlackboardArtifactNode.noDesc.text=no description
|
||||
BlackboardArtifactNode.createSheet.srcFile.name=Source File
|
||||
BlackboardArtifactNode.createSheet.srcFile.displayName=Source File
|
||||
BlackboardArtifactNode.createSheet.ext.name=Extension
|
||||
BlackboardArtifactNode.createSheet.ext.displayName=Extension
|
||||
BlackboardArtifactNode.createSheet.mimeType.name=MIME Type
|
||||
@ -348,6 +346,8 @@ TagNameNode.bbArtTagTypeNodeKey.text=Result Tags
|
||||
TagNameNode.bookmark.text=Bookmark
|
||||
TagNameNode.createSheet.name.name=Name
|
||||
TagNameNode.createSheet.name.displayName=Name
|
||||
TagNode.propertySheet.origName=Original Name
|
||||
TagNode.propertySheet.origNameDisplayName=Original Name
|
||||
TagsNode.displayName.text=Tags
|
||||
TagsNode.createSheet.name.name=Name
|
||||
TagsNode.createSheet.name.displayName=Name
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2016 Basis Technology Corp.
|
||||
* Copyright 2013-2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -24,7 +24,6 @@ import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.Action;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
@ -39,18 +38,16 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
/**
|
||||
* Instances of this class wrap ContentTag objects. In the Autopsy presentation
|
||||
* of the SleuthKit data model, they are leaf nodes of a tree consisting of
|
||||
* content and blackboard artifact tags, grouped first by tag type, then by tag
|
||||
* name.
|
||||
* content and artifact tags, grouped first by tag type, then by tag name.
|
||||
*/
|
||||
class ContentTagNode extends DisplayableItemNode {
|
||||
class ContentTagNode extends TagNode {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(ContentTagNode.class.getName());
|
||||
|
||||
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/blue-tag-icon-16.png"; //NON-NLS
|
||||
private final ContentTag tag;
|
||||
|
||||
public ContentTagNode(ContentTag tag) {
|
||||
super(Children.LEAF, Lookups.fixed(tag, tag.getContent()));
|
||||
ContentTagNode(ContentTag tag) {
|
||||
super(Lookups.fixed(tag, tag.getContent()), tag.getContent());
|
||||
super.setName(tag.getContent().getName());
|
||||
super.setDisplayName(tag.getContent().getName());
|
||||
this.setIconBaseWithExtension(ICON_PATH);
|
||||
@ -58,6 +55,7 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
}
|
||||
|
||||
@Messages({
|
||||
"ContentTagNode.createSheet.origFileName=Original Name",
|
||||
"ContentTagNode.createSheet.artifactMD5.displayName=MD5 Hash",
|
||||
"ContentTagNode.createSheet.artifactMD5.name=MD5 Hash",
|
||||
"ContentTagNode.createSheet.userName.text=User Name"})
|
||||
@ -79,15 +77,19 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
properties = Sheet.createPropertiesSet();
|
||||
propertySheet.put(properties);
|
||||
}
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.file.name"),
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.file.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.file.displayName"),
|
||||
"",
|
||||
content.getName()));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.filePath.name"),
|
||||
addOriginalNameProp(properties);
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.filePath.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.filePath.displayName"),
|
||||
"",
|
||||
contentPath));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.comment.name"),
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.comment.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.comment.displayName"),
|
||||
"",
|
||||
tag.getComment()));
|
||||
@ -95,23 +97,28 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.displayName"),
|
||||
"",
|
||||
file != null ? ContentUtils.getStringTime(file.getMtime(), file) : ""));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.name"),
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.displayName"),
|
||||
"",
|
||||
file != null ? ContentUtils.getStringTime(file.getCtime(), file) : ""));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.name"),
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.displayName"),
|
||||
"",
|
||||
file != null ? ContentUtils.getStringTime(file.getAtime(), file) : ""));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.name"),
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.displayName"),
|
||||
"",
|
||||
file != null ? ContentUtils.getStringTime(file.getCrtime(), file) : ""));
|
||||
properties.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.name"),
|
||||
properties.put(new NodeProperty<>(
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.displayName"),
|
||||
"",
|
||||
content.getSize()));
|
||||
properties.put(new NodeProperty<>(Bundle.ContentTagNode_createSheet_artifactMD5_name(),
|
||||
properties.put(new NodeProperty<>(
|
||||
Bundle.ContentTagNode_createSheet_artifactMD5_name(),
|
||||
Bundle.ContentTagNode_createSheet_artifactMD5_displayName(),
|
||||
"",
|
||||
file != null ? StringUtils.defaultString(file.getMd5Hash()) : ""));
|
||||
@ -128,8 +135,7 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.addAll(Arrays.asList(super.getActions(context)));
|
||||
|
||||
AbstractFile file = getLookup().lookup(AbstractFile.class
|
||||
);
|
||||
AbstractFile file = getLookup().lookup(AbstractFile.class);
|
||||
if (file != null) {
|
||||
actions.add(ViewFileInTimelineAction.createViewFileAction(file));
|
||||
}
|
||||
@ -144,13 +150,9 @@ class ContentTagNode extends DisplayableItemNode {
|
||||
return visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemType() {
|
||||
return getClass().getName();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Copyright 2012-2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.Lookup;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
@ -142,4 +143,26 @@ public abstract class DisplayableItemNode extends AbstractNode {
|
||||
return selectedChildNodeInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the node property sheet by replacing existing properties with new
|
||||
* properties with the same property name.
|
||||
*
|
||||
* @param newProps The replacement property objects.
|
||||
*/
|
||||
protected synchronized final void updatePropertySheet(NodeProperty<?>... newProps) {
|
||||
Sheet currentSheet = this.getSheet();
|
||||
Sheet.Set currentPropsSet = currentSheet.get(Sheet.PROPERTIES);
|
||||
Property<?>[] currentProps = currentPropsSet.getProperties();
|
||||
for (NodeProperty<?> newProp : newProps) {
|
||||
for (int i = 0; i < currentProps.length; i++) {
|
||||
if (currentProps[i].getName().equals(newProp.getName())) {
|
||||
currentProps[i] = newProp;
|
||||
}
|
||||
}
|
||||
}
|
||||
currentPropsSet.put(currentProps);
|
||||
currentSheet.put(currentPropsSet);
|
||||
this.setSheet(currentSheet);
|
||||
}
|
||||
|
||||
}
|
||||
|
128
Core/src/org/sleuthkit/autopsy/datamodel/TagNode.java
Executable file
128
Core/src/org/sleuthkit/autopsy/datamodel/TagNode.java
Executable file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020-2020 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.datamodel;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
import org.sleuthkit.autopsy.datamodel.utils.FileNameTransTask;
|
||||
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
|
||||
/**
|
||||
* An abstract superclass for a node that represents a tag, uses the name of a
|
||||
* given Content object as its display name, and has a property sheet with an
|
||||
* original name property when machine translation is enabled.
|
||||
*
|
||||
* The translation of the Content name is done in a background thread. The
|
||||
* translated name is made the display name of the node and the untranslated
|
||||
* name is put into both the original name property and into the node's tooltip.
|
||||
*
|
||||
* TODO (Jira-6174): Consider modifying this class to be able to use it more broadly
|
||||
* within the Autopsy data model (i.e., AbstractNode suclasses). It's not really
|
||||
* specific to a tag node.
|
||||
*/
|
||||
@NbBundle.Messages({
|
||||
"TagNode.propertySheet.origName=Original Name",
|
||||
"TagNode.propertySheet.origNameDisplayName=Original Name"
|
||||
})
|
||||
abstract class TagNode extends DisplayableItemNode {
|
||||
|
||||
private final static String ORIG_NAME_PROP_NAME = Bundle.TagNode_propertySheet_origName();
|
||||
private final static String ORIG_NAME_PROP_DISPLAY_NAME = Bundle.TagNode_propertySheet_origNameDisplayName();
|
||||
|
||||
private final String originalName;
|
||||
private volatile String translatedName;
|
||||
|
||||
/**
|
||||
* An abstract superclass for a node that represents a tag, uses the name of
|
||||
* a given Content object as its display name, and has a property sheet with
|
||||
* an untranslated file name property when machine translation is enabled.
|
||||
*
|
||||
* @param lookup The Lookup of the node.
|
||||
* @param content The Content to use for the node display name.
|
||||
*/
|
||||
TagNode(Lookup lookup, Content content) {
|
||||
super(Children.LEAF, lookup);
|
||||
originalName = content.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
abstract public String getItemType();
|
||||
|
||||
@Override
|
||||
abstract public <T> T accept(DisplayableItemNodeVisitor<T> visitor);
|
||||
|
||||
/**
|
||||
* Adds an original name property to the node's property sheet and submits
|
||||
* an original name translation task.
|
||||
*
|
||||
* The translation of the original name is done in a background thread. The
|
||||
* translated name is made the display name of the node and the untranslated
|
||||
* name is put into both the original name property and into the node's
|
||||
* tooltip.
|
||||
*
|
||||
* @param properties The node's property sheet.
|
||||
*/
|
||||
protected void addOriginalNameProp(Sheet.Set properties) {
|
||||
if (TextTranslationService.getInstance().hasProvider() && UserPreferences.displayTranslatedFileNames()) {
|
||||
properties.put(new NodeProperty<>(
|
||||
ORIG_NAME_PROP_NAME,
|
||||
ORIG_NAME_PROP_DISPLAY_NAME,
|
||||
"",
|
||||
translatedName != null ? originalName : ""));
|
||||
if (translatedName == null) {
|
||||
new FileNameTransTask(originalName, this, new NameTranslationListener()).submit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A listener for PropertyChangeEvents from a background task used to
|
||||
* translate the original display name associated with the node.
|
||||
*/
|
||||
private class NameTranslationListener implements PropertyChangeListener {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
String eventType = evt.getPropertyName();
|
||||
if (eventType.equals(FileNameTransTask.getPropertyName())) {
|
||||
translatedName = evt.getNewValue().toString();
|
||||
String originalName = evt.getOldValue().toString();
|
||||
setDisplayName(translatedName);
|
||||
setShortDescription(originalName);
|
||||
updatePropertySheet(new NodeProperty<>(
|
||||
ORIG_NAME_PROP_NAME,
|
||||
ORIG_NAME_PROP_DISPLAY_NAME,
|
||||
"",
|
||||
originalName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -64,7 +64,7 @@ public abstract class AbstractNodePropertySheetTask<T extends AbstractNode> impl
|
||||
* @return The Future of the task, may be used for task cancellation by
|
||||
* calling Future.cancel(true).
|
||||
*/
|
||||
public static Future<?> submitTask(AbstractNodePropertySheetTask<?> task) {
|
||||
private static Future<?> submitTask(AbstractNodePropertySheetTask<?> task) {
|
||||
return executor.submit(task);
|
||||
}
|
||||
|
||||
@ -104,12 +104,22 @@ public abstract class AbstractNodePropertySheetTask<T extends AbstractNode> impl
|
||||
*
|
||||
* @param node The AbstractNode.
|
||||
*
|
||||
* @return The result of the computation as a PropertyChangeEvent.
|
||||
* @return The result of the computation as a PropertyChangeEvent, may be
|
||||
* null.
|
||||
*/
|
||||
protected abstract PropertyChangeEvent computePropertyValue(T node) throws Exception;
|
||||
|
||||
/**
|
||||
* Submits this task to the ExecutorService for the thread pool.
|
||||
*
|
||||
* @return The task's Future from the ExecutorService.
|
||||
*/
|
||||
public final Future<?> submit() {
|
||||
return submitTask(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
final public void run() {
|
||||
public final void run() {
|
||||
try {
|
||||
T node = this.weakNodeRef.get();
|
||||
PropertyChangeListener listener = this.weakListenerRef.get();
|
||||
|
61
Core/src/org/sleuthkit/autopsy/datamodel/utils/FileNameTransTask.java
Executable file
61
Core/src/org/sleuthkit/autopsy/datamodel/utils/FileNameTransTask.java
Executable file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020 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.datamodel.utils;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.sleuthkit.autopsy.texttranslation.utils.FileNameTranslationUtil;
|
||||
|
||||
/**
|
||||
* An AbstractNodePropertySheetTask that translates a file name for an
|
||||
* AbstractNode's property sheet.
|
||||
*/
|
||||
public class FileNameTransTask extends AbstractNodePropertySheetTask<AbstractNode> {
|
||||
|
||||
private final static String EVENT_SOURCE = FileNameTransTask.class.getName();
|
||||
private final static String PROPERTY_NAME = EVENT_SOURCE + ".TranslatedFileName";
|
||||
private final String fileName;
|
||||
|
||||
public static String getPropertyName() {
|
||||
return PROPERTY_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an AbstractNodePropertySheetTask that translates a file name
|
||||
* for an AbstractNode's property sheet. When the translation is complete, a
|
||||
* PropertyChangeEvent will be fired to the node's PropertyChangeListener.
|
||||
* Call getPropertyName() to identify the property.
|
||||
*
|
||||
* @param node The node.
|
||||
* @param listener The node's PropertyChangeListener.
|
||||
* @param fileName THe file name.
|
||||
*/
|
||||
public FileNameTransTask(String fileName, AbstractNode node, PropertyChangeListener listener) {
|
||||
super(node, listener);
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeEvent computePropertyValue(AbstractNode node) throws Exception {
|
||||
String translatedFileName = FileNameTranslationUtil.translate(fileName);
|
||||
return translatedFileName.isEmpty() ? null : new PropertyChangeEvent(EVENT_SOURCE, PROPERTY_NAME, fileName, translatedFileName);
|
||||
}
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Copyright 2012-2020 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -187,27 +187,6 @@ public class DataResultFilterNode extends FilterNode {
|
||||
return propertySets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the display name for the wrapped node.
|
||||
*
|
||||
* OutlineView used in the DataResult table uses getDisplayName() to
|
||||
* populate the first column, which is Source File.
|
||||
*
|
||||
* Hence this override to return the 'correct' displayName for the wrapped
|
||||
* node.
|
||||
*
|
||||
* @return The display name for the node.
|
||||
*/
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
final Node orig = getOriginal();
|
||||
String name = orig.getDisplayName();
|
||||
if ((orig instanceof BlackboardArtifactNode)) {
|
||||
name = ((BlackboardArtifactNode) orig).getSourceName();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds information about which child node of this node, if any, should be
|
||||
* selected. Can be null.
|
||||
|
@ -23,7 +23,6 @@ import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.io.Files;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.file.Paths;
|
||||
@ -95,6 +94,7 @@ class FileSearch {
|
||||
.build();
|
||||
private static final int PREVIEW_SIZE = 256;
|
||||
private static volatile TextSummarizer summarizerToUse = null;
|
||||
private static final BufferedImage VIDEO_DEFAULT_IMAGE = getDefaultVideoThumbnail();
|
||||
|
||||
/**
|
||||
* Run the file search and returns the SearchResults object for debugging.
|
||||
@ -456,6 +456,20 @@ class FileSearch {
|
||||
+ "AND blackboard_artifacts.obj_id IN (" + objIdList + ") "; // NON-NLS
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default image to display when a thumbnail is not available.
|
||||
*
|
||||
* @return The default video thumbnail.
|
||||
*/
|
||||
private static BufferedImage getDefaultVideoThumbnail() {
|
||||
try {
|
||||
return ImageIO.read(ImageUtils.class.getResourceAsStream("/org/sleuthkit/autopsy/images/failedToCreateVideoThumb.png"));//NON-NLS
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to load 'failed to create video' placeholder.", ex); //NON-NLS
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the video thumbnails for a file which exists in a
|
||||
* VideoThumbnailsWrapper and update the VideoThumbnailsWrapper to include
|
||||
@ -476,7 +490,6 @@ class FileSearch {
|
||||
cacheDirectory = null;
|
||||
logger.log(Level.WARNING, "Unable to get cache directory, video thumbnails will not be saved", ex);
|
||||
}
|
||||
|
||||
if (cacheDirectory == null || file.getMd5Hash() == null || !Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash()).toFile().exists()) {
|
||||
java.io.File tempFile;
|
||||
try {
|
||||
@ -488,7 +501,7 @@ class FileSearch {
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
thumbnailWrapper.setThumbnails(createDefaultThumbnailList(), framePositions);
|
||||
thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions);
|
||||
return;
|
||||
}
|
||||
if (tempFile.exists() == false || tempFile.length() < file.getSize()) {
|
||||
@ -502,7 +515,7 @@ class FileSearch {
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
thumbnailWrapper.setThumbnails(createDefaultThumbnailList(), framePositions);
|
||||
thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions);
|
||||
return;
|
||||
}
|
||||
ContentUtils.writeToFile(file, tempFile, progress, null, true);
|
||||
@ -523,7 +536,7 @@ class FileSearch {
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
thumbnailWrapper.setThumbnails(createDefaultThumbnailList(), framePositions);
|
||||
thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions);
|
||||
return;
|
||||
}
|
||||
double fps = videoFile.get(5); // gets frame per second
|
||||
@ -535,7 +548,7 @@ class FileSearch {
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
thumbnailWrapper.setThumbnails(createDefaultThumbnailList(), framePositions);
|
||||
thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions);
|
||||
return;
|
||||
}
|
||||
if (Thread.interrupted()) {
|
||||
@ -544,7 +557,7 @@ class FileSearch {
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
thumbnailWrapper.setThumbnails(createDefaultThumbnailList(), framePositions);
|
||||
thumbnailWrapper.setThumbnails(createDefaultThumbnailList(VIDEO_DEFAULT_IMAGE), framePositions);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -573,10 +586,10 @@ class FileSearch {
|
||||
logger.log(Level.WARNING, "Error seeking to " + framePositions[i] + "ms in {0}", file.getParentPath() + "/" + file.getName()); //NON-NLS
|
||||
// If we can't set the time, continue to the next frame position and try again.
|
||||
|
||||
videoThumbnails.add(ImageUtils.getDefaultThumbnail());
|
||||
videoThumbnails.add(VIDEO_DEFAULT_IMAGE);
|
||||
if (cacheDirectory != null) {
|
||||
try {
|
||||
ImageIO.write((RenderedImage) ImageUtils.getDefaultThumbnail(), THUMBNAIL_FORMAT,
|
||||
ImageIO.write(VIDEO_DEFAULT_IMAGE, THUMBNAIL_FORMAT,
|
||||
Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash(), i + "-" + framePositions[i] + "." + THUMBNAIL_FORMAT).toFile()); //NON-NLS)
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, "Unable to save default video thumbnail for " + file.getMd5Hash() + " at frame position " + framePositions[i], ex);
|
||||
@ -588,10 +601,10 @@ class FileSearch {
|
||||
if (!videoFile.read(imageMatrix)) {
|
||||
logger.log(Level.WARNING, "Error reading frame at " + framePositions[i] + "ms from {0}", file.getParentPath() + "/" + file.getName()); //NON-NLS
|
||||
// If the image is bad for some reason, continue to the next frame position and try again.
|
||||
videoThumbnails.add(ImageUtils.getDefaultThumbnail());
|
||||
videoThumbnails.add(VIDEO_DEFAULT_IMAGE);
|
||||
if (cacheDirectory != null) {
|
||||
try {
|
||||
ImageIO.write((RenderedImage) ImageUtils.getDefaultThumbnail(), THUMBNAIL_FORMAT,
|
||||
ImageIO.write(VIDEO_DEFAULT_IMAGE, THUMBNAIL_FORMAT,
|
||||
Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash(), i + "-" + framePositions[i] + "." + THUMBNAIL_FORMAT).toFile()); //NON-NLS)
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, "Unable to save default video thumbnail for " + file.getMd5Hash() + " at frame position " + framePositions[i], ex);
|
||||
@ -602,10 +615,10 @@ class FileSearch {
|
||||
}
|
||||
// If the image is empty, return since no buffered image can be created.
|
||||
if (imageMatrix.empty()) {
|
||||
videoThumbnails.add(ImageUtils.getDefaultThumbnail());
|
||||
videoThumbnails.add(VIDEO_DEFAULT_IMAGE);
|
||||
if (cacheDirectory != null) {
|
||||
try {
|
||||
ImageIO.write((RenderedImage) ImageUtils.getDefaultThumbnail(), THUMBNAIL_FORMAT,
|
||||
ImageIO.write(VIDEO_DEFAULT_IMAGE, THUMBNAIL_FORMAT,
|
||||
Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, file.getMd5Hash(), i + "-" + framePositions[i] + "." + THUMBNAIL_FORMAT).toFile()); //NON-NLS)
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, "Unable to save default video thumbnail for " + file.getMd5Hash() + " at frame position " + framePositions[i], ex);
|
||||
@ -660,7 +673,7 @@ class FileSearch {
|
||||
videoFile.release(); // close the file}
|
||||
}
|
||||
} else {
|
||||
loadSavedThumbnails(cacheDirectory, thumbnailWrapper);
|
||||
loadSavedThumbnails(cacheDirectory, thumbnailWrapper, VIDEO_DEFAULT_IMAGE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -674,7 +687,7 @@ class FileSearch {
|
||||
* information about the file and the thumbnails
|
||||
* associated with it.
|
||||
*/
|
||||
private static void loadSavedThumbnails(String cacheDirectory, VideoThumbnailsWrapper thumbnailWrapper) {
|
||||
private static void loadSavedThumbnails(String cacheDirectory, VideoThumbnailsWrapper thumbnailWrapper, BufferedImage failedVideoThumbImage) {
|
||||
int[] framePositions = new int[4];
|
||||
List<Image> videoThumbnails = new ArrayList<>();
|
||||
int thumbnailNumber = 0;
|
||||
@ -683,7 +696,7 @@ class FileSearch {
|
||||
try {
|
||||
videoThumbnails.add(ImageIO.read(Paths.get(cacheDirectory, VIDEO_THUMBNAIL_DIR, md5, fileName).toFile()));
|
||||
} catch (IOException ex) {
|
||||
videoThumbnails.add(ImageUtils.getDefaultThumbnail());
|
||||
videoThumbnails.add(failedVideoThumbImage);
|
||||
logger.log(Level.WARNING, "Unable to read saved video thumbnail " + fileName + " for " + md5, ex);
|
||||
}
|
||||
int framePos = Integer.valueOf(FilenameUtils.getBaseName(fileName).substring(2));
|
||||
@ -699,12 +712,12 @@ class FileSearch {
|
||||
*
|
||||
* @return List containing the default thumbnail.
|
||||
*/
|
||||
private static List<Image> createDefaultThumbnailList() {
|
||||
private static List<Image> createDefaultThumbnailList(BufferedImage failedVideoThumbImage) {
|
||||
List<Image> videoThumbnails = new ArrayList<>();
|
||||
videoThumbnails.add(ImageUtils.getDefaultThumbnail());
|
||||
videoThumbnails.add(ImageUtils.getDefaultThumbnail());
|
||||
videoThumbnails.add(ImageUtils.getDefaultThumbnail());
|
||||
videoThumbnails.add(ImageUtils.getDefaultThumbnail());
|
||||
videoThumbnails.add(failedVideoThumbImage);
|
||||
videoThumbnails.add(failedVideoThumbImage);
|
||||
videoThumbnails.add(failedVideoThumbImage);
|
||||
videoThumbnails.add(failedVideoThumbImage);
|
||||
return videoThumbnails;
|
||||
}
|
||||
|
||||
|
@ -273,7 +273,6 @@ final class FileSearchData {
|
||||
= new ImmutableSet.Builder<String>()
|
||||
.add("text/html", //NON-NLS
|
||||
"text/csv", //NON-NLS
|
||||
"text/x-log", //NON-NLS
|
||||
"application/rtf", //NON-NLS
|
||||
"application/pdf", //NON-NLS
|
||||
"application/xhtml+xml", //NON-NLS
|
||||
|
@ -434,7 +434,7 @@ final public class MapPanel extends javax.swing.JPanel {
|
||||
/**
|
||||
* Find the waypoint that is closest to the given mouse click point.
|
||||
*
|
||||
* @param mouseClickPoint The mouse click point
|
||||
* @param clickPoint The mouse click point
|
||||
*
|
||||
* @return A waypoint that is within 10 pixels of the given point, or null
|
||||
* if none was found.
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
@ -81,9 +81,9 @@ public abstract class TranslateTextTask extends SwingWorker<TranslateTextTask.Tr
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main contructor for the TranslateTextTask.
|
||||
* This is the main constructor for the TranslateTextTask.
|
||||
* @param translateText whether or not to translate text
|
||||
* @param contentDescriptor the content descriptor for the item being
|
||||
* @param fileDescriptor the content descriptor for the item being
|
||||
* translated (used for logging errors)
|
||||
*/
|
||||
public TranslateTextTask(boolean translateText, String fileDescriptor) {
|
||||
|
@ -164,9 +164,7 @@ public final class TranslatedTextViewer implements TextViewer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts text from the given node
|
||||
*
|
||||
* @param file Selected node in UI
|
||||
* Extracts text from the current node
|
||||
*
|
||||
* @return Extracted text
|
||||
*
|
||||
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2020-2020 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.texttranslation.utils;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException;
|
||||
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
|
||||
import org.sleuthkit.autopsy.texttranslation.TranslationException;
|
||||
|
||||
/**
|
||||
* A utility to translate file names.
|
||||
*/
|
||||
public final class FileNameTranslationUtil {
|
||||
|
||||
/**
|
||||
* Translates a file name using the configured machine translation service.
|
||||
*
|
||||
* @param fileName The file name.
|
||||
*
|
||||
* @return The translation of the file name.
|
||||
*
|
||||
* @throws NoServiceProviderException If machine translation is not
|
||||
* configured.
|
||||
* @throws TranslationException If there is an error doing the
|
||||
* translation.
|
||||
*/
|
||||
public static String translate(String fileName) throws NoServiceProviderException, TranslationException {
|
||||
/*
|
||||
* Don't attempt translation if the characters of the file name are all
|
||||
* ASCII chars.
|
||||
*
|
||||
* TODO (Jira-6175): This filter prevents translation of many
|
||||
* non-English file names composed entirely of Latin chars.
|
||||
*/
|
||||
if (fileName.matches("^\\p{ASCII}+$")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
TextTranslationService translator = TextTranslationService.getInstance();
|
||||
String baseName = FilenameUtils.getBaseName(fileName);
|
||||
String translation = translator.translate(baseName);
|
||||
if (!translation.isEmpty()) {
|
||||
String extension = FilenameUtils.getExtension(fileName);
|
||||
if (!extension.isEmpty()) {
|
||||
String extensionDelimiter = (extension.isEmpty()) ? "" : ".";
|
||||
translation += extensionDelimiter + extension;
|
||||
}
|
||||
}
|
||||
return translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent instantiation of this utility class
|
||||
*/
|
||||
private FileNameTranslationUtil() {
|
||||
}
|
||||
|
||||
}
|
@ -130,8 +130,7 @@ public class CentralRepoDatamodelTest extends TestCase {
|
||||
|
||||
dbSettingsSqlite.saveSettings();
|
||||
CentralRepoDbUtil.setUseCentralRepo(true);
|
||||
CentralRepoPlatforms.setSelectedPlatform(CentralRepoPlatforms.SQLITE.name());
|
||||
CentralRepoPlatforms.saveSelectedPlatform();
|
||||
CentralRepoDbManager.saveDbChoice(CentralRepoDbChoice.SQLITE);
|
||||
} catch (CentralRepoException ex) {
|
||||
Exceptions.printStackTrace(ex);
|
||||
Assert.fail(ex.getMessage());
|
||||
|
@ -47,6 +47,8 @@ import org.sleuthkit.autopsy.testutils.IngestUtils;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import junit.framework.Assert;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbChoice;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbManager;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
|
||||
import org.sleuthkit.autopsy.coreutils.TimeStampUtils;
|
||||
@ -303,8 +305,7 @@ class InterCaseTestUtils {
|
||||
centralRepoSchemaFactory.insertDefaultDatabaseContent();
|
||||
|
||||
crSettings.saveSettings();
|
||||
CentralRepoPlatforms.setSelectedPlatform(CentralRepoPlatforms.SQLITE.name());
|
||||
CentralRepoPlatforms.saveSelectedPlatform();
|
||||
CentralRepoDbManager.saveDbChoice(CentralRepoDbChoice.SQLITE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,8 +14,7 @@
|
||||
|
||||
<!-- for viewers -->
|
||||
<dependency conf="autopsy_core->*" org="org.freedesktop.gstreamer" name="gst1-java-core" rev="1.0.0"/>
|
||||
<dependency conf="autopsy_core->*" org="net.java.dev.jna" name="jna" rev="3.4.0"/>
|
||||
<dependency conf="autopsy_core->*" org="net.java.dev.jna" name="platform" rev="3.4.0"/>
|
||||
<dependency conf="autopsy_core->*" org="net.java.dev.jna" name="jna-platform" rev="5.5.0"/>
|
||||
|
||||
<!-- for file search -->
|
||||
<dependency conf="autopsy_core->*" org="com.github.lgooddatepicker" name="LGoodDatePicker" rev="10.3.1"/>
|
||||
@ -73,8 +72,5 @@
|
||||
<dependency conf="autopsy_core->default" org="com.googlecode.plist" name="dd-plist" rev="1.20"/>
|
||||
|
||||
<exclude org="*" ext="*" type="javadoc"/>
|
||||
<!-- conflict resolutions for multiple JAR versions -->
|
||||
<conflict org="net.java.dev.jna" module="jna" rev="3.4.0"/>
|
||||
<conflict org="net.java.dev.jna" module="platform" rev="3.4.0"/>
|
||||
</dependencies>
|
||||
</ivy-module>
|
||||
|
@ -21,7 +21,6 @@ file.reference.dom4j-1.6.1.jar=release/modules/ext/dom4j-1.6.1.jar
|
||||
file.reference.geronimo-jms_1.1_spec-1.0.jar=release/modules/ext/geronimo-jms_1.1_spec-1.0.jar
|
||||
file.reference.gson-2.8.5.jar=release/modules/ext/gson-2.8.5.jar
|
||||
file.reference.gst1-java-core-1.0.0.jar=release\\modules\\ext\\gst1-java-core-1.0.0.jar
|
||||
file.reference.jna-3.4.0.jar=release/modules/ext/jna-3.4.0.jar
|
||||
file.reference.guava-19.0.jar=release/modules/ext/guava-19.0.jar
|
||||
file.reference.imageio-bmp-3.2.jar=release/modules/ext/imageio-bmp-3.2.jar
|
||||
file.reference.imageio-core-3.2.jar=release/modules/ext/imageio-core-3.2.jar
|
||||
@ -44,6 +43,8 @@ file.reference.jfxtras-common-8.0-r4.jar=release/modules/ext/jfxtras-common-8.0-
|
||||
file.reference.jfxtras-controls-8.0-r4.jar=release/modules/ext/jfxtras-controls-8.0-r4.jar
|
||||
file.reference.jfxtras-fxml-8.0-r4.jar=release/modules/ext/jfxtras-fxml-8.0-r4.jar
|
||||
file.reference.jna-3.4.0.jar=release/modules/ext/jna-3.4.0.jar
|
||||
file.reference.jna-5.5.0.jar=release\\modules\\ext\\jna-5.5.0.jar
|
||||
file.reference.jna-platform-5.5.0.jar=release\\modules\\ext\\jna-platform-5.5.0.jar
|
||||
file.reference.joda-time-2.4.jar=release/modules/ext/joda-time-2.4.jar
|
||||
file.reference.jsr305-1.3.9.jar=release/modules/ext/jsr305-1.3.9.jar
|
||||
file.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1.jar
|
||||
@ -52,7 +53,6 @@ file.reference.logkit-1.0.1.jar=release/modules/ext/logkit-1.0.1.jar
|
||||
file.reference.mail-1.4.3.jar=release/modules/ext/mail-1.4.3.jar
|
||||
file.reference.opencv-248.jar=release/modules/ext/opencv-248.jar
|
||||
file.reference.openjfx-dialogs-1.0.2.jar=release/modules/ext/openjfx-dialogs-1.0.3.jar
|
||||
file.reference.platform-3.4.0.jar=release/modules/ext/platform-3.4.0.jar
|
||||
file.reference.poi-4.0.1.jar=release\\modules\\ext\\poi-4.0.1.jar
|
||||
file.reference.poi-excelant-4.0.1.jar=release\\modules\\ext\\poi-excelant-4.0.1.jar
|
||||
file.reference.poi-ooxml-4.0.1.jar=release\\modules\\ext\\poi-ooxml-4.0.1.jar
|
||||
|
@ -806,10 +806,6 @@
|
||||
<runtime-relative-path>ext/sigar-1.6.4.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/sigar-1.6.4.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jna-3.4.0.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jna-3.4.0.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/gson-2.8.5.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/gson-2.8.5.jar</binary-origin>
|
||||
@ -902,6 +898,10 @@
|
||||
<runtime-relative-path>ext/commons-csv-1.4.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/commons-csv-1.4.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jna-5.5.0.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jna-5.5.0.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/imageio-sgi-3.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/imageio-sgi-3.2.jar</binary-origin>
|
||||
@ -946,10 +946,6 @@
|
||||
<runtime-relative-path>ext/imageio-bmp-3.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/imageio-bmp-3.2.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/platform-3.4.0.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/platform-3.4.0.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/commons-lang-2.6.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/commons-lang-2.6.jar</binary-origin>
|
||||
@ -1018,6 +1014,10 @@
|
||||
<runtime-relative-path>ext/dom4j-1.6.1.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/dom4j-1.6.1.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jna-platform-5.5.0.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jna-platform-5.5.0.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/imageio-metadata-3.2.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/imageio-metadata-3.2.jar</binary-origin>
|
||||
|
@ -95,7 +95,7 @@ class BrowserLocationAnalyzer(general.AndroidComponentAnalyzer):
|
||||
longitude = Double.valueOf(resultSet.getString("longitude"))
|
||||
|
||||
attributes = ArrayList()
|
||||
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT)
|
||||
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK)
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, general.MODULE_NAME, latitude))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, general.MODULE_NAME, longitude))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, timestamp))
|
||||
|
@ -41,6 +41,7 @@ from org.sleuthkit.datamodel import TskCoreException
|
||||
|
||||
import traceback
|
||||
import general
|
||||
import struct
|
||||
|
||||
"""
|
||||
Parses cache files that Android maintains for Wifi and cell towers. Adds GPS points to blackboard.
|
||||
@ -74,60 +75,24 @@ class CacheLocationAnalyzer(general.AndroidComponentAnalyzer):
|
||||
|
||||
def __findGeoLocationsInFile(self, file, abstractFile):
|
||||
|
||||
tempBytes = bytearray([0] * 2) # will temporarily hold bytes to be converted into the correct data types
|
||||
|
||||
try:
|
||||
inputStream = FileInputStream(file)
|
||||
|
||||
inputStream.read(tempBytes) # version
|
||||
|
||||
tempBytes = bytearray([0] * 2)
|
||||
inputStream.read(tempBytes) # number of location entries
|
||||
|
||||
iterations = BigInteger(tempBytes).intValue()
|
||||
|
||||
for i in range(iterations): # loop through every entry
|
||||
tempBytes = bytearray([0] * 2)
|
||||
inputStream.read(tempBytes)
|
||||
|
||||
tempBytes = bytearray([0])
|
||||
inputStream.read(tempBytes)
|
||||
|
||||
while BigInteger(tempBytes).intValue() != 0: # pass through non important values until the start of accuracy(around 7-10 bytes)
|
||||
if 0 > inputStream.read(tempBytes):
|
||||
break # we've passed the end of the file, so stop
|
||||
|
||||
tempBytes = bytearray([0] * 3)
|
||||
inputStream.read(tempBytes)
|
||||
if BigInteger(tempBytes).intValue() <= 0: # This refers to a location that could not be calculated
|
||||
tempBytes = bytearray([0] * 28) # read rest of the row's bytes
|
||||
inputStream.read(tempBytes)
|
||||
continue
|
||||
accuracy = "" + BigInteger(tempBytes).intValue()
|
||||
|
||||
tempBytes = bytearray([0] * 4)
|
||||
inputStream.read(tempBytes)
|
||||
confidence = "" + BigInteger(tempBytes).intValue()
|
||||
|
||||
tempBytes = bytearray([0] * 8)
|
||||
inputStream.read(tempBytes)
|
||||
latitude = CacheLocationAnalyzer.toDouble(bytes)
|
||||
|
||||
tempBytes = bytearray([0] * 8)
|
||||
inputStream.read(tempBytes)
|
||||
longitude = CacheLocationAnalyzer.toDouble(bytes)
|
||||
|
||||
tempBytes = bytearray([0] * 8)
|
||||
inputStream.read(tempBytes)
|
||||
timestamp = BigInteger(tempBytes).longValue() / 1000
|
||||
# code to parse the cache.wifi and cache.cell taken from https://forensics.spreitzenbarth.de/2011/10/28/decoding-cache-cell-and-cache-wifi-files/
|
||||
cacheFile = open(str(file), 'rb')
|
||||
(version, entries) = struct.unpack('>hh', cacheFile.read(4))
|
||||
i = 0
|
||||
while i < entries:
|
||||
key = cacheFile.read(struct.unpack('>h', cacheFile.read(2))[0])
|
||||
(accuracy, confidence, latitude, longitude, readtime) = struct.unpack('>iiddQ', cacheFile.read(32))
|
||||
timestamp = readtime/1000
|
||||
i = i + 1
|
||||
|
||||
attributes = ArrayList()
|
||||
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT)
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, AndroidAnalyzer.MODULE_NAME, latitude))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, AndroidAnalyzer.MODULE_NAME, longitude))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, AndroidModuleFactorymodule.Name, timestamp))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, AndroidAnalyzer.MODULE_NAME,
|
||||
file.getName() + "Location History"))
|
||||
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK)
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, general.MODULE_NAME, latitude))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, general.MODULE_NAME, longitude))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, timestamp))
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, general.MODULE_NAME,
|
||||
abstractFile.getName() + " Location History"))
|
||||
|
||||
artifact.addAttributes(attributes)
|
||||
#Not storing these for now.
|
||||
@ -136,15 +101,13 @@ class CacheLocationAnalyzer(general.AndroidComponentAnalyzer):
|
||||
try:
|
||||
# index the artifact for keyword search
|
||||
blackboard = Case.getCurrentCase().getSleuthkitCase().getBlackboard()
|
||||
blackboard.postArtifact(artifact, MODULE_NAME)
|
||||
blackboard.postArtifact(artifact, general.MODULE_NAME)
|
||||
except Blackboard.BlackboardException as ex:
|
||||
self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + str(artifact.getArtifactID()), ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
MessageNotifyUtil.Notify.error("Failed to index GPS trackpoint artifact for keyword search.", artifact.getDisplayName())
|
||||
cacheFile.close()
|
||||
|
||||
except SQLException as ex:
|
||||
# Unable to execute Cached GPS locations SQL query against database.
|
||||
pass
|
||||
except Exception as ex:
|
||||
self._logger.log(Level.SEVERE, "Error parsing Cached GPS locations to blackboard", ex)
|
||||
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||
|
@ -117,6 +117,7 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer):
|
||||
try:
|
||||
contacts_parser = ViberContactsParser(contacts_db)
|
||||
while contacts_parser.next():
|
||||
if (not(not contacts_parser.get_phone() or contacts_parser.get_phone().isspace())):
|
||||
helper.addContact(
|
||||
contacts_parser.get_contact_name(),
|
||||
contacts_parser.get_phone(),
|
||||
@ -124,6 +125,17 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer):
|
||||
contacts_parser.get_mobile_phone(),
|
||||
contacts_parser.get_email()
|
||||
)
|
||||
# Check if contact_name is blank and if it is not create a TSK_CONTACT otherwise ignore as not Contact Info
|
||||
elif (not(not contacts_parser.get_contact_name() or contacts_parser.get_contact_name().isspace())):
|
||||
current_case = Case.getCurrentCase().getSleuthkitCase()
|
||||
attributes = ArrayList()
|
||||
artifact = contacts_db.getDBFile().newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT)
|
||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), self._PARSER_NAME, contacts_parser.get_contact_name()))
|
||||
artifact.addAttributes(attributes)
|
||||
|
||||
# Post the artifact to blackboard
|
||||
current_case.getBlackboard().postArtifact(artifact, self._PARSER_NAME)
|
||||
|
||||
contacts_parser.close()
|
||||
except SQLException as ex:
|
||||
self._logger.log(Level.WARNING, "Error querying the viber database for contacts.", ex)
|
||||
@ -269,7 +281,7 @@ class ViberContactsParser(TskContactsParser):
|
||||
super(ViberContactsParser, self).__init__(contact_db.runQuery(
|
||||
"""
|
||||
SELECT C.display_name AS name,
|
||||
D.data2 AS number
|
||||
coalesce(D.data2, D.data1, D.data3) AS number
|
||||
FROM phonebookcontact AS C
|
||||
JOIN phonebookdata AS D
|
||||
ON C._id = D.contact_id
|
||||
|
Loading…
x
Reference in New Issue
Block a user