mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-14 00:46:16 +00:00
Merge commit 'e978a4b759b68741ade89ca69656089c75844e51' of https://github.com/sleuthkit/autopsy into 6077-DisplayImageForSummary
This commit is contained in:
commit
c75adc72d2
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2012-2019 Basis Technology Corp.
|
* Copyright 2012-2020 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -1114,7 +1114,7 @@ public class Case {
|
|||||||
CallableSystemAction.get(CaseCloseAction.class).setEnabled(true);
|
CallableSystemAction.get(CaseCloseAction.class).setEnabled(true);
|
||||||
CallableSystemAction.get(CaseDetailsAction.class).setEnabled(true);
|
CallableSystemAction.get(CaseDetailsAction.class).setEnabled(true);
|
||||||
CallableSystemAction.get(DataSourceSummaryAction.class).setEnabled(true);
|
CallableSystemAction.get(DataSourceSummaryAction.class).setEnabled(true);
|
||||||
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(true);
|
CallableSystemAction.get(CaseDeleteAction.class).setEnabled(FeatureAccessUtils.canDeleteCurrentCase());
|
||||||
CallableSystemAction.get(OpenTimelineAction.class).setEnabled(true);
|
CallableSystemAction.get(OpenTimelineAction.class).setEnabled(true);
|
||||||
CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(true);
|
CallableSystemAction.get(OpenCommVisualizationToolAction.class).setEnabled(true);
|
||||||
CallableSystemAction.get(CommonAttributeSearchAction.class).setEnabled(true);
|
CallableSystemAction.get(CommonAttributeSearchAction.class).setEnabled(true);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2011-2020 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -35,6 +35,7 @@ import org.openide.util.NbBundle.Messages;
|
|||||||
import org.openide.util.actions.CallableSystemAction;
|
import org.openide.util.actions.CallableSystemAction;
|
||||||
import org.openide.windows.WindowManager;
|
import org.openide.windows.WindowManager;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.featureaccess.FeatureAccessUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The action associated with the Delete button of the Case Properties panel. It
|
* The action associated with the Delete button of the Case Properties panel. It
|
||||||
@ -54,7 +55,7 @@ final class CaseDeleteAction extends CallableSystemAction {
|
|||||||
/*
|
/*
|
||||||
* A value of 'null' signifies that there is no case open.
|
* A value of 'null' signifies that there is no case open.
|
||||||
*/
|
*/
|
||||||
setEnabled(null != evt.getNewValue());
|
setEnabled(null != evt.getNewValue() && FeatureAccessUtils.canDeleteCurrentCase());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
package org.sleuthkit.autopsy.centralrepository.datamodel;
|
||||||
|
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.beans.PropertyChangeSupport;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
|
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
|
||||||
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
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 {
|
public class CentralRepoDbManager {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(CentralRepoDbManager.class.getName());
|
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_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();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* obtains the database connectivity for central repository
|
* 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 to connect to
|
* @return The CentralRepository object that will be used for connection.
|
||||||
* @throws CentralRepoException
|
* @throws CentralRepoException
|
||||||
*/
|
*/
|
||||||
private static CentralRepository obtainCentralRepository() 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
|
* @param db The database connection.
|
||||||
* @return the lock if acquired
|
* @return The lock if acquired.
|
||||||
* @throws CentralRepoException
|
* @throws CentralRepoException
|
||||||
*/
|
*/
|
||||||
private static CoordinationService.Lock obtainCentralRepoLock(CentralRepository db) 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 db The database connectivity object.
|
||||||
* @param lock the acquired lock
|
* @param lock The acquired lock.
|
||||||
* @throws CentralRepoException
|
* @throws CentralRepoException
|
||||||
*/
|
*/
|
||||||
private static void updatedDbSchema(CentralRepository db, CoordinationService.Lock 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
|
* upgrade fails, the Central Repository will be disabled and the current
|
||||||
* settings will be cleared.
|
* settings will be cleared.
|
||||||
*/
|
*/
|
||||||
@ -142,8 +288,7 @@ public class CentralRepoDbManager {
|
|||||||
} catch (CentralRepoException ex2) {
|
} catch (CentralRepoException ex2) {
|
||||||
logger.log(Level.SEVERE, "Error shutting down central repo connection pool", ex2);
|
logger.log(Level.SEVERE, "Error shutting down central repo connection pool", ex2);
|
||||||
}
|
}
|
||||||
CentralRepoPlatforms.setSelectedPlatform(CentralRepoPlatforms.DISABLED.name());
|
saveDbChoice(CentralRepoDbChoice.DISABLED, false);
|
||||||
CentralRepoPlatforms.saveSelectedPlatform();
|
|
||||||
if (innerException == null) {
|
if (innerException == null) {
|
||||||
throw new CentralRepoException(message, desc);
|
throw new CentralRepoException(message, desc);
|
||||||
} else {
|
} else {
|
||||||
@ -151,41 +296,56 @@ public class CentralRepoDbManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private DatabaseTestResult testingStatus;
|
private DatabaseTestResult testingStatus;
|
||||||
private CentralRepoPlatforms selectedPlatform;
|
private CentralRepoDbChoice selectedDbChoice;
|
||||||
|
|
||||||
private final PostgresCentralRepoSettings dbSettingsPostgres;
|
private final PostgresCentralRepoSettings dbSettingsPostgres;
|
||||||
|
private final PostgresCentralRepoSettings dbSettingsMultiUser;
|
||||||
private final SqliteCentralRepoSettings dbSettingsSqlite;
|
private final SqliteCentralRepoSettings dbSettingsSqlite;
|
||||||
|
|
||||||
private boolean configurationChanged = false;
|
private boolean configurationChanged = false;
|
||||||
|
|
||||||
public CentralRepoDbManager() {
|
public CentralRepoDbManager() {
|
||||||
dbSettingsPostgres = new PostgresCentralRepoSettings();
|
selectedDbChoice = getSavedDbChoice();
|
||||||
|
dbSettingsPostgres = new PostgresCentralRepoSettings(PostgresSettingsLoader.CUSTOM_SETTINGS_LOADER);
|
||||||
|
dbSettingsMultiUser = new PostgresCentralRepoSettings(PostgresSettingsLoader.MULTIUSER_SETTINGS_LOADER);
|
||||||
dbSettingsSqlite = new SqliteCentralRepoSettings();
|
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() {
|
public PostgresCentralRepoSettings getDbSettingsPostgres() {
|
||||||
return dbSettingsPostgres;
|
return dbSettingsPostgres;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the current SQLite database settings for central repository.
|
||||||
|
* @return The current SQLite database settings
|
||||||
|
*/
|
||||||
public SqliteCentralRepoSettings getDbSettingsSqlite() {
|
public SqliteCentralRepoSettings getDbSettingsSqlite() {
|
||||||
return dbSettingsSqlite;
|
return dbSettingsSqlite;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* setup sqlite db with default settings
|
* This method sets up the sqlite database with default settings.
|
||||||
* @throws CentralRepoException if unable to successfully set up database
|
* @throws CentralRepoException if unable to successfully set up database.
|
||||||
*/
|
*/
|
||||||
public void setupDefaultSqliteDb() throws CentralRepoException {
|
public void setupDefaultSqliteDb() throws CentralRepoException {
|
||||||
// change in-memory settings to default sqlite
|
// change in-memory settings to default sqlite
|
||||||
selectedPlatform = CentralRepoPlatforms.SQLITE;
|
selectedDbChoice = CentralRepoDbChoice.SQLITE;
|
||||||
dbSettingsSqlite.setupDefaultSettings();
|
dbSettingsSqlite.setupDefaultSettings();
|
||||||
|
|
||||||
// if db is not present, attempt to create it
|
// if db is not present, attempt to create it
|
||||||
@ -196,7 +356,7 @@ public class CentralRepoDbManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// the only successful setup status is tested ok
|
// 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");
|
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
|
* This method returns if changes to the central repository configuration were
|
||||||
* successfully applied
|
* successfully applied.
|
||||||
*
|
*
|
||||||
* @return true if the database configuration was successfully changed false
|
* @return Returns true if the database configuration was successfully changed false
|
||||||
* if it was not
|
* if it was not.
|
||||||
*/
|
*/
|
||||||
public boolean wasConfigurationChanged() {
|
public boolean wasConfigurationChanged() {
|
||||||
return configurationChanged;
|
return configurationChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CentralRepoDbSettings getSelectedSettings() throws CentralRepoException {
|
private CentralRepoDbConnectivityManager getSelectedSettings() throws CentralRepoException {
|
||||||
switch (selectedPlatform) {
|
if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_MULTIUSER)
|
||||||
case POSTGRESQL:
|
return dbSettingsMultiUser;
|
||||||
return dbSettingsPostgres;
|
if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM)
|
||||||
case SQLITE:
|
return dbSettingsPostgres;
|
||||||
return dbSettingsSqlite;
|
if (selectedDbChoice == CentralRepoDbChoice.SQLITE)
|
||||||
case DISABLED:
|
return dbSettingsSqlite;
|
||||||
return null;
|
if (selectedDbChoice == CentralRepoDbChoice.DISABLED)
|
||||||
default:
|
return null;
|
||||||
throw new CentralRepoException("Unknown database type: " + selectedPlatform);
|
|
||||||
}
|
throw new CentralRepoException("Unknown database type: " + selectedDbChoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RdbmsCentralRepoFactory getDbFactory() throws CentralRepoException {
|
private RdbmsCentralRepoFactory getDbFactory() throws CentralRepoException {
|
||||||
switch (selectedPlatform) {
|
if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_MULTIUSER)
|
||||||
case POSTGRESQL:
|
return new RdbmsCentralRepoFactory(CentralRepoPlatforms.POSTGRESQL, dbSettingsMultiUser);
|
||||||
return new RdbmsCentralRepoFactory(selectedPlatform, dbSettingsPostgres);
|
if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM)
|
||||||
case SQLITE:
|
return new RdbmsCentralRepoFactory(CentralRepoPlatforms.POSTGRESQL, dbSettingsPostgres);
|
||||||
return new RdbmsCentralRepoFactory(selectedPlatform, dbSettingsSqlite);
|
if (selectedDbChoice == CentralRepoDbChoice.SQLITE)
|
||||||
case DISABLED:
|
return new RdbmsCentralRepoFactory(CentralRepoPlatforms.SQLITE, dbSettingsSqlite);
|
||||||
return null;
|
if (selectedDbChoice == CentralRepoDbChoice.DISABLED)
|
||||||
default:
|
return null;
|
||||||
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 {
|
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 result = false;
|
||||||
boolean dbCreated = true;
|
boolean dbCreated = true;
|
||||||
|
|
||||||
CentralRepoDbSettings selectedDbSettings = getSelectedSettings();
|
|
||||||
|
|
||||||
if (!selectedDbSettings.verifyDatabaseExists()) {
|
if (!selectedDbSettings.verifyDatabaseExists()) {
|
||||||
dbCreated = selectedDbSettings.createDatabase();
|
dbCreated = selectedDbSettings.createDatabase();
|
||||||
}
|
}
|
||||||
@ -265,7 +432,6 @@ public class CentralRepoDbManager {
|
|||||||
if (!result) {
|
if (!result) {
|
||||||
// Remove the incomplete database
|
// Remove the incomplete database
|
||||||
if (dbCreated) {
|
if (dbCreated) {
|
||||||
// RAMAN TBD: migrate deleteDatabase() to RdbmsCentralRepoFactory
|
|
||||||
selectedDbSettings.deleteDatabase();
|
selectedDbSettings.deleteDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,12 +440,12 @@ public class CentralRepoDbManager {
|
|||||||
throw new CentralRepoException(schemaError);
|
throw new CentralRepoException(schemaError);
|
||||||
}
|
}
|
||||||
|
|
||||||
testingStatus = DatabaseTestResult.TESTEDOK;
|
testingStatus = DatabaseTestResult.TESTED_OK;
|
||||||
return true;
|
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."})
|
@NbBundle.Messages({"CentralRepoDbManager.connectionErrorMsg.text=Failed to connect to central repository database."})
|
||||||
public void saveNewCentralRepo() throws CentralRepoException {
|
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
|
// Even if we fail to close the existing connections, make sure that we
|
||||||
// save the new connection settings, so an Autopsy restart will correctly
|
// save the new connection settings, so an Autopsy restart will correctly
|
||||||
// start with the new settings.
|
// start with the new settings.
|
||||||
CentralRepoPlatforms.setSelectedPlatform(selectedPlatform.name());
|
CentralRepoDbUtil.setUseCentralRepo(selectedDbChoice != CentralRepoDbChoice.DISABLED);
|
||||||
CentralRepoPlatforms.saveSelectedPlatform();
|
saveDbChoice(selectedDbChoice);
|
||||||
|
|
||||||
CentralRepoDbSettings selectedDbSettings = getSelectedSettings();
|
CentralRepoDbConnectivityManager selectedDbSettings = getSelectedSettings();
|
||||||
|
|
||||||
// save the new settings
|
// save the new settings
|
||||||
selectedDbSettings.saveSettings();
|
selectedDbSettings.saveSettings();
|
||||||
// Load those newly saved settings into the postgres db manager instance
|
// Load those newly saved settings into the postgres db manager instance
|
||||||
// in case we are still using the same instance.
|
// in case we are still using the same instance.
|
||||||
if (selectedPlatform == CentralRepoPlatforms.POSTGRESQL || selectedPlatform == CentralRepoPlatforms.SQLITE) {
|
if (selectedDbChoice != null && selectedDbChoice != CentralRepoDbChoice.DISABLED) {
|
||||||
try {
|
try {
|
||||||
logger.info("Creating central repo db with settings: " + selectedDbSettings);
|
logger.info("Saving central repo settings for db: " + selectedDbSettings);
|
||||||
CentralRepository.getInstance().updateSettings();
|
CentralRepository.getInstance().updateSettings();
|
||||||
configurationChanged = true;
|
configurationChanged = true;
|
||||||
} catch (CentralRepoException ex) {
|
} catch (CentralRepoException ex) {
|
||||||
@ -326,82 +492,82 @@ 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() {
|
public DatabaseTestResult getStatus() {
|
||||||
return testingStatus;
|
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() {
|
public void clearStatus() {
|
||||||
testingStatus = DatabaseTestResult.UNTESTED;
|
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;
|
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(
|
public boolean testDatabaseSettingsAreValid(
|
||||||
String tbDbHostname, String tbDbPort, String tbDbUsername, String tfDatabasePath, String jpDbPassword) throws CentralRepoException, NumberFormatException {
|
String tbDbHostname, String tbDbPort, String tbDbUsername, String tfDatabasePath, String jpDbPassword) throws CentralRepoException, NumberFormatException {
|
||||||
|
|
||||||
switch (selectedPlatform) {
|
if (selectedDbChoice == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
|
||||||
case POSTGRESQL:
|
dbSettingsPostgres.setHost(tbDbHostname);
|
||||||
dbSettingsPostgres.setHost(tbDbHostname);
|
dbSettingsPostgres.setPort(Integer.parseInt(tbDbPort));
|
||||||
dbSettingsPostgres.setPort(Integer.parseInt(tbDbPort));
|
dbSettingsPostgres.setDbName(CENTRAL_REPO_DB_NAME);
|
||||||
dbSettingsPostgres.setDbName(CENTRAL_REPO_DB_NAME);
|
dbSettingsPostgres.setUserName(tbDbUsername);
|
||||||
dbSettingsPostgres.setUserName(tbDbUsername);
|
dbSettingsPostgres.setPassword(jpDbPassword);
|
||||||
dbSettingsPostgres.setPassword(jpDbPassword);
|
}
|
||||||
break;
|
else if (selectedDbChoice == CentralRepoDbChoice.SQLITE) {
|
||||||
case SQLITE:
|
File databasePath = new File(tfDatabasePath);
|
||||||
File databasePath = new File(tfDatabasePath);
|
dbSettingsSqlite.setDbName(SqliteCentralRepoSettings.DEFAULT_DBNAME);
|
||||||
dbSettingsSqlite.setDbName(SqliteCentralRepoSettings.DEFAULT_DBNAME);
|
dbSettingsSqlite.setDbDirectory(databasePath.getPath());
|
||||||
dbSettingsSqlite.setDbDirectory(databasePath.getPath());
|
}
|
||||||
break;
|
else if (selectedDbChoice != CentralRepoDbChoice.POSTGRESQL_MULTIUSER) {
|
||||||
default:
|
throw new IllegalStateException("Central Repo has an unknown selected platform: " + selectedDbChoice);
|
||||||
throw new IllegalStateException("Central Repo has an unknown selected platform: " + selectedPlatform);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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() {
|
public DatabaseTestResult testStatus() {
|
||||||
if (selectedPlatform == CentralRepoPlatforms.POSTGRESQL) {
|
try {
|
||||||
if (dbSettingsPostgres.verifyConnection()) {
|
CentralRepoDbConnectivityManager manager = getSelectedSettings();
|
||||||
if (dbSettingsPostgres.verifyDatabaseExists()) {
|
if (manager != null)
|
||||||
if (dbSettingsPostgres.verifyDatabaseSchema()) {
|
testingStatus = manager.testStatus();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
catch (CentralRepoException e) {
|
||||||
|
logger.log(Level.WARNING, "unable to test status of db connection in central repo", e);
|
||||||
|
}
|
||||||
|
|
||||||
return testingStatus;
|
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,115 @@
|
|||||||
|
/*
|
||||||
|
* 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.getCreateArtifactInstancesTableTemplate(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 {
|
||||||
|
|
||||||
|
// Alter the existing X_Instance tables 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;
|
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.
|
* Writes the current schema version into the database.
|
||||||
*
|
*
|
||||||
|
@ -18,102 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.centralrepository.datamodel;
|
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 {
|
public enum CentralRepoPlatforms {
|
||||||
DISABLED("Disabled", true),
|
DISABLED,
|
||||||
SQLITE("SQLite", false),
|
SQLITE,
|
||||||
POSTGRESQL("PostgreSQL", false);
|
POSTGRESQL
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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() {}
|
||||||
|
|
||||||
|
private void logException(TryHandler handler) {
|
||||||
|
try {
|
||||||
|
handler.operation();
|
||||||
|
}
|
||||||
|
catch (CentralRepoException | NumberFormatException e) {
|
||||||
|
LOGGER.log(Level.WARNING, "There was an error in converting central repo postgres settings", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface represents an action that potentially throws an exception.
|
||||||
|
*/
|
||||||
|
private interface TryHandler {
|
||||||
|
void operation() 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
logException(() -> settings.setHost(muConn.getHost()));
|
||||||
|
logException(() -> settings.setDbName(PostgresConnectionSettings.DEFAULT_DBNAME));
|
||||||
|
logException(() -> settings.setUserName(muConn.getUserName()));
|
||||||
|
|
||||||
|
logException(() -> settings.setPort(Integer.parseInt(muConn.getPort())));
|
||||||
|
logException(() -> settings.setBulkThreshold(RdbmsCentralRepo.DEFAULT_BULK_THRESHHOLD));
|
||||||
|
|
||||||
|
logException(() -> settings.setPassword(muConn.getPassword()));
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
logException(() -> settings.setHost(keyVals.get(HOST_KEY)));
|
||||||
|
logException(() -> settings.setDbName(keyVals.get(DBNAME_KEY)));
|
||||||
|
logException(() -> settings.setUserName(keyVals.get(USER_KEY)));
|
||||||
|
|
||||||
|
logException(() -> settings.setPort(Integer.parseInt(keyVals.get(PORT_KEY))));
|
||||||
|
logException(() -> settings.setBulkThreshold(Integer.parseInt(keyVals.get((BULK_THRESHOLD_KEY)))));
|
||||||
|
|
||||||
|
String passwordHex = keyVals.get(PASSWORD_KEY);
|
||||||
|
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;
|
||||||
|
logException(() -> settings.setPassword(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;
|
CentralRepoPlatforms selectedPlatform = CentralRepoPlatforms.DISABLED;
|
||||||
if (CentralRepoDbUtil.allowUseOfCentralRepository()) {
|
if (CentralRepoDbUtil.allowUseOfCentralRepository()) {
|
||||||
selectedPlatform = CentralRepoPlatforms.getSelectedPlatform();
|
selectedPlatform = CentralRepoDbManager.getSavedDbChoice().getDbPlatform();
|
||||||
}
|
}
|
||||||
switch (selectedPlatform) {
|
switch (selectedPlatform) {
|
||||||
case POSTGRESQL:
|
case POSTGRESQL:
|
||||||
@ -93,7 +93,7 @@ public interface CentralRepository {
|
|||||||
*/
|
*/
|
||||||
static boolean isEnabled() {
|
static boolean isEnabled() {
|
||||||
return CentralRepoDbUtil.allowUseOfCentralRepository()
|
return CentralRepoDbUtil.allowUseOfCentralRepository()
|
||||||
&& CentralRepoPlatforms.getSelectedPlatform() != CentralRepoPlatforms.DISABLED;
|
&& CentralRepoDbManager.getSavedDbChoice() != CentralRepoDbChoice.DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,13 +19,13 @@
|
|||||||
package org.sleuthkit.autopsy.centralrepository.datamodel;
|
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 {
|
public enum DatabaseTestResult {
|
||||||
UNTESTED,
|
UNTESTED,
|
||||||
CONNECTION_FAILED,
|
CONNECTION_FAILED,
|
||||||
SCHEMA_INVALID,
|
SCHEMA_INVALID,
|
||||||
DB_DOES_NOT_EXIST,
|
DB_DOES_NOT_EXIST,
|
||||||
TESTEDOK;
|
TESTED_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,15 +24,9 @@ import java.sql.PreparedStatement;
|
|||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
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
|
* Settings for the Postgres implementation of the Central Repository database
|
||||||
@ -40,106 +34,84 @@ import static org.sleuthkit.autopsy.centralrepository.datamodel.RdbmsCentralRepo
|
|||||||
* NOTE: This is public scope because the options panel calls it directly to
|
* NOTE: This is public scope because the options panel calls it directly to
|
||||||
* set/get
|
* 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 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 VALIDATION_QUERY = "SELECT version()"; // NON-NLS
|
||||||
private final static String JDBC_BASE_URI = "jdbc:postgresql://"; // 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 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 final PostgresSettingsLoader loader;
|
||||||
private int port;
|
private PostgresConnectionSettings connSettings;
|
||||||
private String dbName;
|
|
||||||
private int bulkThreshold;
|
private static PostgresSettingsLoader getLoaderFromSaved() throws CentralRepoException {
|
||||||
private String userName;
|
CentralRepoDbChoice choice = CentralRepoDbManager.getSavedDbChoice();
|
||||||
private String password;
|
if (choice == CentralRepoDbChoice.POSTGRESQL_CUSTOM)
|
||||||
|
return PostgresSettingsLoader.CUSTOM_SETTINGS_LOADER;
|
||||||
public PostgresCentralRepoSettings() {
|
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();
|
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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("PostgresCentralRepoSettings: [db type: postgres, host: %s:%d, db name: %s, username: %s]",
|
return String.format("PostgresCentralRepoSettings: [db type: postgres, host: %s:%d, db name: %s, username: %s]",
|
||||||
getHost(), getPort(), getDbName(), getUserName());
|
getHost(), getPort(), getDbName(), getUserName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadSettings() {
|
|
||||||
host = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.host"); // NON-NLS
|
/**
|
||||||
if (host == null || host.isEmpty()) {
|
* @return the VALIDATION_QUERY
|
||||||
host = DEFAULT_HOST;
|
*/
|
||||||
}
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
dbName = ModuleSettings.getConfigSetting("CentralRepository", "db.postgresql.dbName"); // NON-NLS
|
|
||||||
if (dbName == null || dbName.isEmpty()) {
|
|
||||||
dbName = DEFAULT_DBNAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
* @return the POSTGRES_DRIVER
|
||||||
ModuleSettings.setConfigSetting("CentralRepository", "db.postgresql.port", Integer.toString(port)); // NON-NLS
|
*/
|
||||||
ModuleSettings.setConfigSetting("CentralRepository", "db.postgresql.dbName", getDbName()); // NON-NLS
|
String getDriver() {
|
||||||
ModuleSettings.setConfigSetting("CentralRepository", "db.postgresql.bulkThreshold", Integer.toString(getBulkThreshold())); // NON-NLS
|
return JDBC_DRIVER;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the JDBC_BASE_URI
|
||||||
|
*/
|
||||||
|
String getJDBCBaseURI() {
|
||||||
|
return JDBC_BASE_URI;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the full connection URL as a String
|
* Get the full connection URL as a String
|
||||||
*
|
*
|
||||||
@ -301,73 +273,33 @@ 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
|
* @return the host
|
||||||
*/
|
*/
|
||||||
public String getHost() {
|
public String getHost() {
|
||||||
return host;
|
return connSettings.getHost();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param host the host to set
|
* @param host the host to set
|
||||||
*/
|
*/
|
||||||
public void setHost(String host) throws CentralRepoException {
|
public void setHost(String host) throws CentralRepoException {
|
||||||
if (null != host && !host.isEmpty()) {
|
connSettings.setHost(host);
|
||||||
this.host = host;
|
|
||||||
} else {
|
|
||||||
throw new CentralRepoException("Invalid host name. Cannot be empty."); // NON-NLS
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the port
|
* @return the port
|
||||||
*/
|
*/
|
||||||
public int getPort() {
|
public int getPort() {
|
||||||
return port;
|
return connSettings.getPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param port the port to set
|
* @param port the port to set
|
||||||
*/
|
*/
|
||||||
public void setPort(int port) throws CentralRepoException {
|
public void setPort(int port) throws CentralRepoException {
|
||||||
if (port > 0 && port < 65535) {
|
connSettings.setPort(port);
|
||||||
this.port = port;
|
|
||||||
} else {
|
|
||||||
throw new CentralRepoException("Invalid port. Must be a number greater than 0."); // NON-NLS
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -377,95 +309,72 @@ public final class PostgresCentralRepoSettings implements CentralRepoDbSettings
|
|||||||
* @return the dbName
|
* @return the dbName
|
||||||
*/
|
*/
|
||||||
public String getDbName() {
|
public String getDbName() {
|
||||||
return dbName.toLowerCase();
|
return connSettings.getDbName() == null ? null : connSettings.getDbName().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param dbName the dbName to set
|
* @param dbName the dbName to set
|
||||||
*/
|
*/
|
||||||
public void setDbName(String dbName) throws CentralRepoException {
|
public void setDbName(String dbName) throws CentralRepoException {
|
||||||
if (dbName == null || dbName.isEmpty()) {
|
connSettings.setDbName(dbName);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the bulkThreshold
|
* @return the bulkThreshold
|
||||||
*/
|
*/
|
||||||
int getBulkThreshold() {
|
int getBulkThreshold() {
|
||||||
return bulkThreshold;
|
return connSettings.getBulkThreshold();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param bulkThreshold the bulkThreshold to set
|
* @param bulkThreshold the bulkThreshold to set
|
||||||
*/
|
*/
|
||||||
public void setBulkThreshold(int bulkThreshold) throws CentralRepoException {
|
public void setBulkThreshold(int bulkThreshold) throws CentralRepoException {
|
||||||
if (bulkThreshold > 0) {
|
connSettings.setBulkThreshold(bulkThreshold);
|
||||||
this.bulkThreshold = bulkThreshold;
|
|
||||||
} else {
|
|
||||||
throw new CentralRepoException("Invalid bulk threshold."); // NON-NLS
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the userName
|
* @return the userName
|
||||||
*/
|
*/
|
||||||
public String getUserName() {
|
public String getUserName() {
|
||||||
return userName;
|
return connSettings.getUserName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param userName the userName to set
|
* @param userName the userName to set
|
||||||
*/
|
*/
|
||||||
public void setUserName(String userName) throws CentralRepoException {
|
public void setUserName(String userName) throws CentralRepoException {
|
||||||
if (userName == null || userName.isEmpty()) {
|
connSettings.setUserName(userName);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the password
|
* @return the password
|
||||||
*/
|
*/
|
||||||
public String getPassword() {
|
public String getPassword() {
|
||||||
return password;
|
return connSettings.getPassword();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param password the password to set
|
* @param password the password to set
|
||||||
*/
|
*/
|
||||||
public void setPassword(String password) throws CentralRepoException {
|
public void setPassword(String password) throws CentralRepoException {
|
||||||
if (password == null || password.isEmpty()) {
|
connSettings.setPassword(password);
|
||||||
throw new CentralRepoException("Invalid user password. Cannot be empty."); // NON-NLS
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DatabaseTestResult testStatus() {
|
||||||
|
if (verifyConnection()) {
|
||||||
|
if (verifyDatabaseExists()) {
|
||||||
|
if (verifyDatabaseSchema()) {
|
||||||
|
return DatabaseTestResult.TESTED_OK;
|
||||||
|
} else {
|
||||||
|
return DatabaseTestResult.SCHEMA_INVALID;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return DatabaseTestResult.DB_DOES_NOT_EXIST;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return DatabaseTestResult.CONNECTION_FAILED;
|
||||||
}
|
}
|
||||||
this.password = password;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the VALIDATION_QUERY
|
|
||||||
*/
|
|
||||||
String getValidationQuery() {
|
|
||||||
return VALIDATION_QUERY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the POSTGRES_DRIVER
|
|
||||||
*/
|
|
||||||
String getDriver() {
|
|
||||||
return JDBC_DRIVER;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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 SCHEMA_MINOR_VERSION_KEY = "SCHEMA_MINOR_VERSION";
|
||||||
static final String CREATION_SCHEMA_MAJOR_VERSION_KEY = "CREATION_SCHEMA_MAJOR_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 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;
|
protected final List<CorrelationAttributeInstance.Type> defaultCorrelationTypes;
|
||||||
|
|
||||||
@ -3553,7 +3553,7 @@ abstract class RdbmsCentralRepo implements CentralRepository {
|
|||||||
conn = connect(false);
|
conn = connect(false);
|
||||||
conn.setAutoCommit(false);
|
conn.setAutoCommit(false);
|
||||||
statement = conn.createStatement();
|
statement = conn.createStatement();
|
||||||
selectedPlatform = CentralRepoPlatforms.getSelectedPlatform();
|
selectedPlatform = CentralRepoDbManager.getSavedDbChoice().getDbPlatform();
|
||||||
int minorVersion = 0;
|
int minorVersion = 0;
|
||||||
String minorVersionStr = null;
|
String minorVersionStr = null;
|
||||||
resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "'");
|
resultSet = statement.executeQuery("SELECT value FROM db_info WHERE name='" + RdbmsCentralRepo.SCHEMA_MINOR_VERSION_KEY + "'");
|
||||||
@ -3808,6 +3808,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()));
|
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);
|
updateSchemaVersion(conn);
|
||||||
conn.commit();
|
conn.commit();
|
||||||
logger.log(Level.INFO, String.format("Central Repository schema updated to version %s", SOFTWARE_CR_DB_SCHEMA_VERSION));
|
logger.log(Level.INFO, String.format("Central Repository schema updated to version %s", SOFTWARE_CR_DB_SCHEMA_VERSION));
|
||||||
|
@ -134,7 +134,7 @@ public class RdbmsCentralRepoFactory {
|
|||||||
stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')");
|
stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MAJOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMajor() + "')");
|
||||||
stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')");
|
stmt.execute("INSERT INTO db_info (name, value) VALUES ('" + RdbmsCentralRepo.CREATION_SCHEMA_MINOR_VERSION_KEY + "', '" + SOFTWARE_CR_DB_SCHEMA_VERSION.getMinor() + "')");
|
||||||
|
|
||||||
// Create account_types and accounts tab;es which are referred by X_instances tables
|
// Create account_types and accounts tables which are referred by X_instances tables
|
||||||
stmt.execute(getCreateAccountTypesTableStatement(selectedPlatform));
|
stmt.execute(getCreateAccountTypesTableStatement(selectedPlatform));
|
||||||
stmt.execute(getCreateAccountsTableStatement(selectedPlatform));
|
stmt.execute(getCreateAccountsTableStatement(selectedPlatform));
|
||||||
|
|
||||||
@ -161,7 +161,8 @@ public class RdbmsCentralRepoFactory {
|
|||||||
stmt.execute(String.format(getReferenceTypeValueKnownstatusIndexTemplate(), reference_type_dbname, reference_type_dbname));
|
stmt.execute(String.format(getReferenceTypeValueKnownstatusIndexTemplate(), reference_type_dbname, reference_type_dbname));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createPersonaTables(stmt);
|
// @TODO: uncomment this when ready to create Persona tables.
|
||||||
|
//createPersonaTables(stmt);
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "Error initializing db schema.", ex); // NON-NLS
|
LOGGER.log(Level.SEVERE, "Error initializing db schema.", ex); // NON-NLS
|
||||||
return false;
|
return false;
|
||||||
@ -191,8 +192,10 @@ public class RdbmsCentralRepoFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result = CentralRepoDbUtil.insertDefaultCorrelationTypes(conn)
|
result = CentralRepoDbUtil.insertDefaultCorrelationTypes(conn)
|
||||||
&& CentralRepoDbUtil.insertDefaultOrganization(conn)
|
&& CentralRepoDbUtil.insertDefaultOrganization(conn) &&
|
||||||
&& insertDefaultPersonaTablesContent(conn);
|
insertDefaultAccountsTablesContent(conn);
|
||||||
|
// @TODO: uncomment when ready to create/populate persona tables
|
||||||
|
// && insertDefaultPersonaTablesContent(conn);
|
||||||
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
LOGGER.log(Level.SEVERE, String.format("Failed to populate default data in CR tables."), ex);
|
LOGGER.log(Level.SEVERE, String.format("Failed to populate default data in CR tables."), ex);
|
||||||
@ -529,7 +532,7 @@ public class RdbmsCentralRepoFactory {
|
|||||||
*
|
*
|
||||||
* @return SQL clause.
|
* @return SQL clause.
|
||||||
*/
|
*/
|
||||||
private static String getBigIntType(CentralRepoPlatforms selectedPlatform) {
|
static String getBigIntType(CentralRepoPlatforms selectedPlatform) {
|
||||||
switch (selectedPlatform) {
|
switch (selectedPlatform) {
|
||||||
case POSTGRESQL:
|
case POSTGRESQL:
|
||||||
return " BIGINT ";
|
return " BIGINT ";
|
||||||
@ -576,7 +579,6 @@ public class RdbmsCentralRepoFactory {
|
|||||||
stmt.execute(getCreateConfidenceTableStatement(selectedPlatform));
|
stmt.execute(getCreateConfidenceTableStatement(selectedPlatform));
|
||||||
stmt.execute(getCreateExaminersTableStatement(selectedPlatform));
|
stmt.execute(getCreateExaminersTableStatement(selectedPlatform));
|
||||||
stmt.execute(getCreatePersonaStatusTableStatement(selectedPlatform));
|
stmt.execute(getCreatePersonaStatusTableStatement(selectedPlatform));
|
||||||
stmt.execute(getCreateAliasesTableStatement(selectedPlatform));
|
|
||||||
|
|
||||||
stmt.execute(getCreatePersonasTableStatement(selectedPlatform));
|
stmt.execute(getCreatePersonasTableStatement(selectedPlatform));
|
||||||
stmt.execute(getCreatePersonaAliasTableStatement(selectedPlatform));
|
stmt.execute(getCreatePersonaAliasTableStatement(selectedPlatform));
|
||||||
@ -653,20 +655,6 @@ public class RdbmsCentralRepoFactory {
|
|||||||
+ ")";
|
+ ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the SQL String for creating a new aliases table in a central
|
|
||||||
* repository.
|
|
||||||
*
|
|
||||||
* @return SQL string for creating aliases table
|
|
||||||
*/
|
|
||||||
static String getCreateAliasesTableStatement(CentralRepoPlatforms selectedPlatform) {
|
|
||||||
|
|
||||||
return "CREATE TABLE IF NOT EXISTS aliases ("
|
|
||||||
+ getNumericPrimaryKeyClause("id", selectedPlatform)
|
|
||||||
+ "alias TEXT NOT NULL,"
|
|
||||||
+ "CONSTRAINT alias_unique UNIQUE(alias)"
|
|
||||||
+ ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the SQL String for creating a new accounts table in a central
|
* Get the SQL String for creating a new accounts table in a central
|
||||||
@ -719,13 +707,12 @@ public class RdbmsCentralRepoFactory {
|
|||||||
return "CREATE TABLE IF NOT EXISTS persona_alias ("
|
return "CREATE TABLE IF NOT EXISTS persona_alias ("
|
||||||
+ getNumericPrimaryKeyClause("id", selectedPlatform)
|
+ getNumericPrimaryKeyClause("id", selectedPlatform)
|
||||||
+ "persona_id " + getBigIntType(selectedPlatform) + " ,"
|
+ "persona_id " + getBigIntType(selectedPlatform) + " ,"
|
||||||
+ "alias_id " + getBigIntType(selectedPlatform) + " ,"
|
+ "alias TEXT NOT NULL, "
|
||||||
+ "justification TEXT NOT NULL,"
|
+ "justification TEXT NOT NULL,"
|
||||||
+ "confidence_id integer NOT NULL,"
|
+ "confidence_id integer NOT NULL,"
|
||||||
+ "date_added " + getBigIntType(selectedPlatform) + " ,"
|
+ "date_added " + getBigIntType(selectedPlatform) + " ,"
|
||||||
+ "examiner_id integer NOT NULL,"
|
+ "examiner_id integer NOT NULL,"
|
||||||
+ "FOREIGN KEY (persona_id) REFERENCES personas(id),"
|
+ "FOREIGN KEY (persona_id) REFERENCES personas(id),"
|
||||||
+ "FOREIGN KEY (alias_id) REFERENCES aliases(id),"
|
|
||||||
+ "FOREIGN KEY (confidence_id) REFERENCES confidence(confidence_id),"
|
+ "FOREIGN KEY (confidence_id) REFERENCES confidence(confidence_id),"
|
||||||
+ "FOREIGN KEY (examiner_id) REFERENCES examiners(id)"
|
+ "FOREIGN KEY (examiner_id) REFERENCES examiners(id)"
|
||||||
+ ")";
|
+ ")";
|
||||||
@ -779,6 +766,33 @@ 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.
|
* Inserts the default content in persona related tables.
|
||||||
*
|
*
|
||||||
@ -786,12 +800,9 @@ public class RdbmsCentralRepoFactory {
|
|||||||
*
|
*
|
||||||
* @return True if success, false otherwise.
|
* @return True if success, false otherwise.
|
||||||
*/
|
*/
|
||||||
private boolean insertDefaultPersonaTablesContent(Connection conn) {
|
private static boolean insertDefaultPersonaTablesContent(Connection conn, CentralRepoPlatforms selectedPlatform) {
|
||||||
|
|
||||||
Statement stmt = null;
|
try (Statement stmt = conn.createStatement()) {
|
||||||
try {
|
|
||||||
stmt = conn.createStatement();
|
|
||||||
|
|
||||||
// populate the confidence table
|
// populate the confidence table
|
||||||
for (Confidence confidence : Persona.Confidence.values()) {
|
for (Confidence confidence : Persona.Confidence.values()) {
|
||||||
String sqlString = "INSERT INTO confidence (confidence_id, description) VALUES ( " + confidence.getLevel() + ", '" + confidence.toString() + "')" //NON-NLS
|
String sqlString = "INSERT INTO confidence (confidence_id, description) VALUES ( " + confidence.getLevel() + ", '" + confidence.toString() + "')" //NON-NLS
|
||||||
@ -806,27 +817,38 @@ public class RdbmsCentralRepoFactory {
|
|||||||
stmt.execute(sqlString);
|
stmt.execute(sqlString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, String.format("Failed to populate default data in Persona tables."), ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
// Populate the account_types table
|
||||||
for (Account.Type type : Account.Type.PREDEFINED_ACCOUNT_TYPES) {
|
for (Account.Type type : Account.Type.PREDEFINED_ACCOUNT_TYPES) {
|
||||||
int correlationTypeId = getCorrelationTypeIdForAccountType(conn, type);
|
int correlationTypeId = getCorrelationTypeIdForAccountType(conn, type);
|
||||||
if (correlationTypeId > 0) {
|
if (correlationTypeId > 0) {
|
||||||
String sqlString = String.format("INSERT INTO account_types (type_name, display_name, correlation_type_id) VALUES ('%s', '%s', %d)" + getOnConflictDoNothingClause(selectedPlatform),
|
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);
|
type.getTypeName(), type.getDisplayName(), correlationTypeId);
|
||||||
stmt.execute(sqlString);
|
stmt.execute(sqlString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
LOGGER.log(Level.SEVERE, String.format("Failed to populate default data in Persona tables."), ex);
|
LOGGER.log(Level.SEVERE, String.format("Failed to populate default data in account_types table."), ex);
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
|
||||||
if (stmt != null) {
|
|
||||||
try {
|
|
||||||
stmt.close();
|
|
||||||
} catch (SQLException ex2) {
|
|
||||||
LOGGER.log(Level.SEVERE, "Error closing statement.", ex2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -841,7 +863,7 @@ public class RdbmsCentralRepoFactory {
|
|||||||
* '
|
* '
|
||||||
* @return correlation type id.
|
* @return correlation type id.
|
||||||
*/
|
*/
|
||||||
private int getCorrelationTypeIdForAccountType(Connection conn, Account.Type accountType) {
|
static int getCorrelationTypeIdForAccountType(Connection conn, Account.Type accountType) {
|
||||||
|
|
||||||
int typeId = -1;
|
int typeId = -1;
|
||||||
if (accountType == Account.Type.EMAIL) {
|
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
|
* NOTE: This is public scope because the options panel calls it directly to
|
||||||
* set/get
|
* 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
|
public final static String DEFAULT_DBNAME = "central_repository.db"; // NON-NLS
|
||||||
private final static Logger LOGGER = Logger.getLogger(SqliteCentralRepoSettings.class.getName());
|
private final static Logger LOGGER = Logger.getLogger(SqliteCentralRepoSettings.class.getName());
|
||||||
@ -45,7 +45,7 @@ public final class SqliteCentralRepoSettings implements CentralRepoDbSettings {
|
|||||||
private final static String JDBC_DRIVER = "org.sqlite.JDBC"; // NON-NLS
|
private final static String JDBC_DRIVER = "org.sqlite.JDBC"; // NON-NLS
|
||||||
private final static String JDBC_BASE_URI = "jdbc:sqlite:"; // NON-NLS
|
private final static String JDBC_BASE_URI = "jdbc:sqlite:"; // NON-NLS
|
||||||
private final static String VALIDATION_QUERY = "SELECT count(*) from sqlite_master"; // NON-NLS
|
private final static String VALIDATION_QUERY = "SELECT count(*) from sqlite_master"; // NON-NLS
|
||||||
|
|
||||||
private final static String DB_NAMES_REGEX = "[a-z][a-z0-9_]*(\\.db)?";
|
private final static String DB_NAMES_REGEX = "[a-z][a-z0-9_]*(\\.db)?";
|
||||||
private String dbName;
|
private String dbName;
|
||||||
private String dbDirectory;
|
private String dbDirectory;
|
||||||
@ -80,11 +80,11 @@ public final class SqliteCentralRepoSettings implements CentralRepoDbSettings {
|
|||||||
this.bulkThreshold = RdbmsCentralRepo.DEFAULT_BULK_THRESHHOLD;
|
this.bulkThreshold = RdbmsCentralRepo.DEFAULT_BULK_THRESHHOLD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("SqliteCentralRepoSettings: [db type: sqlite, directory: %s, name: %s]", getDbDirectory(), getDbName());
|
return String.format("SqliteCentralRepoSettings: [db type: sqlite, directory: %s, name: %s]", getDbDirectory(), getDbName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sets database directory and name to defaults
|
* sets database directory and name to defaults
|
||||||
*/
|
*/
|
||||||
@ -115,13 +115,11 @@ public final class SqliteCentralRepoSettings implements CentralRepoDbSettings {
|
|||||||
return (!dbFile.isDirectory());
|
return (!dbFile.isDirectory());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean verifyDatabaseExists() {
|
public boolean verifyDatabaseExists() {
|
||||||
return dbDirectoryExists();
|
return dbDirectoryExists();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that the db directory path exists.
|
* 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
|
* creates database directory for sqlite database if it does not exist
|
||||||
|
*
|
||||||
* @return whether or not operation occurred successfully
|
* @return whether or not operation occurred successfully
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@ -150,7 +149,6 @@ public final class SqliteCentralRepoSettings implements CentralRepoDbSettings {
|
|||||||
return createDbDirectory();
|
return createDbDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the db directory if it does not exist.
|
* Create the db directory if it does not exist.
|
||||||
*
|
*
|
||||||
@ -354,4 +352,21 @@ public final class SqliteCentralRepoSettings implements CentralRepoDbSettings {
|
|||||||
String getJDBCBaseURI() {
|
String getJDBCBaseURI() {
|
||||||
return JDBC_BASE_URI;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,5 +8,5 @@ IngestEventsListener.prevExists.text=Previously Seen Devices (Central Repository
|
|||||||
IngestEventsListener.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)
|
IngestEventsListener.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)
|
||||||
Installer.centralRepoUpgradeFailed.title=Central repository disabled
|
Installer.centralRepoUpgradeFailed.title=Central repository disabled
|
||||||
Installer.initialCreateSqlite.messageDesc=It will store information about all hashes and identifiers that you process. You can use this to ignore previously seen files and make connections between cases.
|
Installer.initialCreateSqlite.messageDesc=It will store information about all hashes and identifiers that you process. You can use this to ignore previously seen files and make connections between cases.
|
||||||
Installer.initialCreateSqlite.messageHeader=The Central Repository is not enabled. Would you like to?
|
Installer.initialCreateSqlite.messageHeader=The Central Repository is not enabled. Would you like to enable it?
|
||||||
Installer.initialCreateSqlite.title=Enable Central Repository?
|
Installer.initialCreateSqlite.title=Enable Central Repository?
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Central Repository
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2015-2017 Basis Technology Corp.
|
* Copyright 2017-2020 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -32,19 +32,40 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
|
|||||||
import org.sleuthkit.autopsy.core.RuntimeProperties;
|
import org.sleuthkit.autopsy.core.RuntimeProperties;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Version;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Install event listeners during module initialization
|
* Adds/removes application event listeners responsible for adding data to the
|
||||||
|
* central repository, sets up a default, single-user SQLite central repository
|
||||||
|
* if no central repository is configured, and updates the central repository
|
||||||
|
* schema as required.
|
||||||
|
*
|
||||||
|
* TODO (Jira-6108): At first glance, this package seems to have become a rather
|
||||||
|
* strange package for the "package installer" for the CR to reside in. The
|
||||||
|
* org.sleuthkit.autopsy.centralrepository package would seem to be more
|
||||||
|
* appropriate with so much going on. However, having a central repository
|
||||||
|
* schema update occur in a "package installer" with no user feedback is not
|
||||||
|
* optimal. Furthermore, for a multi-user (collaborative) installation, a schema
|
||||||
|
* update should be done in a more controlled way by acquiring an exclusive
|
||||||
|
* coordination service lock and requiring shared locks to be acquired by nodes
|
||||||
|
* with open cases.
|
||||||
*/
|
*/
|
||||||
public class Installer extends ModuleInstall {
|
public class Installer extends ModuleInstall {
|
||||||
|
|
||||||
private static final Logger LOGGER = Logger.getLogger(Installer.class.getName());
|
private static final Logger logger = Logger.getLogger(Installer.class.getName());
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private final CaseEventListener pcl = new CaseEventListener();
|
|
||||||
private final IngestEventsListener ieListener = new IngestEventsListener();
|
|
||||||
|
|
||||||
private static Installer instance;
|
private static Installer instance;
|
||||||
|
private final CaseEventListener caseEventListener = new CaseEventListener();
|
||||||
|
private final IngestEventsListener ingestEventListener = new IngestEventsListener();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the singleton "package installer" used by the registered Installer
|
||||||
|
* for the Autopsy-Core module located in the org.sleuthkit.autopsy.core
|
||||||
|
* package.
|
||||||
|
*
|
||||||
|
* @return The "package installer" singleton for the
|
||||||
|
* org.sleuthkit.autopsy.centralrepository.eventlisteners package.
|
||||||
|
*/
|
||||||
public synchronized static Installer getDefault() {
|
public synchronized static Installer getDefault() {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
instance = new Installer();
|
instance = new Installer();
|
||||||
@ -52,28 +73,64 @@ public class Installer extends ModuleInstall {
|
|||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the singleton "package installer" used by the registered
|
||||||
|
* Installer for the Autopsy-Core module located in the
|
||||||
|
* org.sleuthkit.autopsy.core package.
|
||||||
|
*/
|
||||||
private Installer() {
|
private Installer() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adds/removes application event listeners responsible for adding data to
|
||||||
|
* the central repository, sets up a default, single-user SQLite central
|
||||||
|
* repository if no central repository is configured, and updates the
|
||||||
|
* central repository schema as required.
|
||||||
|
*
|
||||||
|
* Called by the registered Installer for the Autopsy-Core module located in
|
||||||
|
* the org.sleuthkit.autopsy.core package when the already installed
|
||||||
|
* Autopsy-Core module is restored (during application startup).
|
||||||
|
*/
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"Installer.initialCreateSqlite.title=Enable Central Repository?",
|
"Installer.initialCreateSqlite.title=Enable Central Repository?",
|
||||||
"Installer.initialCreateSqlite.messageHeader=The Central Repository is not enabled. Would you like to enable it?",
|
"Installer.initialCreateSqlite.messageHeader=The Central Repository is not enabled. Would you like to enable it?",
|
||||||
"Installer.initialCreateSqlite.messageDesc=It will store information about all hashes and identifiers that you process. " +
|
"Installer.initialCreateSqlite.messageDesc=It will store information about all hashes and identifiers that you process. "
|
||||||
"You can use this to ignore previously seen files and make connections between cases."
|
+ "You can use this to ignore previously seen files and make connections between cases."
|
||||||
})
|
})
|
||||||
@Override
|
@Override
|
||||||
public void restored() {
|
public void restored() {
|
||||||
Case.addPropertyChangeListener(pcl);
|
addApplicationEventListeners();
|
||||||
ieListener.installListeners();
|
|
||||||
|
|
||||||
|
if (Version.getBuildType() == Version.Type.RELEASE) {
|
||||||
|
setupDefaultCentralRepository();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCentralRepoSchema();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the application event listeners responsible for adding data to the
|
||||||
|
* central repository.
|
||||||
|
*/
|
||||||
|
private void addApplicationEventListeners() {
|
||||||
|
Case.addPropertyChangeListener(caseEventListener);
|
||||||
|
ingestEventListener.installListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the central repository has been set up and configured. If not,
|
||||||
|
* either offers to perform set up (running with a GUI) or does the set up
|
||||||
|
* unconditionally (not running with a GUI, e.g., in an automated ingest
|
||||||
|
* node).
|
||||||
|
*/
|
||||||
|
private void setupDefaultCentralRepository() {
|
||||||
Map<String, String> centralRepoSettings = ModuleSettings.getConfigSettings("CentralRepository");
|
Map<String, String> centralRepoSettings = ModuleSettings.getConfigSettings("CentralRepository");
|
||||||
String initializedStr = centralRepoSettings.get("initialized");
|
String initializedStr = centralRepoSettings.get("initialized");
|
||||||
|
|
||||||
// check to see if the repo has been initialized asking to setup cr
|
// check to see if the repo has been initialized asking to setup cr
|
||||||
boolean initialized = Boolean.parseBoolean(initializedStr);
|
boolean initialized = Boolean.parseBoolean(initializedStr);
|
||||||
|
|
||||||
// if it hasn't received that flag, check for a previous install where cr is already setup
|
// if it hasn't received that flag, check for a previous install where cr is already setup
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
boolean prevRepo = Boolean.parseBoolean(centralRepoSettings.get("db.useCentralRepo"));
|
boolean prevRepo = Boolean.parseBoolean(centralRepoSettings.get("db.useCentralRepo"));
|
||||||
@ -91,92 +148,114 @@ public class Installer extends ModuleInstall {
|
|||||||
try {
|
try {
|
||||||
SwingUtilities.invokeAndWait(() -> {
|
SwingUtilities.invokeAndWait(() -> {
|
||||||
try {
|
try {
|
||||||
String dialogText =
|
String dialogText
|
||||||
"<html><body>" +
|
= "<html><body>"
|
||||||
"<div style='width: 400px;'>" +
|
+ "<div style='width: 400px;'>"
|
||||||
"<p>" + NbBundle.getMessage(this.getClass(), "Installer.initialCreateSqlite.messageHeader") + "</p>" +
|
+ "<p>" + NbBundle.getMessage(this.getClass(), "Installer.initialCreateSqlite.messageHeader") + "</p>"
|
||||||
"<p style='margin-top: 10px'>" + NbBundle.getMessage(this.getClass(), "Installer.initialCreateSqlite.messageDesc") + "</p>" +
|
+ "<p style='margin-top: 10px'>" + NbBundle.getMessage(this.getClass(), "Installer.initialCreateSqlite.messageDesc") + "</p>"
|
||||||
"</div>" +
|
+ "</div>"
|
||||||
"</body></html>";
|
+ "</body></html>";
|
||||||
|
|
||||||
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(),
|
if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(WindowManager.getDefault().getMainWindow(),
|
||||||
dialogText,
|
dialogText,
|
||||||
NbBundle.getMessage(this.getClass(), "Installer.initialCreateSqlite.title"),
|
NbBundle.getMessage(this.getClass(), "Installer.initialCreateSqlite.title"),
|
||||||
JOptionPane.YES_NO_OPTION)) {
|
JOptionPane.YES_NO_OPTION)) {
|
||||||
|
|
||||||
setupDefaultSqlite();
|
setupDefaultSqliteCentralRepo();
|
||||||
}
|
}
|
||||||
} catch (CentralRepoException ex) {
|
} catch (CentralRepoException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "There was an error while initializing the central repository database", ex);
|
logger.log(Level.SEVERE, "There was an error while initializing the central repository database", ex);
|
||||||
|
|
||||||
reportUpgradeError(ex);
|
doMessageBoxIfRunningInGUI(ex);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (InterruptedException | InvocationTargetException ex) {
|
} catch (InterruptedException | InvocationTargetException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "There was an error while running the swing utility invoke later while creating the central repository database", ex);
|
logger.log(Level.SEVERE, "There was an error while running the swing utility invoke later while creating the central repository database", ex);
|
||||||
}
|
}
|
||||||
} // if no GUI, just initialize
|
} // if no GUI, just initialize
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
setupDefaultSqlite();
|
setupDefaultSqliteCentralRepo();
|
||||||
} catch (CentralRepoException ex) {
|
} catch (CentralRepoException ex) {
|
||||||
LOGGER.log(Level.SEVERE, "There was an error while initializing the central repository database", ex);
|
logger.log(Level.SEVERE, "There was an error while initializing the central repository database", ex);
|
||||||
|
|
||||||
reportUpgradeError(ex);
|
doMessageBoxIfRunningInGUI(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleSettings.setConfigSetting("CentralRepository", "initialized", "true");
|
ModuleSettings.setConfigSetting("CentralRepository", "initialized", "true");
|
||||||
}
|
|
||||||
|
|
||||||
// now run regular module startup code
|
|
||||||
try {
|
|
||||||
CentralRepoDbManager.upgradeDatabase();
|
|
||||||
} catch (CentralRepoException ex) {
|
|
||||||
LOGGER.log(Level.SEVERE, "There was an error while upgrading the central repository database", ex);
|
|
||||||
if (RuntimeProperties.runningWithGUI()) {
|
|
||||||
reportUpgradeError(ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupDefaultSqlite() throws CentralRepoException {
|
/**
|
||||||
|
* Sets up a default single-user SQLite central repository.
|
||||||
|
*
|
||||||
|
* @throws CentralRepoException If there is an error setting up teh central
|
||||||
|
* repository.
|
||||||
|
*/
|
||||||
|
private void setupDefaultSqliteCentralRepo() throws CentralRepoException {
|
||||||
CentralRepoDbManager manager = new CentralRepoDbManager();
|
CentralRepoDbManager manager = new CentralRepoDbManager();
|
||||||
manager.setupDefaultSqliteDb();
|
manager.setupDefaultSqliteDb();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NbBundle.Messages({ "Installer.centralRepoUpgradeFailed.title=Central repository disabled" })
|
/**
|
||||||
private void reportUpgradeError(CentralRepoException ex) {
|
* Update the central repository schema.
|
||||||
|
*/
|
||||||
|
private void updateCentralRepoSchema() {
|
||||||
try {
|
try {
|
||||||
SwingUtilities.invokeAndWait(() -> {
|
CentralRepoDbManager.upgradeDatabase();
|
||||||
JOptionPane.showMessageDialog(null,
|
} catch (CentralRepoException ex) {
|
||||||
ex.getUserMessage(),
|
logger.log(Level.SEVERE, "An error occurred updating the central repository schema", ex);
|
||||||
NbBundle.getMessage(this.getClass(),
|
if (RuntimeProperties.runningWithGUI()) {
|
||||||
"Installer.centralRepoUpgradeFailed.title"),
|
doMessageBoxIfRunningInGUI(ex);
|
||||||
JOptionPane.ERROR_MESSAGE);
|
}
|
||||||
});
|
|
||||||
} catch (InterruptedException | InvocationTargetException e) {
|
|
||||||
LOGGER.log(Level.WARNING, e.getMessage(), e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public boolean closing() {
|
* Display a central repository exception in a message box if running with a
|
||||||
//platform about to close
|
* GUI.
|
||||||
|
*
|
||||||
return true;
|
* @param ex The exception.
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({"Installer.centralRepoUpgradeFailed.title=Central repository disabled"})
|
||||||
|
private void doMessageBoxIfRunningInGUI(CentralRepoException ex) {
|
||||||
|
if (RuntimeProperties.runningWithGUI()) {
|
||||||
|
try {
|
||||||
|
SwingUtilities.invokeAndWait(() -> {
|
||||||
|
JOptionPane.showMessageDialog(null,
|
||||||
|
ex.getUserMessage(),
|
||||||
|
NbBundle.getMessage(this.getClass(), "Installer.centralRepoUpgradeFailed.title"),
|
||||||
|
JOptionPane.ERROR_MESSAGE);
|
||||||
|
});
|
||||||
|
} catch (InterruptedException | InvocationTargetException e) {
|
||||||
|
logger.log(Level.WARNING, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void uninstalled() {
|
public void uninstalled() {
|
||||||
//module is being unloaded
|
/*
|
||||||
|
* TODO (Jira-6108): This code is erronoeous. As documented at
|
||||||
Case.removePropertyChangeListener(pcl);
|
* http://bits.netbeans.org/dev/javadoc/org-openide-modules/org/openide/modules/ModuleInstall.html#uninstalled--
|
||||||
pcl.shutdown();
|
*
|
||||||
ieListener.shutdown();
|
* "Called when the module is disabled while the application is still
|
||||||
ieListener.uninstallListeners();
|
* running. Should remove whatever functionality that it had registered
|
||||||
|
* in ModuleInstall.restored().
|
||||||
// TODO: remove thread pool
|
*
|
||||||
|
* Beware: in practice there is no way to
|
||||||
|
* ensure that this method will really be called. The module might
|
||||||
|
* simply be deleted or disabled while the application is not running.
|
||||||
|
* In fact this is always the case in NetBeans 6.0; the Plugin Manager
|
||||||
|
* only uninstalls or disables modules between restarts. This method
|
||||||
|
* will still be called if you reload a module during development."
|
||||||
|
*
|
||||||
|
* THIS CODE IS NEVER EXECUTED.
|
||||||
|
*/
|
||||||
|
Case.removePropertyChangeListener(caseEventListener);
|
||||||
|
caseEventListener.shutdown();
|
||||||
|
ingestEventListener.shutdown();
|
||||||
|
ingestEventListener.uninstallListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
|
|||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeUtil;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms;
|
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.centralrepository.eventlisteners.IngestEventsListener;
|
||||||
import org.sleuthkit.autopsy.core.RuntimeProperties;
|
import org.sleuthkit.autopsy.core.RuntimeProperties;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
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
|
// Don't allow sqlite central repo databases to be used for multi user cases
|
||||||
if ((autopsyCase.getCaseType() == Case.CaseType.MULTI_USER_CASE)
|
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.");
|
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
|
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.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.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.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.databaseConnectionFailed.title=Database Connection Failed
|
||||||
EamDbSettingsDialog.okButton.errorMsg.text=Please restart Autopsy to begin using the new database platform.
|
EamDbSettingsDialog.okButton.errorMsg.text=Please restart Autopsy to begin using the new database platform.
|
||||||
EamDbSettingsDialog.okButton.errorTitle.text=Restart Required.
|
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.
|
EamDbSettingsDialog.validation.incompleteFields=Fill in all values for the selected database.
|
||||||
EamOptionsController.moduleErr=Error processing value changes.
|
EamOptionsController.moduleErr=Error processing value changes.
|
||||||
EamOptionsController.moduleErr.msg=Value change processing failed.
|
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.updateFailed.title=Central repository disabled
|
||||||
GlobalSettingsPanel.validationErrMsg.ingestRunning=You cannot change settings while ingest is running.
|
GlobalSettingsPanel.validationErrMsg.ingestRunning=You cannot change settings while ingest is running.
|
||||||
GlobalSettingsPanel.validationerrMsg.mustConfigure=Configure the database to enable this module.
|
GlobalSettingsPanel.validationerrMsg.mustConfigure=Configure the database to enable this module.
|
||||||
|
@ -138,16 +138,16 @@
|
|||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
|
<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">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
<Component id="tfDatabasePath" min="-2" max="-2" attributes="0"/>
|
<Component id="tfDatabasePath" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||||
<Component id="bnDatabasePathFileOpen" min="-2" max="-2" attributes="0"/>
|
<Component id="bnDatabasePathFileOpen" min="-2" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
<Component id="cbDatabaseType" min="-2" max="-2" attributes="0"/>
|
<Component id="cbDatabaseType" min="-2" pref="210" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="32767" attributes="0"/>
|
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||||
<Component id="lbSingleUserSqLite" min="-2" max="-2" attributes="0"/>
|
<Component id="lbSingleUserSqLite" pref="0" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<Component id="jpDbPassword" alignment="0" min="-2" max="-2" attributes="0"/>
|
<Component id="jpDbPassword" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="tbDbUsername" 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">
|
<Component class="javax.swing.JComboBox" name="cbDatabaseType">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
<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>
|
||||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
<Dimension value="[120, 20]"/>
|
<Dimension value="[120, 20]"/>
|
||||||
@ -330,7 +330,7 @@
|
|||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbDatabaseTypeActionPerformed"/>
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbDatabaseTypeActionPerformed"/>
|
||||||
</Events>
|
</Events>
|
||||||
<AuxValues>
|
<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>
|
</AuxValues>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JLabel" name="lbSingleUserSqLite">
|
<Component class="javax.swing.JLabel" name="lbSingleUserSqLite">
|
||||||
|
@ -19,25 +19,31 @@
|
|||||||
package org.sleuthkit.autopsy.centralrepository.optionspanel;
|
package org.sleuthkit.autopsy.centralrepository.optionspanel;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
import java.awt.Cursor;
|
import java.awt.Cursor;
|
||||||
|
import java.awt.HeadlessException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.JFileChooser;
|
import javax.swing.JFileChooser;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JList;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.JTextField;
|
import javax.swing.JTextField;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.event.DocumentEvent;
|
import javax.swing.event.DocumentEvent;
|
||||||
import javax.swing.event.DocumentListener;
|
import javax.swing.event.DocumentListener;
|
||||||
import javax.swing.filechooser.FileFilter;
|
import javax.swing.filechooser.FileFilter;
|
||||||
|
import javax.swing.plaf.basic.BasicComboBoxRenderer;
|
||||||
import org.netbeans.spi.options.OptionsPanelController;
|
import org.netbeans.spi.options.OptionsPanelController;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.NbBundle.Messages;
|
import org.openide.util.NbBundle.Messages;
|
||||||
import org.openide.windows.WindowManager;
|
import org.openide.windows.WindowManager;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbChoice;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbManager;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbManager;
|
||||||
import org.sleuthkit.autopsy.corecomponents.TextPrompt;
|
import org.sleuthkit.autopsy.corecomponents.TextPrompt;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
@ -45,8 +51,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
|
|||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.DatabaseTestResult;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.DatabaseTestResult;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteCentralRepoSettings;
|
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.
|
* Configuration dialog for Central Repository database settings.
|
||||||
@ -57,11 +61,42 @@ public class EamDbSettingsDialog extends JDialog {
|
|||||||
private static final Logger logger = Logger.getLogger(EamDbSettingsDialog.class.getName());
|
private static final Logger logger = Logger.getLogger(EamDbSettingsDialog.class.getName());
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
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 BasicComboBoxRenderer {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public Component getListCellRendererComponent(JList list, Object value,
|
||||||
|
int index, boolean isSelected, boolean cellHasFocus) {
|
||||||
|
|
||||||
|
CentralRepoDbChoice item = (CentralRepoDbChoice) value;
|
||||||
|
|
||||||
|
// disable cell if it is the db connection from multi user settings
|
||||||
|
// and that option is not enabled in multi user settings
|
||||||
|
setText(item.getTitle());
|
||||||
|
setEnabled(isDbChoiceSelectable(item));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private final Collection<JTextField> textBoxes;
|
private final Collection<JTextField> textBoxes;
|
||||||
private final TextBoxChangedListener textBoxChangedListener;
|
private final TextBoxChangedListener textBoxChangedListener;
|
||||||
private final CentralRepoDbManager manager = new CentralRepoDbManager();
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new form EamDbSettingsDialog
|
* Creates new form EamDbSettingsDialog
|
||||||
*/
|
*/
|
||||||
@ -69,7 +104,7 @@ public class EamDbSettingsDialog extends JDialog {
|
|||||||
"EamDbSettingsDialog.lbSingleUserSqLite.text=SQLite should only be used by one examiner at a time.",
|
"EamDbSettingsDialog.lbSingleUserSqLite.text=SQLite should only be used by one examiner at a time.",
|
||||||
"EamDbSettingsDialog.lbDatabaseType.text=Database Type :",
|
"EamDbSettingsDialog.lbDatabaseType.text=Database Type :",
|
||||||
"EamDbSettingsDialog.fcDatabasePath.title=Select location for central_repository.db"})
|
"EamDbSettingsDialog.fcDatabasePath.title=Select location for central_repository.db"})
|
||||||
public EamDbSettingsDialog() {
|
public EamDbSettingsDialog(CentralRepoDbChoice initialMenuItem) {
|
||||||
super((JFrame) WindowManager.getDefault().getMainWindow(),
|
super((JFrame) WindowManager.getDefault().getMainWindow(),
|
||||||
Bundle.EamDbSettingsDialog_title_text(),
|
Bundle.EamDbSettingsDialog_title_text(),
|
||||||
true);
|
true);
|
||||||
@ -95,29 +130,45 @@ public class EamDbSettingsDialog extends JDialog {
|
|||||||
return "Directories and Central Repository databases";
|
return "Directories and Central Repository databases";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
cbDatabaseType.setSelectedItem(manager.getSelectedPlatform());
|
|
||||||
customizeComponents();
|
setupDbChoice(initialMenuItem);
|
||||||
valid();
|
valid();
|
||||||
display();
|
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;
|
||||||
|
|
||||||
|
// set the renderer so item is unselectable if inappropriate
|
||||||
|
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.)
|
* This method 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
|
* @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",
|
@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.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.title=Database Does Not Exist",
|
||||||
"EamDbSettingsDialog.okButton.createDbDialog.message=Database does not exist, would you like to create it?",
|
"EamDbSettingsDialog.okButton.createDbDialog.message=Database does not exist, would you like to create it?",
|
||||||
"EamDbSettingsDialog.okButton.databaseConnectionFailed.title=Database Connection Failed",
|
"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.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.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"})
|
"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) {
|
if (manager.getStatus() == DatabaseTestResult.CONNECTION_FAILED) {
|
||||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
||||||
Bundle.EamDbSettingsDialog_okButton_databaseConnectionFailed_message(),
|
Bundle.EamDbSettingsDialog_okButton_databaseConnectionFailed_message(),
|
||||||
@ -135,36 +186,49 @@ public class EamDbSettingsDialog extends JDialog {
|
|||||||
Bundle.EamDbSettingsDialog_okButton_createDbDialog_message(),
|
Bundle.EamDbSettingsDialog_okButton_createDbDialog_message(),
|
||||||
Bundle.EamDbSettingsDialog_okButton_createDbDialog_title(),
|
Bundle.EamDbSettingsDialog_okButton_createDbDialog_title(),
|
||||||
JOptionPane.YES_NO_OPTION)) {
|
JOptionPane.YES_NO_OPTION)) {
|
||||||
try {
|
onUserPromptCreateDb(manager, dialog);
|
||||||
manager.createDb();
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(),
|
|
||||||
errorMessage,
|
|
||||||
Bundle.EamDbSettingsDialog_okButton_createDbError_title(),
|
|
||||||
JOptionPane.WARNING_MESSAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
valid();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (manager.getStatus() == DatabaseTestResult.TESTEDOK);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -281,7 +345,7 @@ public class EamDbSettingsDialog extends JDialog {
|
|||||||
|
|
||||||
jpDbPassword.setPreferredSize(new java.awt.Dimension(509, 20));
|
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.setPreferredSize(new java.awt.Dimension(120, 20));
|
||||||
cbDatabaseType.addActionListener(new java.awt.event.ActionListener() {
|
cbDatabaseType.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
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(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)
|
.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)
|
.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)))
|
.addComponent(lbUserPassword, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
|
||||||
.addGap(10, 10, 10)
|
.addGap(10, 10, 10)
|
||||||
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(pnSQLiteSettingsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||||
.addGroup(pnSQLiteSettingsLayout.createSequentialGroup()
|
.addGroup(pnSQLiteSettingsLayout.createSequentialGroup()
|
||||||
.addComponent(tfDatabasePath, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
.addComponent(tfDatabasePath, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
.addComponent(bnDatabasePathFileOpen))
|
.addComponent(bnDatabasePathFileOpen))
|
||||||
.addGroup(pnSQLiteSettingsLayout.createSequentialGroup()
|
.addGroup(pnSQLiteSettingsLayout.createSequentialGroup()
|
||||||
.addComponent(cbDatabaseType, 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.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
.addComponent(lbSingleUserSqLite, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
.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(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(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)
|
.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();
|
setTextPrompts();
|
||||||
setTextBoxListeners();
|
setTextBoxListeners();
|
||||||
manager.clearStatus();
|
manager.clearStatus();
|
||||||
if (manager.getSelectedPlatform() == CentralRepoPlatforms.SQLITE) {
|
if (manager.getSelectedDbChoice() == CentralRepoDbChoice.SQLITE) {
|
||||||
updatePostgresFields(false);
|
updatePostgresFields(false);
|
||||||
updateSqliteFields(true);
|
updateSqliteFields(true);
|
||||||
}
|
}
|
||||||
else {
|
else if (manager.getSelectedDbChoice() == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
|
||||||
updatePostgresFields(true);
|
updatePostgresFields(true);
|
||||||
updateSqliteFields(false);
|
updateSqliteFields(false);
|
||||||
}
|
}
|
||||||
displayDatabaseSettings(CentralRepoPlatforms.POSTGRESQL.equals(manager.getSelectedPlatform()));
|
else {
|
||||||
|
updatePostgresFields(false);
|
||||||
|
updateSqliteFields(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
displayDatabaseSettings(manager.getSelectedDbChoice());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void display() {
|
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.errorMsg.text=Please restart Autopsy to begin using the new database platform.",
|
||||||
"EamDbSettingsDialog.okButton.connectionErrorMsg.text=Failed to connect to central repository database."})
|
"EamDbSettingsDialog.okButton.connectionErrorMsg.text=Failed to connect to central repository database."})
|
||||||
private void bnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOkActionPerformed
|
private void bnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOkActionPerformed
|
||||||
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
testStatusAndCreate(this, manager, this);
|
||||||
|
dispose();
|
||||||
|
}//GEN-LAST:event_bnOkActionPerformed
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
manager.testStatus();
|
||||||
valid();
|
|
||||||
|
|
||||||
boolean testedOk = promptTestStatusWarnings();
|
if (dialog != null)
|
||||||
|
dialog.valid();
|
||||||
|
|
||||||
|
boolean testedOk = promptTestStatusWarnings(manager, dialog);
|
||||||
if (!testedOk) {
|
if (!testedOk) {
|
||||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
@ -467,25 +562,26 @@ public class EamDbSettingsDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
catch (CentralRepoException e) {
|
catch (CentralRepoException e) {
|
||||||
SwingUtilities.invokeLater(() -> {
|
SwingUtilities.invokeLater(() -> {
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(parent,
|
||||||
Bundle.EamDbSettingsDialog_okButton_errorMsg_text(),
|
Bundle.EamDbSettingsDialog_okButton_errorMsg_text(),
|
||||||
Bundle.EamDbSettingsDialog_okButton_errorTitle_text(),
|
Bundle.EamDbSettingsDialog_okButton_errorTitle_text(),
|
||||||
JOptionPane.WARNING_MESSAGE);
|
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
|
* This method returns if changes to the central repository configuration were
|
||||||
* successfully applied
|
* successfully applied.
|
||||||
*
|
*
|
||||||
* @return true if the database configuration was successfully changed false
|
* @return True if the database configuration was successfully changed; false
|
||||||
* if it was not
|
* if it was not.
|
||||||
*/
|
*/
|
||||||
public boolean wasConfigurationChanged() {
|
public boolean wasConfigurationChanged() {
|
||||||
return manager.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
|
private void cbDatabaseTypeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbDatabaseTypeActionPerformed
|
||||||
manager.setSelectedPlatform((CentralRepoPlatforms) cbDatabaseType.getSelectedItem());
|
CentralRepoDbChoice selectedItem = (CentralRepoDbChoice) cbDatabaseType.getSelectedItem();
|
||||||
customizeComponents();
|
changeDbSelection(selectedItem);
|
||||||
}//GEN-LAST:event_cbDatabaseTypeActionPerformed
|
}//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() {
|
private void updateFullDbPath() {
|
||||||
dataBaseFileTextArea.setText(tfDatabasePath.getText() + File.separator + SqliteCentralRepoSettings.DEFAULT_DBNAME);
|
dataBaseFileTextArea.setText(tfDatabasePath.getText() + File.separator + SqliteCentralRepoSettings.DEFAULT_DBNAME);
|
||||||
dataBaseFileTextArea.setCaretPosition(dataBaseFileTextArea.getText().length());
|
dataBaseFileTextArea.setCaretPosition(dataBaseFileTextArea.getText().length());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void displayDatabaseSettings(boolean isPostgres) {
|
private void displayDatabaseSettings(CentralRepoDbChoice choice) {
|
||||||
lbDatabasePath.setVisible(!isPostgres);
|
boolean isSqlite = choice == CentralRepoDbChoice.SQLITE;
|
||||||
tfDatabasePath.setVisible(!isPostgres);
|
boolean isPostgres = choice == CentralRepoDbChoice.POSTGRESQL_CUSTOM;
|
||||||
lbDatabaseDesc.setVisible(!isPostgres);
|
|
||||||
dataBaseFileTextArea.setVisible(!isPostgres);
|
lbDatabasePath.setVisible(isSqlite);
|
||||||
lbSingleUserSqLite.setVisible(!isPostgres);
|
tfDatabasePath.setVisible(isSqlite);
|
||||||
bnDatabasePathFileOpen.setVisible(!isPostgres);
|
lbDatabaseDesc.setVisible(isSqlite);
|
||||||
|
dataBaseFileTextArea.setVisible(isSqlite);
|
||||||
|
lbSingleUserSqLite.setVisible(isSqlite);
|
||||||
|
bnDatabasePathFileOpen.setVisible(isSqlite);
|
||||||
|
|
||||||
lbHostName.setVisible(isPostgres);
|
lbHostName.setVisible(isPostgres);
|
||||||
tbDbHostname.setVisible(isPostgres);
|
tbDbHostname.setVisible(isPostgres);
|
||||||
lbPort.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."})
|
@Messages({"EamDbSettingsDialog.validation.incompleteFields=Fill in all values for the selected database."})
|
||||||
private boolean databaseFieldsArePopulated() {
|
private boolean databaseFieldsArePopulated() {
|
||||||
boolean result = true;
|
boolean result = true;
|
||||||
if (manager.getSelectedPlatform() == CentralRepoPlatforms.POSTGRESQL) {
|
if (manager.getSelectedDbChoice() == CentralRepoDbChoice.POSTGRESQL_CUSTOM) {
|
||||||
result = !tbDbHostname.getText().trim().isEmpty()
|
result = !tbDbHostname.getText().trim().isEmpty()
|
||||||
&& !tbDbPort.getText().trim().isEmpty()
|
&& !tbDbPort.getText().trim().isEmpty()
|
||||||
// && !tbDbName.getText().trim().isEmpty()
|
// && !tbDbName.getText().trim().isEmpty()
|
||||||
&& !tbDbUsername.getText().trim().isEmpty()
|
&& !tbDbUsername.getText().trim().isEmpty()
|
||||||
&& 0 < jpDbPassword.getPassword().length;
|
&& 0 < jpDbPassword.getPassword().length;
|
||||||
}
|
}
|
||||||
else if (manager.getSelectedPlatform() == CentralRepoPlatforms.SQLITE) {
|
else if (manager.getSelectedDbChoice() == CentralRepoDbChoice.SQLITE) {
|
||||||
result = !tfDatabasePath.getText().trim().isEmpty();
|
result = !tfDatabasePath.getText().trim().isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -722,7 +834,7 @@ public class EamDbSettingsDialog extends JDialog {
|
|||||||
private javax.swing.JButton bnDatabasePathFileOpen;
|
private javax.swing.JButton bnDatabasePathFileOpen;
|
||||||
private javax.swing.ButtonGroup bnGrpDatabasePlatforms;
|
private javax.swing.ButtonGroup bnGrpDatabasePlatforms;
|
||||||
private javax.swing.JButton bnOk;
|
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.JScrollPane dataBaseFileScrollPane;
|
||||||
private javax.swing.JTextArea dataBaseFileTextArea;
|
private javax.swing.JTextArea dataBaseFileTextArea;
|
||||||
private javax.swing.JFileChooser fcDatabasePath;
|
private javax.swing.JFileChooser fcDatabasePath;
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="pnDatabaseConfiguration" alignment="0" max="32767" attributes="0"/>
|
<Component id="pnDatabaseConfiguration" alignment="0" max="32767" attributes="0"/>
|
||||||
<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="organizationPanel" alignment="1" max="32767" attributes="0"/>
|
||||||
<Component id="casesPanel" alignment="0" max="32767" attributes="0"/>
|
<Component id="casesPanel" alignment="0" max="32767" attributes="0"/>
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
@ -258,7 +258,7 @@
|
|||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="1" attributes="0">
|
<Group type="102" alignment="1" attributes="0">
|
||||||
<Component id="correlationPropertiesScrollPane" pref="32" max="32767" attributes="0"/>
|
<Component id="correlationPropertiesScrollPane" pref="25" max="32767" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="bnManageTypes" min="-2" max="-2" attributes="0"/>
|
<Component id="bnManageTypes" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
|
<EmptySpace min="-2" pref="8" max="-2" attributes="0"/>
|
||||||
|
@ -33,33 +33,39 @@ import org.openide.util.NbBundle.Messages;
|
|||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbManager;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbManager;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoException;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms;
|
||||||
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
|
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
|
||||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
|
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbChoice;
|
||||||
import static org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoPlatforms.DISABLED;
|
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoDbUtil;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.PostgresCentralRepoSettings;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.PostgresCentralRepoSettings;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteCentralRepoSettings;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.SqliteCentralRepoSettings;
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main settings panel for the Central Repository
|
* Main settings panel for the Central Repository
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||||
public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel {
|
public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final Logger logger = Logger.getLogger(GlobalSettingsPanel.class.getName());
|
private static final Logger logger = Logger.getLogger(GlobalSettingsPanel.class.getName());
|
||||||
private static final Set<IngestManager.IngestJobEvent> INGEST_JOB_EVENTS_OF_INTEREST = EnumSet.of(IngestManager.IngestJobEvent.STARTED, IngestManager.IngestJobEvent.CANCELLED, IngestManager.IngestJobEvent.COMPLETED);
|
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;
|
private final IngestJobEventPropertyChangeListener ingestJobEventListener;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new form EamOptionsPanel
|
* Creates new form EamOptionsPanel
|
||||||
*/
|
*/
|
||||||
public GlobalSettingsPanel() {
|
public GlobalSettingsPanel() {
|
||||||
ingestJobEventListener = new IngestJobEventPropertyChangeListener();
|
ingestJobEventListener = new IngestJobEventPropertyChangeListener();
|
||||||
|
|
||||||
|
// listen for change events in currently saved choice
|
||||||
|
CentralRepoDbManager.addPropertyChangeListener((PropertyChangeEvent evt) -> ingestStateUpdated(Case.isCaseOpen()));
|
||||||
initComponents();
|
initComponents();
|
||||||
customizeComponents();
|
customizeComponents();
|
||||||
addIngestJobEventsListener();
|
addIngestJobEventsListener();
|
||||||
@ -68,7 +74,8 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
ingestStateUpdated(evt.getNewValue() != null);
|
ingestStateUpdated(evt.getNewValue() != null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void customizeComponents() {
|
private void customizeComponents() {
|
||||||
setName(NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.pnCorrelationProperties.border.title"));
|
setName(NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.pnCorrelationProperties.border.title"));
|
||||||
}
|
}
|
||||||
@ -78,26 +85,163 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
ingestStateUpdated(Case.isCaseOpen());
|
ingestStateUpdated(Case.isCaseOpen());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Messages({"GlobalSettingsPanel.updateFailed.title=Central repository disabled"})
|
|
||||||
private void updateDatabase() {
|
private void updateDatabase() {
|
||||||
|
updateDatabase(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (CentralRepoPlatforms.getSelectedPlatform().equals(DISABLED)) {
|
|
||||||
|
/**
|
||||||
|
* 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;
|
return;
|
||||||
}
|
}
|
||||||
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
parent.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
CentralRepoDbManager.upgradeDatabase();
|
CentralRepoDbManager.upgradeDatabase();
|
||||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||||
} catch (CentralRepoException ex) {
|
} catch (CentralRepoException ex) {
|
||||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
parent.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(parent,
|
||||||
ex.getUserMessage(),
|
ex.getUserMessage(),
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(GlobalSettingsPanel.class,
|
||||||
"GlobalSettingsPanel.updateFailed.title"),
|
"GlobalSettingsPanel.updateFailed.title"),
|
||||||
JOptionPane.WARNING_MESSAGE);
|
JOptionPane.WARNING_MESSAGE);
|
||||||
} finally {
|
} 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
|
private void bnDbConfigureActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnDbConfigureActionPerformed
|
||||||
store();
|
store();
|
||||||
EamDbSettingsDialog dialog = new EamDbSettingsDialog();
|
boolean changed = invokeCrChoice(this, null);
|
||||||
if (dialog.wasConfigurationChanged()) {
|
if (changed) {
|
||||||
updateDatabase();
|
|
||||||
load(); // reload db settings content and update buttons
|
load(); // reload db settings content and update buttons
|
||||||
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
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
|
private void cbUseCentralRepoActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbUseCentralRepoActionPerformed
|
||||||
//if saved setting is disabled checkbox should be disabled already
|
//if saved setting is disabled checkbox should be disabled already
|
||||||
store();
|
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();
|
updateDatabase();
|
||||||
load();
|
load();
|
||||||
this.ingestStateUpdated(Case.isCaseOpen());
|
this.ingestStateUpdated(Case.isCaseOpen());
|
||||||
@ -457,31 +610,35 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
|
|||||||
public void load() {
|
public void load() {
|
||||||
tbOops.setText("");
|
tbOops.setText("");
|
||||||
enableButtonSubComponents(false);
|
enableButtonSubComponents(false);
|
||||||
CentralRepoPlatforms selectedPlatform = CentralRepoPlatforms.getSelectedPlatform();
|
CentralRepoDbChoice selectedChoice = CentralRepoDbManager.getSavedDbChoice();
|
||||||
cbUseCentralRepo.setSelected(CentralRepoDbUtil.allowUseOfCentralRepository()); // NON-NLS
|
cbUseCentralRepo.setSelected(CentralRepoDbUtil.allowUseOfCentralRepository()); // NON-NLS
|
||||||
switch (selectedPlatform) {
|
|
||||||
case POSTGRESQL:
|
lbDbPlatformValue.setText(selectedChoice.getTitle());
|
||||||
PostgresCentralRepoSettings dbSettingsPg = new PostgresCentralRepoSettings();
|
CentralRepoPlatforms selectedDb = selectedChoice.getDbPlatform();
|
||||||
lbDbPlatformValue.setText(CentralRepoPlatforms.POSTGRESQL.toString());
|
|
||||||
lbDbNameValue.setText(dbSettingsPg.getDbName());
|
if (selectedChoice == null || selectedDb == CentralRepoPlatforms.DISABLED) {
|
||||||
lbDbLocationValue.setText(dbSettingsPg.getHost());
|
lbDbNameValue.setText("");
|
||||||
enableButtonSubComponents(cbUseCentralRepo.isSelected());
|
lbDbLocationValue.setText("");
|
||||||
break;
|
tbOops.setText(Bundle.GlobalSettingsPanel_validationerrMsg_mustConfigure());
|
||||||
case SQLITE:
|
}
|
||||||
|
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();
|
SqliteCentralRepoSettings dbSettingsSqlite = new SqliteCentralRepoSettings();
|
||||||
lbDbPlatformValue.setText(CentralRepoPlatforms.SQLITE.toString());
|
|
||||||
lbDbNameValue.setText(dbSettingsSqlite.getDbName());
|
lbDbNameValue.setText(dbSettingsSqlite.getDbName());
|
||||||
lbDbLocationValue.setText(dbSettingsSqlite.getDbDirectory());
|
lbDbLocationValue.setText(dbSettingsSqlite.getDbDirectory());
|
||||||
enableButtonSubComponents(cbUseCentralRepo.isSelected());
|
}
|
||||||
break;
|
|
||||||
default:
|
|
||||||
lbDbPlatformValue.setText(CentralRepoPlatforms.DISABLED.toString());
|
|
||||||
lbDbNameValue.setText("");
|
|
||||||
lbDbLocationValue.setText("");
|
|
||||||
tbOops.setText(Bundle.GlobalSettingsPanel_validationerrMsg_mustConfigure());
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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() {
|
public boolean valid() {
|
||||||
return !cbUseCentralRepo.isSelected() || !lbDbPlatformValue.getText().equals(DISABLED.toString());
|
return !cbUseCentralRepo.isSelected() || !lbDbPlatformValue.getText().equals(CentralRepoDbChoice.DISABLED.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -343,6 +343,7 @@ public class CommandLineIngestManager {
|
|||||||
* @param baseCaseName Case name
|
* @param baseCaseName Case name
|
||||||
* @param rootOutputDirectory Full path to directory in which case
|
* @param rootOutputDirectory Full path to directory in which case
|
||||||
* output folder will be created
|
* output folder will be created
|
||||||
|
* @param caseType Type of case being created
|
||||||
*
|
*
|
||||||
* @throws CaseActionException
|
* @throws CaseActionException
|
||||||
*/
|
*/
|
||||||
|
@ -168,3 +168,7 @@ MediaPlayerPanel.playBackSpeedLabel.text=Speed:
|
|||||||
SQLiteViewer.readTable.errorText=Error getting rows for table: {0}
|
SQLiteViewer.readTable.errorText=Error getting rows for table: {0}
|
||||||
# {0} - tableName
|
# {0} - tableName
|
||||||
SQLiteViewer.selectTable.errorText=Error getting row count for table: {0}
|
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
|
||||||
|
@ -241,7 +241,7 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
progressSlider.addChangeListener(new ChangeListener() {
|
progressSlider.addChangeListener(new ChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void stateChanged(ChangeEvent e) {
|
public void stateChanged(ChangeEvent e) {
|
||||||
if (progressSlider.getValueIsAdjusting()) {
|
if (progressSlider.getValueIsAdjusting() && gstPlayBin != null) {
|
||||||
long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
|
long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
|
||||||
double relativePosition = progressSlider.getValue() * 1.0 / PROGRESS_SLIDER_SIZE;
|
double relativePosition = progressSlider.getValue() * 1.0 / PROGRESS_SLIDER_SIZE;
|
||||||
long newStartTime = (long) (relativePosition * duration);
|
long newStartTime = (long) (relativePosition * duration);
|
||||||
@ -264,20 +264,23 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
//Manage the video while the user is performing actions on the track.
|
//Manage the video while the user is performing actions on the track.
|
||||||
progressSlider.addMouseListener(new MouseListener() {
|
progressSlider.addMouseListener(new MouseListener() {
|
||||||
private State previousState = State.NULL;
|
private State previousState = State.NULL;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mousePressed(MouseEvent e) {
|
public void mousePressed(MouseEvent e) {
|
||||||
previousState = gstPlayBin.getState();
|
if (gstPlayBin != null) {
|
||||||
gstPlayBin.pause();
|
previousState = gstPlayBin.getState();
|
||||||
|
gstPlayBin.pause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseReleased(MouseEvent e) {
|
public void mouseReleased(MouseEvent e) {
|
||||||
if(previousState.equals(State.PLAYING)) {
|
if (previousState.equals(State.PLAYING) && gstPlayBin != null) {
|
||||||
gstPlayBin.play();
|
gstPlayBin.play();
|
||||||
}
|
}
|
||||||
previousState = State.NULL;
|
previousState = State.NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseClicked(MouseEvent e) {
|
public void mouseClicked(MouseEvent e) {
|
||||||
}
|
}
|
||||||
@ -289,11 +292,11 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
@Override
|
@Override
|
||||||
public void mouseExited(MouseEvent e) {
|
public void mouseExited(MouseEvent e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
//Manage the audio level when the user is adjusting the volume slider
|
//Manage the audio level when the user is adjusting the volume slider
|
||||||
audioSlider.addChangeListener((ChangeEvent event) -> {
|
audioSlider.addChangeListener((ChangeEvent event) -> {
|
||||||
if (audioSlider.getValueIsAdjusting()) {
|
if (audioSlider.getValueIsAdjusting() && gstPlayBin != null) {
|
||||||
double audioPercent = (audioSlider.getValue() * 2.0) / 100.0;
|
double audioPercent = (audioSlider.getValue() * 2.0) / 100.0;
|
||||||
gstPlayBin.setVolume(audioPercent);
|
gstPlayBin.setVolume(audioPercent);
|
||||||
}
|
}
|
||||||
@ -327,11 +330,13 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
endOfStreamListener = new Bus.EOS() {
|
endOfStreamListener = new Bus.EOS() {
|
||||||
@Override
|
@Override
|
||||||
public void endOfStream(GstObject go) {
|
public void endOfStream(GstObject go) {
|
||||||
gstPlayBin.seek(ClockTime.ZERO);
|
if (gstPlayBin != null) {
|
||||||
/**
|
gstPlayBin.seek(ClockTime.ZERO);
|
||||||
* Keep the video from automatically playing
|
/**
|
||||||
*/
|
* Keep the video from automatically playing
|
||||||
Gst.getExecutor().submit(() -> gstPlayBin.pause());
|
*/
|
||||||
|
Gst.getExecutor().submit(() -> gstPlayBin.pause());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -556,10 +561,12 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
//Video is ready for playback. Create new components
|
//Video is ready for playback. Create new components
|
||||||
gstPlayBin = new PlayBin("VideoPlayer", tempFile.toURI());
|
gstPlayBin = new PlayBin("VideoPlayer", tempFile.toURI());
|
||||||
//Configure event handling
|
//Configure event handling
|
||||||
Bus playBinBus = gstPlayBin.getBus();
|
if (gstPlayBin != null) {
|
||||||
playBinBus.connect(endOfStreamListener);
|
Bus playBinBus = gstPlayBin.getBus();
|
||||||
playBinBus.connect(stateChangeListener);
|
playBinBus.connect(endOfStreamListener);
|
||||||
playBinBus.connect(errorListener);
|
playBinBus.connect(stateChangeListener);
|
||||||
|
playBinBus.connect(errorListener);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.isCancelled()) {
|
if (this.isCancelled()) {
|
||||||
return;
|
return;
|
||||||
@ -570,15 +577,16 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
videoPanel.setLayout(new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
|
videoPanel.setLayout(new BoxLayout(videoPanel, BoxLayout.Y_AXIS));
|
||||||
videoPanel.add(fxPanel);
|
videoPanel.add(fxPanel);
|
||||||
fxAppSink = new JavaFxAppSink("JavaFxAppSink", fxPanel);
|
fxAppSink = new JavaFxAppSink("JavaFxAppSink", fxPanel);
|
||||||
gstPlayBin.setVideoSink(fxAppSink);
|
if (gstPlayBin != null) {
|
||||||
|
gstPlayBin.setVideoSink(fxAppSink);
|
||||||
|
}
|
||||||
if (this.isCancelled()) {
|
if (this.isCancelled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (gstPlayBin != null) {
|
||||||
gstPlayBin.setVolume((audioSlider.getValue() * 2.0) / 100.0);
|
gstPlayBin.setVolume((audioSlider.getValue() * 2.0) / 100.0);
|
||||||
gstPlayBin.pause();
|
gstPlayBin.pause();
|
||||||
|
}
|
||||||
timer.start();
|
timer.start();
|
||||||
enableComponents(true);
|
enableComponents(true);
|
||||||
} catch (CancellationException ex) {
|
} catch (CancellationException ex) {
|
||||||
@ -598,7 +606,7 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
if (!progressSlider.getValueIsAdjusting()) {
|
if (!progressSlider.getValueIsAdjusting() && gstPlayBin != null) {
|
||||||
sliderLock.acquireUninterruptibly();
|
sliderLock.acquireUninterruptibly();
|
||||||
long position = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
long position = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
||||||
long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
|
long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
|
||||||
@ -635,13 +643,13 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
* thumb at the given width and height. It also paints the track blue as
|
* thumb at the given width and height. It also paints the track blue as
|
||||||
* the thumb progresses.
|
* the thumb progresses.
|
||||||
*
|
*
|
||||||
* @param slider JSlider component
|
* @param slider JSlider component
|
||||||
* @param thumbDimension
|
* @param thumbDimension
|
||||||
*/
|
*/
|
||||||
public CircularJSliderUI(JSlider slider, Dimension thumbDimension) {
|
public CircularJSliderUI(JSlider slider, Dimension thumbDimension) {
|
||||||
super(slider);
|
super(slider);
|
||||||
this.thumbDimension = thumbDimension;
|
this.thumbDimension = thumbDimension;
|
||||||
|
|
||||||
//Configure track and thumb colors.
|
//Configure track and thumb colors.
|
||||||
Color lightBlue = new Color(0, 130, 255);
|
Color lightBlue = new Color(0, 130, 255);
|
||||||
thumbColor = lightBlue;
|
thumbColor = lightBlue;
|
||||||
@ -655,8 +663,8 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modifies the View to be an oval rather than the underlying
|
* Modifies the View to be an oval rather than the underlying rectangle
|
||||||
* rectangle Controller.
|
* Controller.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void paintThumb(Graphics graphic) {
|
public void paintThumb(Graphics graphic) {
|
||||||
@ -705,12 +713,13 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
@Override
|
@Override
|
||||||
protected TrackListener createTrackListener(JSlider slider) {
|
protected TrackListener createTrackListener(JSlider slider) {
|
||||||
/**
|
/**
|
||||||
* This track listener will force the thumb to be snapped to the mouse
|
* This track listener will force the thumb to be snapped to the
|
||||||
* location. This makes grabbing and dragging the JSlider much easier.
|
* mouse location. This makes grabbing and dragging the JSlider much
|
||||||
* Using the default track listener, the user would have to click
|
* easier. Using the default track listener, the user would have to
|
||||||
* exactly on the slider thumb to drag it. Now the thumb positions
|
* click exactly on the slider thumb to drag it. Now the thumb
|
||||||
* itself under the mouse so that it can always be dragged.
|
* positions itself under the mouse so that it can always be
|
||||||
*/
|
* dragged.
|
||||||
|
*/
|
||||||
return new TrackListener() {
|
return new TrackListener() {
|
||||||
@Override
|
@Override
|
||||||
public void mousePressed(MouseEvent e) {
|
public void mousePressed(MouseEvent e) {
|
||||||
@ -982,87 +991,95 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
|
|||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
private void rewindButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rewindButtonActionPerformed
|
private void rewindButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rewindButtonActionPerformed
|
||||||
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
if (gstPlayBin != null) {
|
||||||
//Skip 30 seconds.
|
|
||||||
long rewindDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
|
|
||||||
//Ensure new video position is within bounds
|
|
||||||
long newTime = Math.max(currentTime - rewindDelta, 0);
|
|
||||||
double playBackRate = getPlayBackRate();
|
|
||||||
gstPlayBin.seek(playBackRate,
|
|
||||||
Format.TIME,
|
|
||||||
//FLUSH - flushes the pipeline
|
|
||||||
//ACCURATE - video will seek exactly to the position requested
|
|
||||||
EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
|
|
||||||
//Set the start position to newTime
|
|
||||||
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
|
|
||||||
long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
|
|
||||||
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
|
||||||
//Skip 30 seconds.
|
|
||||||
long fastForwardDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
|
|
||||||
//Don't allow skipping within 2 seconds of video ending. Skipping right to
|
|
||||||
//the end causes undefined behavior for some gstreamer plugins.
|
|
||||||
long twoSecondsInNano = TimeUnit.NANOSECONDS.convert(2, TimeUnit.SECONDS);
|
|
||||||
if((duration - currentTime) <= twoSecondsInNano) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
long newTime;
|
|
||||||
if (currentTime + fastForwardDelta >= duration) {
|
|
||||||
//If there are less than 30 seconds left, only fast forward to the midpoint.
|
|
||||||
newTime = currentTime + (duration - currentTime)/2;
|
|
||||||
} else {
|
|
||||||
newTime = currentTime + fastForwardDelta;
|
|
||||||
}
|
|
||||||
|
|
||||||
double playBackRate = getPlayBackRate();
|
|
||||||
gstPlayBin.seek(playBackRate,
|
|
||||||
Format.TIME,
|
|
||||||
//FLUSH - flushes the pipeline
|
|
||||||
//ACCURATE - video will seek exactly to the position requested
|
|
||||||
EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
|
|
||||||
//Set the start position to newTime
|
|
||||||
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
|
|
||||||
if (gstPlayBin.isPlaying()) {
|
|
||||||
gstPlayBin.pause();
|
|
||||||
} else {
|
|
||||||
double playBackRate = getPlayBackRate();
|
|
||||||
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
||||||
//Set playback rate before play.
|
//Skip 30 seconds.
|
||||||
|
long rewindDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
|
||||||
|
//Ensure new video position is within bounds
|
||||||
|
long newTime = Math.max(currentTime - rewindDelta, 0);
|
||||||
|
double playBackRate = getPlayBackRate();
|
||||||
gstPlayBin.seek(playBackRate,
|
gstPlayBin.seek(playBackRate,
|
||||||
Format.TIME,
|
Format.TIME,
|
||||||
//FLUSH - flushes the pipeline
|
//FLUSH - flushes the pipeline
|
||||||
//ACCURATE - video will seek exactly to the position requested
|
//ACCURATE - video will seek exactly to the position requested
|
||||||
EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
|
EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
|
||||||
//Set the start position to newTime
|
//Set the start position to newTime
|
||||||
SeekType.SET, currentTime,
|
SeekType.SET, newTime,
|
||||||
//Do nothing for the end position
|
//Do nothing for the end position
|
||||||
SeekType.NONE, -1);
|
SeekType.NONE, -1);
|
||||||
gstPlayBin.play();
|
}
|
||||||
|
}//GEN-LAST:event_rewindButtonActionPerformed
|
||||||
|
|
||||||
|
private void fastForwardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fastForwardButtonActionPerformed
|
||||||
|
if (gstPlayBin != null) {
|
||||||
|
long duration = gstPlayBin.queryDuration(TimeUnit.NANOSECONDS);
|
||||||
|
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
||||||
|
//Skip 30 seconds.
|
||||||
|
long fastForwardDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
|
||||||
|
//Don't allow skipping within 2 seconds of video ending. Skipping right to
|
||||||
|
//the end causes undefined behavior for some gstreamer plugins.
|
||||||
|
long twoSecondsInNano = TimeUnit.NANOSECONDS.convert(2, TimeUnit.SECONDS);
|
||||||
|
if ((duration - currentTime) <= twoSecondsInNano) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long newTime;
|
||||||
|
if (currentTime + fastForwardDelta >= duration) {
|
||||||
|
//If there are less than 30 seconds left, only fast forward to the midpoint.
|
||||||
|
newTime = currentTime + (duration - currentTime) / 2;
|
||||||
|
} else {
|
||||||
|
newTime = currentTime + fastForwardDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
double playBackRate = getPlayBackRate();
|
||||||
|
gstPlayBin.seek(playBackRate,
|
||||||
|
Format.TIME,
|
||||||
|
//FLUSH - flushes the pipeline
|
||||||
|
//ACCURATE - video will seek exactly to the position requested
|
||||||
|
EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
|
||||||
|
//Set the start position to newTime
|
||||||
|
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
|
||||||
|
if (gstPlayBin != null) {
|
||||||
|
if (gstPlayBin.isPlaying()) {
|
||||||
|
gstPlayBin.pause();
|
||||||
|
} else {
|
||||||
|
double playBackRate = getPlayBackRate();
|
||||||
|
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
||||||
|
//Set playback rate before play.
|
||||||
|
gstPlayBin.seek(playBackRate,
|
||||||
|
Format.TIME,
|
||||||
|
//FLUSH - flushes the pipeline
|
||||||
|
//ACCURATE - video will seek exactly to the position requested
|
||||||
|
EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
|
||||||
|
//Set the start position to newTime
|
||||||
|
SeekType.SET, currentTime,
|
||||||
|
//Do nothing for the end position
|
||||||
|
SeekType.NONE, -1);
|
||||||
|
gstPlayBin.play();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}//GEN-LAST:event_playButtonActionPerformed
|
}//GEN-LAST:event_playButtonActionPerformed
|
||||||
|
|
||||||
private void playBackSpeedComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_playBackSpeedComboBoxActionPerformed
|
private void playBackSpeedComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_playBackSpeedComboBoxActionPerformed
|
||||||
double playBackRate = getPlayBackRate();
|
if (gstPlayBin != null) {
|
||||||
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
double playBackRate = getPlayBackRate();
|
||||||
gstPlayBin.seek(playBackRate,
|
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
|
||||||
Format.TIME,
|
gstPlayBin.seek(playBackRate,
|
||||||
//FLUSH - flushes the pipeline
|
Format.TIME,
|
||||||
//ACCURATE - video will seek exactly to the position requested
|
//FLUSH - flushes the pipeline
|
||||||
EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
|
//ACCURATE - video will seek exactly to the position requested
|
||||||
//Set the position to the currentTime, we are only adjusting the
|
EnumSet.of(SeekFlags.FLUSH, SeekFlags.ACCURATE),
|
||||||
//playback rate.
|
//Set the position to the currentTime, we are only adjusting the
|
||||||
SeekType.SET, currentTime,
|
//playback rate.
|
||||||
SeekType.NONE, 0);
|
SeekType.SET, currentTime,
|
||||||
|
SeekType.NONE, 0);
|
||||||
|
}
|
||||||
}//GEN-LAST:event_playBackSpeedComboBoxActionPerformed
|
}//GEN-LAST:event_playBackSpeedComboBoxActionPerformed
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
@ -233,33 +233,6 @@
|
|||||||
</Component>
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Container>
|
</Container>
|
||||||
<Container class="javax.swing.JScrollPane" name="textbodyScrollPane">
|
|
||||||
<Properties>
|
|
||||||
<Property name="horizontalScrollBarPolicy" type="int" value="31"/>
|
|
||||||
<Property name="verticalScrollBarPolicy" type="int" value="22"/>
|
|
||||||
</Properties>
|
|
||||||
<Constraints>
|
|
||||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
|
|
||||||
<JTabbedPaneConstraints tabName="Text">
|
|
||||||
<Property name="tabTitle" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MessageContentViewer.textbodyScrollPane.TabConstraints.tabTitle" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
|
||||||
</Property>
|
|
||||||
</JTabbedPaneConstraints>
|
|
||||||
</Constraint>
|
|
||||||
</Constraints>
|
|
||||||
|
|
||||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
|
||||||
<SubComponents>
|
|
||||||
<Component class="javax.swing.JTextArea" name="textbodyTextArea">
|
|
||||||
<Properties>
|
|
||||||
<Property name="editable" type="boolean" value="false"/>
|
|
||||||
<Property name="lineWrap" type="boolean" value="true"/>
|
|
||||||
<Property name="rows" type="int" value="5"/>
|
|
||||||
<Property name="wrapStyleWord" type="boolean" value="true"/>
|
|
||||||
</Properties>
|
|
||||||
</Component>
|
|
||||||
</SubComponents>
|
|
||||||
</Container>
|
|
||||||
<Container class="javax.swing.JPanel" name="htmlPane">
|
<Container class="javax.swing.JPanel" name="htmlPane">
|
||||||
<Constraints>
|
<Constraints>
|
||||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
|
||||||
|
@ -22,6 +22,7 @@ import org.sleuthkit.autopsy.datamodel.AttachmentNode;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.awt.ComponentOrientation;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -29,6 +30,7 @@ import java.util.List;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jsoup.Jsoup;
|
import org.jsoup.Jsoup;
|
||||||
@ -41,7 +43,9 @@ import org.openide.util.NbBundle;
|
|||||||
import org.openide.util.lookup.ServiceProvider;
|
import org.openide.util.lookup.ServiceProvider;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.contentviewers.TranslatablePanel.TranslatablePanelException;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||||
|
import org.sleuthkit.autopsy.corecomponents.AutoWrappingJTextPane;
|
||||||
import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
|
import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
|
||||||
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
@ -84,6 +88,38 @@ import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments.URL
|
|||||||
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
|
||||||
public class MessageContentViewer extends javax.swing.JPanel implements DataContentViewer {
|
public class MessageContentViewer extends javax.swing.JPanel implements DataContentViewer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a text component viewer to be a child component to be placed in a {@link TranslatablePanel TranslatablePanel}.
|
||||||
|
*/
|
||||||
|
class TextComponent implements TranslatablePanel.ContentComponent {
|
||||||
|
|
||||||
|
private final Component rootComponent;
|
||||||
|
private final AutoWrappingJTextPane childTextComponent;
|
||||||
|
|
||||||
|
TextComponent() {
|
||||||
|
childTextComponent = new AutoWrappingJTextPane();
|
||||||
|
childTextComponent.setEditable(false);
|
||||||
|
|
||||||
|
JScrollPane parentComponent = new JScrollPane();
|
||||||
|
parentComponent.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||||
|
parentComponent.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
|
||||||
|
parentComponent.setViewportView(childTextComponent);
|
||||||
|
rootComponent = parentComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Component getRootComponent() {
|
||||||
|
return rootComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContent(String content, ComponentOrientation orientation) throws TranslatablePanelException {
|
||||||
|
childTextComponent.setText(content == null ? "" : content);
|
||||||
|
childTextComponent.setComponentOrientation(orientation);
|
||||||
|
childTextComponent.setCaretPosition(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final Logger LOGGER = Logger.getLogger(MessageContentViewer.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(MessageContentViewer.class.getName());
|
||||||
private static final BlackboardAttribute.Type TSK_ASSOCIATED_TYPE = new BlackboardAttribute.Type(TSK_ASSOCIATED_ARTIFACT);
|
private static final BlackboardAttribute.Type TSK_ASSOCIATED_TYPE = new BlackboardAttribute.Type(TSK_ASSOCIATED_ARTIFACT);
|
||||||
@ -96,6 +132,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
|
|
||||||
private final List<JTextComponent> textAreas;
|
private final List<JTextComponent> textAreas;
|
||||||
private final org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel();
|
private final org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel();
|
||||||
|
private final TranslatablePanel textPanel = new TranslatablePanel(new TextComponent());
|
||||||
/**
|
/**
|
||||||
* Artifact currently being displayed
|
* Artifact currently being displayed
|
||||||
*/
|
*/
|
||||||
@ -113,13 +150,21 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
envelopePanel.setBackground(new Color(0, 0, 0, 38));
|
envelopePanel.setBackground(new Color(0, 0, 0, 38));
|
||||||
drp = DataResultPanel.createInstanceUninitialized(Bundle.MessageContentViewer_AtrachmentsPanel_title(), "", new TableFilterNode(Node.EMPTY, false), 0, null);
|
drp = DataResultPanel.createInstanceUninitialized(Bundle.MessageContentViewer_AtrachmentsPanel_title(), "", new TableFilterNode(Node.EMPTY, false), 0, null);
|
||||||
attachmentsScrollPane.setViewportView(drp);
|
attachmentsScrollPane.setViewportView(drp);
|
||||||
|
|
||||||
|
msgbodyTabbedPane.insertTab(
|
||||||
|
NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.textbodyScrollPane.TabConstraints.tabTitle"),
|
||||||
|
null,
|
||||||
|
textPanel,
|
||||||
|
null,
|
||||||
|
TEXT_TAB_INDEX);
|
||||||
|
|
||||||
msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, true);
|
msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* HTML tab uses the HtmlPanel instead of an internal text pane, so we
|
* HTML tab uses the HtmlPanel instead of an internal text pane, so we
|
||||||
* use 'null' for that index.
|
* use 'null' for that index.
|
||||||
*/
|
*/
|
||||||
textAreas = Arrays.asList(headersTextArea, textbodyTextArea, null, rtfbodyTextPane);
|
textAreas = Arrays.asList(headersTextArea, null, null, rtfbodyTextPane);
|
||||||
|
|
||||||
Utilities.configureTextPaneAsRtf(rtfbodyTextPane);
|
Utilities.configureTextPaneAsRtf(rtfbodyTextPane);
|
||||||
resetComponent();
|
resetComponent();
|
||||||
@ -159,8 +204,6 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
msgbodyTabbedPane = new javax.swing.JTabbedPane();
|
msgbodyTabbedPane = new javax.swing.JTabbedPane();
|
||||||
headersScrollPane = new javax.swing.JScrollPane();
|
headersScrollPane = new javax.swing.JScrollPane();
|
||||||
headersTextArea = new javax.swing.JTextArea();
|
headersTextArea = new javax.swing.JTextArea();
|
||||||
textbodyScrollPane = new javax.swing.JScrollPane();
|
|
||||||
textbodyTextArea = new javax.swing.JTextArea();
|
|
||||||
htmlPane = new javax.swing.JPanel();
|
htmlPane = new javax.swing.JPanel();
|
||||||
rtfbodyScrollPane = new javax.swing.JScrollPane();
|
rtfbodyScrollPane = new javax.swing.JScrollPane();
|
||||||
rtfbodyTextPane = new javax.swing.JTextPane();
|
rtfbodyTextPane = new javax.swing.JTextPane();
|
||||||
@ -263,17 +306,6 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
|
|
||||||
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.headersScrollPane.TabConstraints.tabTitle"), headersScrollPane); // NOI18N
|
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.headersScrollPane.TabConstraints.tabTitle"), headersScrollPane); // NOI18N
|
||||||
|
|
||||||
textbodyScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
|
||||||
textbodyScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
|
|
||||||
|
|
||||||
textbodyTextArea.setEditable(false);
|
|
||||||
textbodyTextArea.setLineWrap(true);
|
|
||||||
textbodyTextArea.setRows(5);
|
|
||||||
textbodyTextArea.setWrapStyleWord(true);
|
|
||||||
textbodyScrollPane.setViewportView(textbodyTextArea);
|
|
||||||
|
|
||||||
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.textbodyScrollPane.TabConstraints.tabTitle"), textbodyScrollPane); // NOI18N
|
|
||||||
|
|
||||||
htmlPane.setLayout(new java.awt.BorderLayout());
|
htmlPane.setLayout(new java.awt.BorderLayout());
|
||||||
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.htmlPane.TabConstraints.tabTitle"), htmlPane); // NOI18N
|
msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.htmlPane.TabConstraints.tabTitle"), htmlPane); // NOI18N
|
||||||
|
|
||||||
@ -335,6 +367,8 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
.addComponent(msgbodyTabbedPane)
|
.addComponent(msgbodyTabbedPane)
|
||||||
.addGap(5, 5, 5))
|
.addGap(5, 5, 5))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
msgbodyTabbedPane.getAccessibleContext().setAccessibleParent(null);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
private void viewInNewWindowButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewInNewWindowButtonActionPerformed
|
private void viewInNewWindowButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewInNewWindowButtonActionPerformed
|
||||||
@ -360,8 +394,6 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
private javax.swing.JTextPane rtfbodyTextPane;
|
private javax.swing.JTextPane rtfbodyTextPane;
|
||||||
private javax.swing.JLabel subjectLabel;
|
private javax.swing.JLabel subjectLabel;
|
||||||
private javax.swing.JLabel subjectText;
|
private javax.swing.JLabel subjectText;
|
||||||
private javax.swing.JScrollPane textbodyScrollPane;
|
|
||||||
private javax.swing.JTextArea textbodyTextArea;
|
|
||||||
private javax.swing.JLabel toLabel;
|
private javax.swing.JLabel toLabel;
|
||||||
private javax.swing.JLabel toText;
|
private javax.swing.JLabel toText;
|
||||||
private javax.swing.JButton viewInNewWindowButton;
|
private javax.swing.JButton viewInNewWindowButton;
|
||||||
@ -407,11 +439,11 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
* Get the artifact associated with the given artifact, if there is one.
|
* Get the artifact associated with the given artifact, if there is one.
|
||||||
*
|
*
|
||||||
* @param artifact The artifact to get the associated artifact from. Must
|
* @param artifact The artifact to get the associated artifact from. Must
|
||||||
* not be null
|
* not be null
|
||||||
*
|
*
|
||||||
* @throws TskCoreException If there is a critical error querying the DB.
|
* @throws TskCoreException If there is a critical error querying the DB.
|
||||||
* @return An optional containing the artifact associated with the given
|
* @return An optional containing the artifact associated with the given
|
||||||
* artifact, if there is one.
|
* artifact, if there is one.
|
||||||
*/
|
*/
|
||||||
private static Optional<BlackboardArtifact> getAssociatedArtifact(final BlackboardArtifact artifact) throws TskCoreException {
|
private static Optional<BlackboardArtifact> getAssociatedArtifact(final BlackboardArtifact artifact) throws TskCoreException {
|
||||||
BlackboardAttribute attribute = artifact.getAttribute(TSK_ASSOCIATED_TYPE);
|
BlackboardAttribute attribute = artifact.getAttribute(TSK_ASSOCIATED_TYPE);
|
||||||
@ -462,7 +494,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
headersTextArea.setText("");
|
headersTextArea.setText("");
|
||||||
rtfbodyTextPane.setText("");
|
rtfbodyTextPane.setText("");
|
||||||
htmlPanel.reset();
|
htmlPanel.reset();
|
||||||
textbodyTextArea.setText("");
|
textPanel.reset();
|
||||||
msgbodyTabbedPane.setEnabled(false);
|
msgbodyTabbedPane.setEnabled(false);
|
||||||
drp.setNode(null);
|
drp.setNode(null);
|
||||||
}
|
}
|
||||||
@ -491,10 +523,10 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
* Is the given artifact one that can be shown in this viewer?
|
* Is the given artifact one that can be shown in this viewer?
|
||||||
*
|
*
|
||||||
* @param nodeArtifact An artifact that might be a message. Must not be
|
* @param nodeArtifact An artifact that might be a message. Must not be
|
||||||
* null.
|
* null.
|
||||||
*
|
*
|
||||||
* @return True if the given artifact can be shown as a message in this
|
* @return True if the given artifact can be shown as a message in this
|
||||||
* viewer.
|
* viewer.
|
||||||
*/
|
*/
|
||||||
private static boolean isMessageArtifact(BlackboardArtifact nodeArtifact) {
|
private static boolean isMessageArtifact(BlackboardArtifact nodeArtifact) {
|
||||||
final int artifactTypeID = nodeArtifact.getArtifactTypeID();
|
final int artifactTypeID = nodeArtifact.getArtifactTypeID();
|
||||||
@ -540,14 +572,14 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
|
|
||||||
return nodeArtifact;
|
return nodeArtifact;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int isPreferred(Node node) {
|
public int isPreferred(Node node) {
|
||||||
// For message artifacts this is a high priority viewer,
|
// For message artifacts this is a high priority viewer,
|
||||||
// but for attachment files, this a lower priority vewer.
|
// but for attachment files, this a lower priority vewer.
|
||||||
if (isSupported(node)) {
|
if (isSupported(node)) {
|
||||||
BlackboardArtifact nodeArtifact = node.getLookup().lookup(BlackboardArtifact.class);
|
BlackboardArtifact nodeArtifact = node.getLookup().lookup(BlackboardArtifact.class);
|
||||||
if (nodeArtifact != null) {
|
if (nodeArtifact != null) {
|
||||||
return 7;
|
return 7;
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
@ -560,7 +592,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
* Configure the text area at the given index to show the content of the
|
* Configure the text area at the given index to show the content of the
|
||||||
* given type.
|
* given type.
|
||||||
*
|
*
|
||||||
* @param type The ATTRIBUT_TYPE to show in the indexed tab.
|
* @param type The ATTRIBUT_TYPE to show in the indexed tab.
|
||||||
* @param index The index of the text area to configure.
|
* @param index The index of the text area to configure.
|
||||||
*
|
*
|
||||||
* @throws TskCoreException
|
* @throws TskCoreException
|
||||||
@ -570,6 +602,8 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
|
|
||||||
if (index == HTML_TAB_INDEX && StringUtils.isNotBlank(attributeText)) {
|
if (index == HTML_TAB_INDEX && StringUtils.isNotBlank(attributeText)) {
|
||||||
htmlPanel.setHtmlText(attributeText);
|
htmlPanel.setHtmlText(attributeText);
|
||||||
|
} else if (index == TEXT_TAB_INDEX && StringUtils.isNotBlank(attributeText)) {
|
||||||
|
textPanel.setContent(attributeText, artifact.toString());
|
||||||
} else {
|
} else {
|
||||||
JTextComponent textComponent = textAreas.get(index);
|
JTextComponent textComponent = textAreas.get(index);
|
||||||
if (textComponent != null) {
|
if (textComponent != null) {
|
||||||
@ -595,34 +629,34 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void configureAttachments() throws TskCoreException {
|
private void configureAttachments() throws TskCoreException {
|
||||||
|
|
||||||
final Set<Attachment> attachments;
|
final Set<Attachment> attachments;
|
||||||
|
|
||||||
// Attachments are specified in an attribute TSK_ATTACHMENTS as JSON attribute
|
// Attachments are specified in an attribute TSK_ATTACHMENTS as JSON attribute
|
||||||
BlackboardAttribute attachmentsAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS));
|
BlackboardAttribute attachmentsAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS));
|
||||||
if(attachmentsAttr != null) {
|
if (attachmentsAttr != null) {
|
||||||
|
|
||||||
attachments = new HashSet<>();
|
attachments = new HashSet<>();
|
||||||
String jsonVal = attachmentsAttr.getValueString();
|
String jsonVal = attachmentsAttr.getValueString();
|
||||||
MessageAttachments msgAttachments = new Gson().fromJson(jsonVal, MessageAttachments.class);
|
MessageAttachments msgAttachments = new Gson().fromJson(jsonVal, MessageAttachments.class);
|
||||||
|
|
||||||
Collection<FileAttachment> fileAttachments = msgAttachments.getFileAttachments();
|
Collection<FileAttachment> fileAttachments = msgAttachments.getFileAttachments();
|
||||||
for (FileAttachment fileAttachment: fileAttachments) {
|
for (FileAttachment fileAttachment : fileAttachments) {
|
||||||
attachments.add(fileAttachment);
|
attachments.add(fileAttachment);
|
||||||
}
|
}
|
||||||
Collection<URLAttachment> urlAttachments = msgAttachments.getUrlAttachments();
|
Collection<URLAttachment> urlAttachments = msgAttachments.getUrlAttachments();
|
||||||
for (URLAttachment urlAttachment: urlAttachments) {
|
for (URLAttachment urlAttachment : urlAttachments) {
|
||||||
attachments.add(urlAttachment);
|
attachments.add(urlAttachment);
|
||||||
}
|
}
|
||||||
} else { // For backward compatibility - email attachements are derived files and children of the email message artifact
|
} else { // For backward compatibility - email attachements are derived files and children of the email message artifact
|
||||||
attachments = new HashSet<>();
|
attachments = new HashSet<>();
|
||||||
for (Content child: artifact.getChildren()) {
|
for (Content child : artifact.getChildren()) {
|
||||||
if (child instanceof AbstractFile) {
|
if (child instanceof AbstractFile) {
|
||||||
attachments.add(new FileAttachment((AbstractFile)child));
|
attachments.add(new FileAttachment((AbstractFile) child));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final int numberOfAttachments = attachments.size();
|
final int numberOfAttachments = attachments.size();
|
||||||
|
|
||||||
msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, numberOfAttachments > 0);
|
msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, numberOfAttachments > 0);
|
||||||
@ -710,9 +744,8 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
return doc.html();
|
return doc.html();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates child nodes for message attachments.
|
* Creates child nodes for message attachments.
|
||||||
*/
|
*/
|
||||||
private static class AttachmentsChildren extends Children.Keys<Attachment> {
|
private static class AttachmentsChildren extends Children.Keys<Attachment> {
|
||||||
|
|
||||||
|
@ -0,0 +1,97 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
|
<Form version="1.5" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||||
|
<Properties>
|
||||||
|
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[2000, 2000]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[2, 2]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="name" type="java.lang.String" value="" noResource="true"/>
|
||||||
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[100, 58]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="verifyInputWhenFocusTarget" type="boolean" value="false"/>
|
||||||
|
</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"/>
|
||||||
|
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,-116,0,0,2,-108"/>
|
||||||
|
</AuxValues>
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||||
|
<SubComponents>
|
||||||
|
<Container class="javax.swing.JPanel" name="translationBar">
|
||||||
|
<Properties>
|
||||||
|
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||||
|
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
|
||||||
|
<EtchetBorder/>
|
||||||
|
</Border>
|
||||||
|
</Property>
|
||||||
|
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[182, 24]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[182, 24]"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||||
|
<BorderConstraints direction="North"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
|
||||||
|
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||||
|
<SubComponents>
|
||||||
|
<Component class="javax.swing.JComboBox" name="translateComboBox">
|
||||||
|
<Properties>
|
||||||
|
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
|
||||||
|
<StringArray count="0"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[200, 20]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[200, 20]"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="name" type="java.lang.String" value="" noResource="true"/>
|
||||||
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[200, 20]"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="translateComboBoxActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
<AuxValues>
|
||||||
|
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<TranslateOption>"/>
|
||||||
|
</AuxValues>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||||
|
<BorderConstraints direction="After"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="statusLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[32767, 32767]"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Constraints>
|
||||||
|
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
|
||||||
|
<BorderConstraints direction="Center"/>
|
||||||
|
</Constraint>
|
||||||
|
</Constraints>
|
||||||
|
</Component>
|
||||||
|
</SubComponents>
|
||||||
|
</Container>
|
||||||
|
</SubComponents>
|
||||||
|
</Form>
|
@ -0,0 +1,434 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.ComponentOrientation;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
import javax.swing.ImageIcon;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
|
import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException;
|
||||||
|
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
|
||||||
|
import org.sleuthkit.autopsy.texttranslation.TranslationException;
|
||||||
|
import org.sleuthkit.autopsy.texttranslation.ui.TranslateTextTask;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a panel for translation with a subcomponent that allows for translation.
|
||||||
|
*/
|
||||||
|
class TranslatablePanel extends JPanel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an exception that can occur during the normal operation of the translatable
|
||||||
|
* panel. For instance, this exception can be thrown if it is not possible to set the child
|
||||||
|
* content to the provided content string.
|
||||||
|
*/
|
||||||
|
class TranslatablePanelException extends Exception {
|
||||||
|
public static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
TranslatablePanelException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
TranslatablePanelException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This describes a child component to be placed as a child of this panel. The child received
|
||||||
|
* from {@link #getRootComponent() getRootComponent() } will listen for content updates from setContent().
|
||||||
|
*/
|
||||||
|
interface ContentComponent {
|
||||||
|
/**
|
||||||
|
* This method gets root component of the translation panel.
|
||||||
|
* @return the root component to insert into the translatable panel
|
||||||
|
*/
|
||||||
|
Component getRootComponent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method sets the content of the component to the provided content.
|
||||||
|
* @param content the content to be displayed
|
||||||
|
* @param orientation how it should be displayed
|
||||||
|
* @throws Exception if there is an error in rendering the content
|
||||||
|
*/
|
||||||
|
void setContent(String content, ComponentOrientation orientation) throws TranslatablePanelException;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an option in drop down of whether or not to translate.
|
||||||
|
*/
|
||||||
|
private static class TranslateOption {
|
||||||
|
|
||||||
|
private final String text;
|
||||||
|
private final boolean translate;
|
||||||
|
|
||||||
|
TranslateOption(String text, boolean translate) {
|
||||||
|
this.text = text;
|
||||||
|
this.translate = translate;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean shouldTranslate() {
|
||||||
|
return translate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This represents the cached result of translating the current content.
|
||||||
|
*/
|
||||||
|
private static class TranslatedText {
|
||||||
|
|
||||||
|
private final String text;
|
||||||
|
private final ComponentOrientation orientation;
|
||||||
|
|
||||||
|
TranslatedText(String text, ComponentOrientation orientation) {
|
||||||
|
this.text = text;
|
||||||
|
this.orientation = orientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getText() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComponentOrientation getOrientation() {
|
||||||
|
return orientation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This connects the swing worker specified by
|
||||||
|
* {@link org.sleuthkit.autopsy.texttranslation.ui.TranslateTextTask TranslateTextTask} to this component.
|
||||||
|
*/
|
||||||
|
private class OnTranslation extends TranslateTextTask {
|
||||||
|
|
||||||
|
OnTranslation() {
|
||||||
|
super(true, contentDescriptor == null ? "" : contentDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String translate(String input) throws NoServiceProviderException, TranslationException {
|
||||||
|
// This defers to the outer class method so that it can be overridden for items like html, rtf, etc.
|
||||||
|
return retrieveTranslation(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onProgressDisplay(String text, ComponentOrientation orientation, int font) {
|
||||||
|
setStatus(text, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onErrorDisplay(String text, ComponentOrientation orientation, int font) {
|
||||||
|
setStatus(text, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String retrieveText() throws IOException, InterruptedException, IllegalStateException {
|
||||||
|
return content == null ? "" : content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onTextDisplay(String text, ComponentOrientation orientation, int font) {
|
||||||
|
// On successful acquire, this caches the result and set the text.
|
||||||
|
setCachedTranslated(new TranslatedText(text, orientation));
|
||||||
|
setChildComponentContent(text, orientation);
|
||||||
|
|
||||||
|
// This clears any status that may be present.
|
||||||
|
clearStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static final ComponentOrientation DEFAULT_ORIENTATION = ComponentOrientation.LEFT_TO_RIGHT;
|
||||||
|
|
||||||
|
private final ImageIcon warningIcon = new ImageIcon(TranslatablePanel.class.getResource("/org/sleuthkit/autopsy/images/warning16.png"));
|
||||||
|
|
||||||
|
private final ContentComponent contentComponent;
|
||||||
|
private final TextTranslationService translationService;
|
||||||
|
private final ThreadFactory translationThreadFactory = new ThreadFactoryBuilder().setNameFormat("translatable-panel-%d").build();
|
||||||
|
private final ExecutorService executorService = Executors.newSingleThreadExecutor(translationThreadFactory);
|
||||||
|
|
||||||
|
private final Object cachedTranslatedLock = new Object();
|
||||||
|
private final Object backgroundTaskLock = new Object();
|
||||||
|
|
||||||
|
private String content;
|
||||||
|
private String contentDescriptor;
|
||||||
|
private boolean prevTranslateSelection;
|
||||||
|
|
||||||
|
private volatile TranslatedText cachedTranslated;
|
||||||
|
private volatile OnTranslation backgroundTask = null;
|
||||||
|
|
||||||
|
@Messages({"TranslatablePanel.comboBoxOption.originalText=Original Text",
|
||||||
|
"TranslatablePanel.comboBoxOption.translatedText=Translated Text"})
|
||||||
|
TranslatablePanel(ContentComponent contentComponent) {
|
||||||
|
this(
|
||||||
|
contentComponent,
|
||||||
|
Bundle.TranslatablePanel_comboBoxOption_originalText(),
|
||||||
|
Bundle.TranslatablePanel_comboBoxOption_translatedText(),
|
||||||
|
null,
|
||||||
|
TextTranslationService.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This creates a new panel using @{link ContentPanel ContentPanel} as a child.
|
||||||
|
*/
|
||||||
|
TranslatablePanel(ContentComponent contentComponent, String origOptionText, String translatedOptionText, String origContent,
|
||||||
|
TextTranslationService translationService) {
|
||||||
|
this.contentComponent = contentComponent;
|
||||||
|
this.translationService = translationService;
|
||||||
|
|
||||||
|
initComponents();
|
||||||
|
additionalInit(contentComponent.getRootComponent(), origOptionText, translatedOptionText);
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the cached translated text or returns null
|
||||||
|
*/
|
||||||
|
private TranslatedText getCachedTranslated() {
|
||||||
|
synchronized (cachedTranslatedLock) {
|
||||||
|
return cachedTranslated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param translated the translated text to be cached
|
||||||
|
*/
|
||||||
|
private void setCachedTranslated(TranslatedText translated) {
|
||||||
|
synchronized (cachedTranslatedLock) {
|
||||||
|
this.cachedTranslated = translated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a translation worker is running, this is called to cancel the worker.
|
||||||
|
*/
|
||||||
|
private void cancelPendingTranslation() {
|
||||||
|
synchronized (backgroundTaskLock) {
|
||||||
|
if (backgroundTask != null && !backgroundTask.isDone()) {
|
||||||
|
backgroundTask.cancel(true);
|
||||||
|
}
|
||||||
|
backgroundTask = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This runs a translation worker to translate the text.
|
||||||
|
*/
|
||||||
|
private void runTranslationTask() {
|
||||||
|
synchronized (backgroundTaskLock) {
|
||||||
|
cancelPendingTranslation();
|
||||||
|
backgroundTask = new OnTranslation();
|
||||||
|
|
||||||
|
//Pass the background task to a single threaded pool to keep
|
||||||
|
//the number of jobs running to one.
|
||||||
|
executorService.execute(backgroundTask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This resets the component to an empty state and sets the translation bar visibility
|
||||||
|
* based on whether there is a provider.
|
||||||
|
*/
|
||||||
|
final void reset() {
|
||||||
|
setContent(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method sets the content for the component; this also clears the status.
|
||||||
|
* @param content the content for the panel
|
||||||
|
* @param contentDescriptor the content descriptor to be used in error messages
|
||||||
|
*/
|
||||||
|
void setContent(String content, String contentDescriptor) {
|
||||||
|
cancelPendingTranslation();
|
||||||
|
setTranslationEnabled();
|
||||||
|
this.translateComboBox.setSelectedIndex(0);
|
||||||
|
this.prevTranslateSelection = false;
|
||||||
|
this.content = content;
|
||||||
|
this.contentDescriptor = contentDescriptor;
|
||||||
|
clearStatus();
|
||||||
|
setCachedTranslated(null);
|
||||||
|
setChildComponentContent(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is where actual translation takes place allowed to be overridden for the
|
||||||
|
* sake of varying translatable content (i.e. html, rtf, etc).
|
||||||
|
*
|
||||||
|
* @param input the input content
|
||||||
|
* @return the result of translation
|
||||||
|
* @throws TranslationException
|
||||||
|
* @throws NoServiceProviderException
|
||||||
|
*/
|
||||||
|
protected String retrieveTranslation(String input) throws TranslationException, NoServiceProviderException {
|
||||||
|
return translationService.translate(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method clears the status bar.
|
||||||
|
*/
|
||||||
|
private void clearStatus() {
|
||||||
|
setStatus(null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This sets the status bar message.
|
||||||
|
* @param msg the status bar message to show
|
||||||
|
* @param showWarningIcon whether that status is a warning
|
||||||
|
*/
|
||||||
|
private synchronized void setStatus(String msg, boolean showWarningIcon) {
|
||||||
|
statusLabel.setText(msg);
|
||||||
|
statusLabel.setIcon(showWarningIcon ? warningIcon : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method sets the translation bar visibility based on whether or not there is a provided.
|
||||||
|
*/
|
||||||
|
private void setTranslationEnabled() {
|
||||||
|
translateComboBox.setEnabled(this.translationService.hasProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The child component provided in the constructor will have its content set to the string provided.
|
||||||
|
* @param content the content to display in the child component
|
||||||
|
*/
|
||||||
|
private void setChildComponentContent(String content) {
|
||||||
|
setChildComponentContent(content, DEFAULT_ORIENTATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The child component provided in the constructor will have its content set to the string provided.
|
||||||
|
* @param content the content to display in the child component
|
||||||
|
* @param orientation the orientation for the text
|
||||||
|
*/
|
||||||
|
@Messages({"# {0} - exception message", "TranslatablePanel.onSetContentError.text=There was an error displaying the text: {0}"})
|
||||||
|
private synchronized void setChildComponentContent(String content, ComponentOrientation orientation) {
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
try {
|
||||||
|
contentComponent.setContent(content, orientation);
|
||||||
|
} catch (TranslatablePanelException ex) {
|
||||||
|
setStatus(Bundle.TranslatablePanel_onSetContentError_text(ex.getMessage()), true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is for items that are programmatically initialized.
|
||||||
|
*/
|
||||||
|
private void additionalInit(Component rootComponent, String origOptionText, String translatedOptionText) {
|
||||||
|
add(rootComponent, java.awt.BorderLayout.CENTER);
|
||||||
|
translateComboBox.removeAllItems();
|
||||||
|
translateComboBox.addItem(new TranslateOption(origOptionText, false));
|
||||||
|
translateComboBox.addItem(new TranslateOption(translatedOptionText, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the combo box choice is selected, this method is fired.
|
||||||
|
* @param translateOption the current translate option
|
||||||
|
*/
|
||||||
|
private void handleComboBoxChange(TranslateOption translateOption) {
|
||||||
|
boolean curTranslateSelection = translateOption.shouldTranslate();
|
||||||
|
if (curTranslateSelection != this.prevTranslateSelection) {
|
||||||
|
this.prevTranslateSelection = curTranslateSelection;
|
||||||
|
|
||||||
|
cancelPendingTranslation();
|
||||||
|
clearStatus();
|
||||||
|
|
||||||
|
if (curTranslateSelection) {
|
||||||
|
TranslatedText translated = getCachedTranslated();
|
||||||
|
if (translated != null) {
|
||||||
|
setChildComponentContent(translated.getText(), translated.getOrientation());
|
||||||
|
} else {
|
||||||
|
runTranslationTask();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setChildComponentContent(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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() {
|
||||||
|
|
||||||
|
translationBar = new javax.swing.JPanel();
|
||||||
|
translateComboBox = new javax.swing.JComboBox<>();
|
||||||
|
statusLabel = new javax.swing.JLabel();
|
||||||
|
|
||||||
|
setMaximumSize(new java.awt.Dimension(2000, 2000));
|
||||||
|
setMinimumSize(new java.awt.Dimension(2, 2));
|
||||||
|
setName(""); // NOI18N
|
||||||
|
setPreferredSize(new java.awt.Dimension(100, 58));
|
||||||
|
setVerifyInputWhenFocusTarget(false);
|
||||||
|
setLayout(new java.awt.BorderLayout());
|
||||||
|
|
||||||
|
translationBar.setBorder(javax.swing.BorderFactory.createEtchedBorder());
|
||||||
|
translationBar.setMaximumSize(new java.awt.Dimension(182, 24));
|
||||||
|
translationBar.setPreferredSize(new java.awt.Dimension(182, 24));
|
||||||
|
translationBar.setLayout(new java.awt.BorderLayout());
|
||||||
|
|
||||||
|
translateComboBox.setMaximumSize(new java.awt.Dimension(200, 20));
|
||||||
|
translateComboBox.setMinimumSize(new java.awt.Dimension(200, 20));
|
||||||
|
translateComboBox.setName(""); // NOI18N
|
||||||
|
translateComboBox.setPreferredSize(new java.awt.Dimension(200, 20));
|
||||||
|
translateComboBox.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
translateComboBoxActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
translationBar.add(translateComboBox, java.awt.BorderLayout.LINE_END);
|
||||||
|
|
||||||
|
statusLabel.setMaximumSize(new java.awt.Dimension(32767, 32767));
|
||||||
|
translationBar.add(statusLabel, java.awt.BorderLayout.CENTER);
|
||||||
|
|
||||||
|
add(translationBar, java.awt.BorderLayout.NORTH);
|
||||||
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
private void translateComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_translateComboBoxActionPerformed
|
||||||
|
handleComboBoxChange((TranslateOption) translateComboBox.getSelectedItem());
|
||||||
|
}//GEN-LAST:event_translateComboBoxActionPerformed
|
||||||
|
|
||||||
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JLabel statusLabel;
|
||||||
|
private javax.swing.JComboBox<TranslateOption> translateComboBox;
|
||||||
|
private javax.swing.JPanel translationBar;
|
||||||
|
// End of variables declaration//GEN-END:variables
|
||||||
|
}
|
@ -1,4 +1,9 @@
|
|||||||
ContextViewer.jSourceGoToResultButton.text=Go to Result
|
ContextUsagePanel.jUsageGoToResultButton.text=Go to Result
|
||||||
ContextViewer.jSourceTextLabel.text=jLabel2
|
ContextSourcePanel.jSourceGoToResultButton.text=Go to Result
|
||||||
ContextViewer.jSourceNameLabel.text=jSourceNameLabel
|
ContextUsagePanel.jUsageTextLabel.text=Label2
|
||||||
ContextViewer.jSourceLabel.text=Source
|
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,18 +1,24 @@
|
|||||||
|
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.attachmentSource=Attached to:
|
||||||
ContextViewer.downloadedOn=On
|
ContextViewer.downloadedOn=On
|
||||||
ContextViewer.downloadSource=Downloaded from:
|
ContextViewer.downloadSource=Downloaded from:
|
||||||
ContextViewer.downloadURL=URL
|
ContextViewer.downloadURL=URL
|
||||||
ContextViewer.email=Email
|
ContextViewer.email=Email
|
||||||
ContextViewer.file=File
|
ContextViewer.jSourceLabel.text=Usage
|
||||||
ContextViewer.jSourceGoToResultButton.text=Go to Result
|
ContextViewer.jUsageLabel.text=Source
|
||||||
ContextViewer.jSourceTextLabel.text=jLabel2
|
ContextViewer.jUnknownLabel.text=Unknown
|
||||||
ContextViewer.jSourceNameLabel.text=jSourceNameLabel
|
|
||||||
ContextViewer.jSourceLabel.text=Source
|
|
||||||
ContextViewer.message=Message
|
ContextViewer.message=Message
|
||||||
ContextViewer.messageFrom=From
|
ContextViewer.messageFrom=From
|
||||||
ContextViewer.messageOn=On
|
ContextViewer.messageOn=On
|
||||||
ContextViewer.messageTo=To
|
ContextViewer.messageTo=To
|
||||||
ContextViewer.on=On
|
ContextViewer.on=Opened at
|
||||||
ContextViewer.recentDocs=Recent Documents:
|
ContextViewer.recentDocs=Recent Documents:
|
||||||
ContextViewer.title=Context
|
ContextViewer.title=Context
|
||||||
ContextViewer.toolTip=Displays context for selected file.
|
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,10 +1,144 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
<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>
|
<Properties>
|
||||||
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||||
<Color blue="ff" green="ff" red="ff" type="rgb"/>
|
<Color blue="ff" green="ff" red="ff" type="rgb"/>
|
||||||
</Property>
|
</Property>
|
||||||
|
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||||
|
<Dimension value="[495, 358]"/>
|
||||||
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
@ -21,80 +155,24 @@
|
|||||||
<Layout>
|
<Layout>
|
||||||
<DimensionLayout dim="0">
|
<DimensionLayout dim="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" attributes="0">
|
<Component id="jScrollPane" alignment="0" pref="509" max="32767" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="jSourceLabel" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<EmptySpace min="-2" pref="6" max="-2" 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>
|
|
||||||
<EmptySpace min="-2" pref="36" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Component id="jSourceGoToResultButton" min="-2" max="-2" attributes="0"/>
|
|
||||||
<EmptySpace max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Component id="jScrollPane" alignment="0" pref="335" max="32767" 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 min="0" pref="203" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
</Layout>
|
</Layout>
|
||||||
<SubComponents>
|
<SubComponents>
|
||||||
<Component class="javax.swing.JButton" name="jSourceGoToResultButton">
|
<Container class="javax.swing.JScrollPane" name="jScrollPane">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jSourceGoToResultButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<Color blue="ff" green="ff" red="ff" type="rgb"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
|
||||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jSourceGoToResultButtonActionPerformed"/>
|
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||||
</Events>
|
</Container>
|
||||||
</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>
|
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Form>
|
</Form>
|
||||||
|
@ -24,6 +24,8 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.logging.Level;
|
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.apache.commons.lang.StringUtils;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.util.NbBundle;
|
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.casemodule.NoCurrentCaseException;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
|
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
|
// defines a list of artifacts that provide context for a file
|
||||||
private static final List<BlackboardArtifact.ARTIFACT_TYPE> SOURCE_CONTEXT_ARTIFACTS = new ArrayList<>();
|
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 {
|
static {
|
||||||
SOURCE_CONTEXT_ARTIFACTS.add(TSK_ASSOCIATED_OBJECT);
|
SOURCE_CONTEXT_ARTIFACTS.add(TSK_ASSOCIATED_OBJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BlackboardArtifact sourceContextArtifact;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new form ContextViewer
|
* Creates new form ContextViewer
|
||||||
*/
|
*/
|
||||||
public ContextViewer() {
|
public ContextViewer() {
|
||||||
|
|
||||||
initComponents();
|
initComponents();
|
||||||
|
jScrollPane.setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -79,73 +81,96 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
|||||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
|
|
||||||
jSourceGoToResultButton = new javax.swing.JButton();
|
jSourcePanel = new javax.swing.JPanel();
|
||||||
jSourceLabel = new javax.swing.JLabel();
|
javax.swing.JLabel jSourceLabel = new javax.swing.JLabel();
|
||||||
jSourceNameLabel = new javax.swing.JLabel();
|
jUsagePanel = new javax.swing.JPanel();
|
||||||
jSourceTextLabel = new javax.swing.JLabel();
|
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));
|
jSourcePanel.setBackground(javax.swing.UIManager.getDefaults().getColor("window"));
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
jSourceLabel.setFont(new java.awt.Font("Dialog", 1, 14)); // NOI18N
|
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(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
|
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
|
||||||
|
|
||||||
|
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))
|
||||||
|
);
|
||||||
|
|
||||||
|
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);
|
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
|
||||||
this.setLayout(layout);
|
this.setLayout(layout);
|
||||||
layout.setHorizontalGroup(
|
layout.setHorizontalGroup(
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addComponent(jScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 509, Short.MAX_VALUE)
|
||||||
.addContainerGap()
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addComponent(jSourceLabel)
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addGap(6, 6, 6)
|
|
||||||
.addComponent(jSourceNameLabel)
|
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
|
||||||
.addComponent(jSourceTextLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 192, Short.MAX_VALUE)))
|
|
||||||
.addGap(36, 36, 36))
|
|
||||||
.addGroup(layout.createSequentialGroup()
|
|
||||||
.addComponent(jSourceGoToResultButton)
|
|
||||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
|
|
||||||
);
|
);
|
||||||
layout.setVerticalGroup(
|
layout.setVerticalGroup(
|
||||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(layout.createSequentialGroup()
|
.addComponent(jScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 335, Short.MAX_VALUE)
|
||||||
.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)
|
|
||||||
.addGap(0, 203, Short.MAX_VALUE))
|
|
||||||
);
|
);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </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
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setNode(Node selectedNode) {
|
public void setNode(Node selectedNode) {
|
||||||
if ((selectedNode == null) || (!isSupported(selectedNode))) {
|
if ((selectedNode == null) || (!isSupported(selectedNode))) {
|
||||||
@ -188,9 +213,8 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resetComponent() {
|
public void resetComponent() {
|
||||||
jSourceGoToResultButton.setVisible(false);
|
contextSourcePanels.clear();
|
||||||
setSourceName("");
|
contextUsagePanels.clear();
|
||||||
setSourceText("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -222,6 +246,9 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"ContextViewer.unknownSource=Unknown ",
|
||||||
|
})
|
||||||
/**
|
/**
|
||||||
* Looks for context providing artifacts for the given file and populates
|
* Looks for context providing artifacts for the given file and populates
|
||||||
* the source context.
|
* the source context.
|
||||||
@ -234,7 +261,7 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
|||||||
private void populateSourceContextData(AbstractFile sourceFile) throws NoCurrentCaseException, TskCoreException {
|
private void populateSourceContextData(AbstractFile sourceFile) throws NoCurrentCaseException, TskCoreException {
|
||||||
|
|
||||||
SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
|
SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
|
||||||
|
|
||||||
// Check for all context artifacts
|
// Check for all context artifacts
|
||||||
boolean foundASource = false;
|
boolean foundASource = false;
|
||||||
for (BlackboardArtifact.ARTIFACT_TYPE artifactType : SOURCE_CONTEXT_ARTIFACTS) {
|
for (BlackboardArtifact.ARTIFACT_TYPE artifactType : SOURCE_CONTEXT_ARTIFACTS) {
|
||||||
@ -245,12 +272,33 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
|||||||
addSourceEntry(contextArtifact);
|
addSourceEntry(contextArtifact);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jSourceGoToResultButton.setVisible(true);
|
javax.swing.JPanel contextContainer = new javax.swing.JPanel();
|
||||||
if (foundASource == false) {
|
contextContainer.add(jSourcePanel);
|
||||||
setSourceName("Unknown");
|
contextContainer.setLayout(new BoxLayout(contextContainer, BoxLayout.Y_AXIS));
|
||||||
showSourceText(false);
|
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();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -263,15 +311,13 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
|||||||
* @throws TskCoreException
|
* @throws TskCoreException
|
||||||
*/
|
*/
|
||||||
private void addSourceEntry(BlackboardArtifact artifact) throws TskCoreException {
|
private void addSourceEntry(BlackboardArtifact artifact) throws TskCoreException {
|
||||||
|
|
||||||
if (BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT.getTypeID() == artifact.getArtifactTypeID()) {
|
if (BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT.getTypeID() == artifact.getArtifactTypeID()) {
|
||||||
BlackboardAttribute associatedArtifactAttribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
|
BlackboardAttribute associatedArtifactAttribute = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
|
||||||
if (associatedArtifactAttribute != null) {
|
if (associatedArtifactAttribute != null) {
|
||||||
long artifactId = associatedArtifactAttribute.getValueLong();
|
long artifactId = associatedArtifactAttribute.getValueLong();
|
||||||
BlackboardArtifact associatedArtifact = artifact.getSleuthkitCase().getBlackboardArtifact(artifactId);
|
BlackboardArtifact associatedArtifact = artifact.getSleuthkitCase().getBlackboardArtifact(artifactId);
|
||||||
|
|
||||||
//save the artifact for "Go to Result" button
|
|
||||||
sourceContextArtifact = associatedArtifact;
|
|
||||||
|
|
||||||
setSourceFields(associatedArtifact);
|
setSourceFields(associatedArtifact);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -293,47 +339,27 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
|||||||
private void setSourceFields(BlackboardArtifact associatedArtifact) throws TskCoreException {
|
private void setSourceFields(BlackboardArtifact associatedArtifact) throws TskCoreException {
|
||||||
if (BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() == associatedArtifact.getArtifactTypeID()
|
if (BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() == associatedArtifact.getArtifactTypeID()
|
||||||
|| BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID() == associatedArtifact.getArtifactTypeID()) {
|
|| BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID() == associatedArtifact.getArtifactTypeID()) {
|
||||||
|
String sourceName = Bundle.ContextViewer_attachmentSource();
|
||||||
setSourceName(Bundle.ContextViewer_attachmentSource());
|
String sourceText = msgArtifactToAbbreviatedString(associatedArtifact);
|
||||||
setSourceText(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()
|
} else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD.getTypeID() == associatedArtifact.getArtifactTypeID()
|
||||||
|| BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_CACHE.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()) {
|
} else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() == associatedArtifact.getArtifactTypeID()) {
|
||||||
setSourceName(Bundle.ContextViewer_recentDocs());
|
String sourceName = Bundle.ContextViewer_recentDocs();
|
||||||
setSourceText(recentDocArtifactToString(associatedArtifact));
|
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 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a display string with download source URL from the given
|
* Returns a display string with download source URL from the given
|
||||||
* artifact.
|
* artifact.
|
||||||
@ -371,16 +397,21 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
|||||||
* @throws TskCoreException
|
* @throws TskCoreException
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"ContextViewer.file=File",
|
"ContextViewer.on=Opened at",
|
||||||
"ContextViewer.on=On"
|
"ContextViewer.unknown=Opened at unknown time"
|
||||||
})
|
})
|
||||||
private String recentDocArtifactToString(BlackboardArtifact artifact) throws TskCoreException {
|
private String recentDocArtifactToString(BlackboardArtifact artifact) throws TskCoreException {
|
||||||
StringBuilder sb = new StringBuilder(ARTIFACT_STR_MAX_LEN);
|
StringBuilder sb = new StringBuilder(ARTIFACT_STR_MAX_LEN);
|
||||||
Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributesMap = getAttributesMap(artifact);
|
Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributesMap = getAttributesMap(artifact);
|
||||||
|
|
||||||
|
BlackboardAttribute attribute = attributesMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME);
|
||||||
|
|
||||||
if (BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() == artifact.getArtifactTypeID()) {
|
if (BlackboardArtifact.ARTIFACT_TYPE.TSK_RECENT_OBJECT.getTypeID() == artifact.getArtifactTypeID()) {
|
||||||
appendAttributeString(sb, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH, attributesMap, Bundle.ContextViewer_file());
|
if (attribute.getValueLong() > 0) {
|
||||||
appendAttributeString(sb, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, attributesMap, Bundle.ContextViewer_on());
|
appendAttributeString(sb, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, attributesMap, Bundle.ContextViewer_on());
|
||||||
|
} else {
|
||||||
|
sb.append(Bundle.ContextViewer_unknown());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
@ -468,9 +499,9 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
|
|||||||
|
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private javax.swing.JButton jSourceGoToResultButton;
|
private javax.swing.JScrollPane jScrollPane;
|
||||||
private javax.swing.JLabel jSourceLabel;
|
private javax.swing.JPanel jSourcePanel;
|
||||||
private javax.swing.JLabel jSourceNameLabel;
|
private javax.swing.JPanel jUnknownPanel;
|
||||||
private javax.swing.JLabel jSourceTextLabel;
|
private javax.swing.JPanel jUsagePanel;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,7 @@ public final class UserPreferences {
|
|||||||
public static final String SHOW_ONLY_CURRENT_USER_TAGS = "ShowOnlyCurrentUserTags";
|
public static final String SHOW_ONLY_CURRENT_USER_TAGS = "ShowOnlyCurrentUserTags";
|
||||||
public static final String HIDE_SCO_COLUMNS = "HideCentralRepoCommentsAndOccurrences"; //The key for this setting pre-dates the settings current functionality //NON-NLS
|
public static final String HIDE_SCO_COLUMNS = "HideCentralRepoCommentsAndOccurrences"; //The key for this setting pre-dates the settings current functionality //NON-NLS
|
||||||
public static final String DISPLAY_TRANSLATED_NAMES = "DisplayTranslatedNames";
|
public static final String DISPLAY_TRANSLATED_NAMES = "DisplayTranslatedNames";
|
||||||
|
private static final boolean DISPLAY_TRANSLATED_NAMES_DEFAULT = true;
|
||||||
public static final String EXTERNAL_HEX_EDITOR_PATH = "ExternalHexEditorPath";
|
public static final String EXTERNAL_HEX_EDITOR_PATH = "ExternalHexEditorPath";
|
||||||
public static final String SOLR_MAX_JVM_SIZE = "SolrMaxJVMSize";
|
public static final String SOLR_MAX_JVM_SIZE = "SolrMaxJVMSize";
|
||||||
public static final String RESULTS_TABLE_PAGE_SIZE = "ResultsTablePageSize";
|
public static final String RESULTS_TABLE_PAGE_SIZE = "ResultsTablePageSize";
|
||||||
@ -265,7 +266,7 @@ public final class UserPreferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean displayTranslatedFileNames() {
|
public static boolean displayTranslatedFileNames() {
|
||||||
return preferences.getBoolean(DISPLAY_TRANSLATED_NAMES, false);
|
return preferences.getBoolean(DISPLAY_TRANSLATED_NAMES, DISPLAY_TRANSLATED_NAMES_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,6 +27,7 @@ import javax.swing.event.DocumentListener;
|
|||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
|
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
|
||||||
import org.sleuthkit.datamodel.TskData.DbType;
|
import org.sleuthkit.datamodel.TskData.DbType;
|
||||||
|
import org.sleuthkit.autopsy.centralrepository.optionspanel.GlobalSettingsPanel;
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo;
|
import org.sleuthkit.autopsy.events.MessageServiceConnectionInfo;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
@ -683,56 +684,93 @@ public final class MultiUserSettingsPanel extends javax.swing.JPanel {
|
|||||||
boolean isPwSet = (tbMsgPassword.getPassword().length != 0);
|
boolean isPwSet = (tbMsgPassword.getPassword().length != 0);
|
||||||
return (isUserSet == isPwSet);
|
return (isUserSet == isPwSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void store() {
|
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();
|
boolean multiUserCasesEnabled = cbEnableMultiUser.isSelected();
|
||||||
UserPreferences.setIsMultiUserModeEnabled(multiUserCasesEnabled);
|
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;
|
||||||
|
info = new CaseDbConnectionInfo(
|
||||||
|
tbDbHostname.getText().trim(),
|
||||||
|
tbDbPort.getText().trim(),
|
||||||
|
tbDbUsername.getText().trim(),
|
||||||
|
new String(tbDbPassword.getPassword()),
|
||||||
|
dbType);
|
||||||
|
try {
|
||||||
|
UserPreferences.setDatabaseConnectionInfo(info);
|
||||||
|
} catch (UserPreferencesException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Error saving case database connection info", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
int msgServicePort = 0;
|
||||||
|
try {
|
||||||
|
msgServicePort = Integer.parseInt(this.tbMsgPort.getText().trim());
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Could not parse messaging service port setting", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageServiceConnectionInfo msgServiceInfo = new MessageServiceConnectionInfo(
|
||||||
|
tbMsgHostname.getText().trim(),
|
||||||
|
msgServicePort,
|
||||||
|
tbMsgUsername.getText().trim(),
|
||||||
|
new String(tbMsgPassword.getPassword()));
|
||||||
|
|
||||||
|
try {
|
||||||
|
UserPreferences.setMessageServiceConnectionInfo(msgServiceInfo);
|
||||||
|
} catch (UserPreferencesException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Error saving messaging service connection info", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
* Currently only supporting multi-user cases with PostgreSQL case
|
if (prevSelected != multiUserCasesEnabled || !areCaseDbConnectionEqual(prevConn, info))
|
||||||
* databases.
|
GlobalSettingsPanel.onMultiUserChange(this, prevSelected, multiUserCasesEnabled);
|
||||||
*/
|
|
||||||
DbType dbType = DbType.POSTGRESQL;
|
|
||||||
CaseDbConnectionInfo info = new CaseDbConnectionInfo(
|
|
||||||
tbDbHostname.getText().trim(),
|
|
||||||
tbDbPort.getText().trim(),
|
|
||||||
tbDbUsername.getText().trim(),
|
|
||||||
new String(tbDbPassword.getPassword()),
|
|
||||||
dbType);
|
|
||||||
try {
|
|
||||||
UserPreferences.setDatabaseConnectionInfo(info);
|
|
||||||
} catch (UserPreferencesException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Error saving case database connection info", ex); //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
int msgServicePort = 0;
|
|
||||||
try {
|
|
||||||
msgServicePort = Integer.parseInt(this.tbMsgPort.getText().trim());
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Could not parse messaging service port setting", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageServiceConnectionInfo msgServiceInfo = new MessageServiceConnectionInfo(
|
|
||||||
tbMsgHostname.getText().trim(),
|
|
||||||
msgServicePort,
|
|
||||||
tbMsgUsername.getText().trim(),
|
|
||||||
new String(tbMsgPassword.getPassword()));
|
|
||||||
|
|
||||||
try {
|
|
||||||
UserPreferences.setMessageServiceConnectionInfo(msgServiceInfo);
|
|
||||||
} catch (UserPreferencesException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Error saving messaging service connection info", ex); //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
UserPreferences.setIndexingServerHost(tbSolrHostname.getText().trim());
|
|
||||||
UserPreferences.setIndexingServerPort(Integer.parseInt(tbSolrPort.getText().trim()));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.
|
* Validates that the form is filled out correctly for our usage.
|
||||||
*
|
*
|
||||||
|
@ -105,7 +105,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
this.content.getName(), this.content.getId()), ex);
|
this.content.getName(), this.content.getId()), ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UserPreferences.displayTranslatedFileNames()) {
|
if (TextTranslationService.getInstance().hasProvider() && UserPreferences.displayTranslatedFileNames()) {
|
||||||
backgroundTasksPool.submit(new TranslationTask(
|
backgroundTasksPool.submit(new TranslationTask(
|
||||||
new WeakReference<>(this), weakPcl));
|
new WeakReference<>(this), weakPcl));
|
||||||
}
|
}
|
||||||
@ -331,7 +331,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
* background task that promises to update these values.
|
* background task that promises to update these values.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (UserPreferences.displayTranslatedFileNames()) {
|
if (TextTranslationService.getInstance().hasProvider() && UserPreferences.displayTranslatedFileNames()) {
|
||||||
properties.add(new NodeProperty<>(ORIGINAL_NAME.toString(), ORIGINAL_NAME.toString(), NO_DESCR, ""));
|
properties.add(new NodeProperty<>(ORIGINAL_NAME.toString(), ORIGINAL_NAME.toString(), NO_DESCR, ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* 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 com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
import java.beans.PropertyChangeEvent;
|
||||||
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.openide.nodes.AbstractNode;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.AbstractContentNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract base class for background tasks needed to compute values for the
|
||||||
|
* property sheet of an AbstractNode.
|
||||||
|
*
|
||||||
|
* The results of the computation are returned by firing a PropertyChangeEvent
|
||||||
|
* and the run method has an exception firewall with logging. These features
|
||||||
|
* relieve the AbstractNode from having to create a thread to block on the get()
|
||||||
|
* method of the task Future.
|
||||||
|
*
|
||||||
|
* Only weak references to the AbstractNode and its PropertyChangeListener are
|
||||||
|
* held prior to task execution so that a queued task does not interfere with
|
||||||
|
* garbage collection if the node has been destroyed by the NetBeans framework.
|
||||||
|
*
|
||||||
|
* A thread pool with descriptively named threads (node-background-task-N) is
|
||||||
|
* provided for executing instances of the tasks.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractNodePropertySheetTask<T extends AbstractNode> implements Runnable {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(AbstractContentNode.class.getName());
|
||||||
|
private static final Integer THREAD_POOL_SIZE = 10;
|
||||||
|
private static final ExecutorService executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE, new ThreadFactoryBuilder().setNameFormat("node-background-task-%d").build());
|
||||||
|
private final WeakReference<T> weakNodeRef;
|
||||||
|
private final WeakReference<PropertyChangeListener> weakListenerRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits a task to compute values for the property sheet of an
|
||||||
|
* AbstractNode to a thread pool dedicated to such tasks with descriptively
|
||||||
|
* named threads (node-background-task-N).
|
||||||
|
*
|
||||||
|
* @param task The task.
|
||||||
|
*
|
||||||
|
* @return The Future of the task, may be used for task cancellation by
|
||||||
|
* calling Future.cancel(true).
|
||||||
|
*/
|
||||||
|
public static Future<?> submitTask(AbstractNodePropertySheetTask<?> task) {
|
||||||
|
return executor.submit(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an abstract base class for background tasks needed to compute
|
||||||
|
* values for the property sheet of an AbstractNode.
|
||||||
|
*
|
||||||
|
* The results of the computation are returned by firing a
|
||||||
|
* PropertyChangeEvent and the run method has an exception firewall with
|
||||||
|
* logging. These features relieve the AbstractNode from having to create a
|
||||||
|
* thread to block on the get() method of the task Future.
|
||||||
|
*
|
||||||
|
* Only weak references to the AbstractNode and its PropertyChangeListener
|
||||||
|
* are held prior to task execution so that a queued task does not interfere
|
||||||
|
* with garbage collection if the node has been destroyed by the NetBeans
|
||||||
|
* framework.
|
||||||
|
*
|
||||||
|
* A thread pool with descriptively named threads (node-background-task-N)
|
||||||
|
* is provided for executing instances of the tasks.
|
||||||
|
*
|
||||||
|
* @param node The node.
|
||||||
|
* @param listener A property change listener for the node.
|
||||||
|
*/
|
||||||
|
protected AbstractNodePropertySheetTask(T node, PropertyChangeListener listener) {
|
||||||
|
this.weakNodeRef = new WeakReference<>(node);
|
||||||
|
this.weakListenerRef = new WeakReference<>(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the values for the property sheet of an AbstractNode. The
|
||||||
|
* results of the computation are returned as a PropertyChangeEvent which is
|
||||||
|
* fired to the PropertyChangeEventListener of the node.
|
||||||
|
*
|
||||||
|
* IMPORTANT: Implementations of this method should check for cancellation
|
||||||
|
* by calling Thread.currentThread().isInterrupted() at appropriate
|
||||||
|
* intervals.
|
||||||
|
*
|
||||||
|
* @param node The AbstractNode.
|
||||||
|
*
|
||||||
|
* @return The result of the computation as a PropertyChangeEvent.
|
||||||
|
*/
|
||||||
|
protected abstract PropertyChangeEvent computePropertyValue(T node) throws Exception;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
final public void run() {
|
||||||
|
try {
|
||||||
|
T node = this.weakNodeRef.get();
|
||||||
|
PropertyChangeListener listener = this.weakListenerRef.get();
|
||||||
|
if (node == null || listener == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Thread.currentThread().isInterrupted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyChangeEvent changeEvent = computePropertyValue(node);
|
||||||
|
|
||||||
|
if (Thread.currentThread().isInterrupted()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changeEvent != null) {
|
||||||
|
listener.propertyChange(changeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Error executing property sheet values computation background task", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -73,6 +73,25 @@ final public class FeatureAccessUtils {
|
|||||||
return dataSourceDeletionAllowed;
|
return dataSourceDeletionAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether or not a user can delete the current case.
|
||||||
|
*
|
||||||
|
* @return True or false.
|
||||||
|
*/
|
||||||
|
public static boolean canDeleteCurrentCase() {
|
||||||
|
return currentCaseIsSingleUserCase() || multiUserCaseRestrictionsFileAbsent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether or not a user can add hash sets to the central
|
||||||
|
* repository.
|
||||||
|
*
|
||||||
|
* @return True or false.
|
||||||
|
*/
|
||||||
|
public static boolean canAddHashSetsToCentralRepo() {
|
||||||
|
return multiUserCaseRestrictionsFileAbsent();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether or not the current case is a single-user case.
|
* Indicates whether or not the current case is a single-user case.
|
||||||
*
|
*
|
||||||
@ -83,12 +102,12 @@ final public class FeatureAccessUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates whether or not the current user is allowed to create or modify
|
* Indicates whether or not the multi-user case privileges restriction file
|
||||||
* (add or delete data sources) multi-user cases.
|
* is absent.
|
||||||
*
|
*
|
||||||
* @return True or false.
|
* @return True or false.
|
||||||
*/
|
*/
|
||||||
public static boolean multiUserCaseRestrictionsFileAbsent() {
|
private static boolean multiUserCaseRestrictionsFileAbsent() {
|
||||||
File accessLimitingFile = new File(MULTIUSER_CASE_RESTRICTED_FILE_PATH);
|
File accessLimitingFile = new File(MULTIUSER_CASE_RESTRICTED_FILE_PATH);
|
||||||
return !accessLimitingFile.exists();
|
return !accessLimitingFile.exists();
|
||||||
}
|
}
|
||||||
|
@ -667,7 +667,7 @@ class FileSearch {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BufferedImage thumbnail = ScalrWrapper.resize(bufferedImage, Scalr.Method.SPEED, Scalr.Mode.FIT_TO_HEIGHT, ImageUtils.ICON_SIZE_LARGE, ImageUtils.ICON_SIZE_MEDIUM, Scalr.OP_ANTIALIAS);
|
BufferedImage thumbnail = ScalrWrapper.resize(bufferedImage, Scalr.Method.SPEED, Scalr.Mode.FIT_TO_HEIGHT, ImageUtils.ICON_SIZE_LARGE, ImageUtils.ICON_SIZE_MEDIUM, Scalr.OP_ANTIALIAS);
|
||||||
//we are height limited here so it can be wider than it can be tall, scalr maintains aspect ratio
|
//We are height limited here so it can be wider than it can be tall.Scalr maintains the aspect ratio.
|
||||||
videoThumbnails.add(thumbnail);
|
videoThumbnails.add(thumbnail);
|
||||||
if (cacheDirectory != null) {
|
if (cacheDirectory != null) {
|
||||||
try {
|
try {
|
||||||
|
@ -434,7 +434,7 @@ final public class MapPanel extends javax.swing.JPanel {
|
|||||||
/**
|
/**
|
||||||
* Find the waypoint that is closest to the given mouse click point.
|
* 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
|
* @return A waypoint that is within 10 pixels of the given point, or null
|
||||||
* if none was found.
|
* if none was found.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2014-2018 Basis Technology Corp.
|
* Copyright 2014-2020 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -51,6 +51,7 @@ final class IngestModuleFactoryLoader {
|
|||||||
private static final Logger logger = Logger.getLogger(IngestModuleFactoryLoader.class.getName());
|
private static final Logger logger = Logger.getLogger(IngestModuleFactoryLoader.class.getName());
|
||||||
private static final String SAMPLE_MODULE_FACTORY_CLASS_NAME = SampleIngestModuleFactory.class.getCanonicalName();
|
private static final String SAMPLE_MODULE_FACTORY_CLASS_NAME = SampleIngestModuleFactory.class.getCanonicalName();
|
||||||
private static final ArrayList<String> coreModuleOrdering = new ArrayList<String>() {
|
private static final ArrayList<String> coreModuleOrdering = new ArrayList<String>() {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
{
|
{
|
||||||
// The ordering of the core ingest module factories implemented
|
// The ordering of the core ingest module factories implemented
|
||||||
// using Java is hard-coded.
|
// using Java is hard-coded.
|
||||||
@ -79,7 +80,7 @@ final class IngestModuleFactoryLoader {
|
|||||||
* removed between invocations.
|
* removed between invocations.
|
||||||
*
|
*
|
||||||
* @return A list of objects that implement the IngestModuleFactory
|
* @return A list of objects that implement the IngestModuleFactory
|
||||||
* interface.
|
* interface.
|
||||||
*/
|
*/
|
||||||
static List<IngestModuleFactory> getIngestModuleFactories() {
|
static List<IngestModuleFactory> getIngestModuleFactories() {
|
||||||
// A hash set of display names and a hash map of class names to
|
// A hash set of display names and a hash map of class names to
|
||||||
@ -132,7 +133,7 @@ final class IngestModuleFactoryLoader {
|
|||||||
factories.add(factory);
|
factories.add(factory);
|
||||||
logger.log(Level.INFO, "Found ingest module factory: name = {0}, version = {1}", new Object[]{factory.getModuleDisplayName(), factory.getModuleVersionNumber()}); //NON-NLS
|
logger.log(Level.INFO, "Found ingest module factory: name = {0}, version = {1}", new Object[]{factory.getModuleDisplayName(), factory.getModuleVersionNumber()}); //NON-NLS
|
||||||
} else {
|
} else {
|
||||||
logger.log(Level.SEVERE, "Found duplicate ingest module display name (name = {0})", factory.getModuleDisplayName()); //NON-NLS
|
logger.log(Level.WARNING, "Found duplicate ingest module display name (name = {0})", factory.getModuleDisplayName()); //NON-NLS
|
||||||
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
|
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
|
||||||
NbBundle.getMessage(IngestModuleFactoryLoader.class, "IngestModuleFactoryLoader.errorMessages.duplicateDisplayName", factory.getModuleDisplayName()),
|
NbBundle.getMessage(IngestModuleFactoryLoader.class, "IngestModuleFactoryLoader.errorMessages.duplicateDisplayName", factory.getModuleDisplayName()),
|
||||||
NotifyDescriptor.ERROR_MESSAGE));
|
NotifyDescriptor.ERROR_MESSAGE));
|
||||||
@ -154,11 +155,14 @@ final class IngestModuleFactoryLoader {
|
|||||||
javaFactoriesByClass.put(factory.getClass().getCanonicalName(), factory);
|
javaFactoriesByClass.put(factory.getClass().getCanonicalName(), factory);
|
||||||
logger.log(Level.INFO, "Found ingest module factory: name = {0}, version = {1}", new Object[]{factory.getModuleDisplayName(), factory.getModuleVersionNumber()}); //NON-NLS
|
logger.log(Level.INFO, "Found ingest module factory: name = {0}, version = {1}", new Object[]{factory.getModuleDisplayName(), factory.getModuleVersionNumber()}); //NON-NLS
|
||||||
} else {
|
} else {
|
||||||
logger.log(Level.SEVERE, "Found duplicate ingest module display name (name = {0})", factory.getModuleDisplayName()); //NON-NLS
|
logger.log(Level.WARNING, "Found duplicate ingest module display name (name = {0})", factory.getModuleDisplayName()); //NON-NLS
|
||||||
DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
|
|
||||||
NbBundle.getMessage(IngestModuleFactoryLoader.class, "IngestModuleFactoryLoader.errorMessages.duplicateDisplayName", factory.getModuleDisplayName()),
|
|
||||||
NotifyDescriptor.ERROR_MESSAGE));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor to prevent instantiation of this utility class.
|
||||||
|
*/
|
||||||
|
private IngestModuleFactoryLoader() {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013-2018 Basis Technology Corp.
|
* Copyright 2013-2020 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -44,6 +44,7 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDbManagerExc
|
|||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||||
|
import org.sleuthkit.autopsy.featureaccess.FeatureAccessUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instances of this class allow a user to create a new hash database and add it
|
* Instances of this class allow a user to create a new hash database and add it
|
||||||
@ -124,29 +125,29 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
|
|||||||
setLocationRelativeTo(getOwner());
|
setLocationRelativeTo(getOwner());
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enableComponents(){
|
private void enableComponents() {
|
||||||
|
|
||||||
if(! CentralRepository.isEnabled()){
|
if (!CentralRepository.isEnabled() || !FeatureAccessUtils.canAddHashSetsToCentralRepo()) {
|
||||||
centralRepoRadioButton.setEnabled(false);
|
centralRepoRadioButton.setEnabled(false);
|
||||||
fileTypeRadioButton.setSelected(true);
|
fileTypeRadioButton.setSelected(true);
|
||||||
} else {
|
} else {
|
||||||
populateCombobox();
|
populateCombobox();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isFileType = fileTypeRadioButton.isSelected();
|
boolean isFileType = fileTypeRadioButton.isSelected();
|
||||||
|
|
||||||
// Type type only
|
// Type type only
|
||||||
databasePathLabel.setEnabled(isFileType);
|
databasePathLabel.setEnabled(isFileType);
|
||||||
databasePathTextField.setEnabled(isFileType);
|
databasePathTextField.setEnabled(isFileType);
|
||||||
saveAsButton.setEnabled(isFileType);
|
saveAsButton.setEnabled(isFileType);
|
||||||
|
|
||||||
// Central repo only
|
// Central repo only
|
||||||
lbOrg.setEnabled(! isFileType);
|
lbOrg.setEnabled(!isFileType);
|
||||||
orgButton.setEnabled(! isFileType);
|
orgButton.setEnabled(!isFileType);
|
||||||
orgComboBox.setEnabled(! isFileType);
|
orgComboBox.setEnabled(!isFileType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NbBundle.Messages({"HashDbCreateDatabaseDialog.populateOrgsError.message=Failure loading organizations."})
|
@NbBundle.Messages({"HashDbCreateDatabaseDialog.populateOrgsError.message=Failure loading organizations."})
|
||||||
private void populateCombobox() {
|
private void populateCombobox() {
|
||||||
orgComboBox.removeAllItems();
|
orgComboBox.removeAllItems();
|
||||||
@ -155,7 +156,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
|
|||||||
orgs = dbManager.getOrganizations();
|
orgs = dbManager.getOrganizations();
|
||||||
orgs.forEach((org) -> {
|
orgs.forEach((org) -> {
|
||||||
orgComboBox.addItem(org.getName());
|
orgComboBox.addItem(org.getName());
|
||||||
if(CentralRepoDbUtil.isDefaultOrg(org)){
|
if (CentralRepoDbUtil.isDefaultOrg(org)) {
|
||||||
orgComboBox.setSelectedItem(org.getName());
|
orgComboBox.setSelectedItem(org.getName());
|
||||||
selectedOrg = org;
|
selectedOrg = org;
|
||||||
}
|
}
|
||||||
@ -167,7 +168,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
|
|||||||
JOptionPane.showMessageDialog(this, Bundle.HashDbCreateDatabaseDialog_populateOrgsError_message());
|
JOptionPane.showMessageDialog(this, Bundle.HashDbCreateDatabaseDialog_populateOrgsError_message());
|
||||||
Logger.getLogger(ImportCentralRepoDbProgressDialog.class.getName()).log(Level.SEVERE, "Failure loading organizations", ex);
|
Logger.getLogger(ImportCentralRepoDbProgressDialog.class.getName()).log(Level.SEVERE, "Failure loading organizations", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called from within the constructor to initialize the form.
|
* This method is called from within the constructor to initialize the form.
|
||||||
@ -413,7 +414,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
|
|||||||
path.append(lastBaseDirectory);
|
path.append(lastBaseDirectory);
|
||||||
File hashDbFolder = new File(path.toString());
|
File hashDbFolder = new File(path.toString());
|
||||||
// create the folder if it doesn't exist
|
// create the folder if it doesn't exist
|
||||||
if (!hashDbFolder.exists()){
|
if (!hashDbFolder.exists()) {
|
||||||
hashDbFolder.mkdir();
|
hashDbFolder.mkdir();
|
||||||
}
|
}
|
||||||
if (!hashSetNameTextField.getText().isEmpty()) {
|
if (!hashSetNameTextField.getText().isEmpty()) {
|
||||||
@ -452,7 +453,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fileTypeRadioButton.isSelected()){
|
if (fileTypeRadioButton.isSelected()) {
|
||||||
if (databasePathTextField.getText().isEmpty()) {
|
if (databasePathTextField.getText().isEmpty()) {
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
@ -463,13 +464,13 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(selectedOrg == null){
|
if (selectedOrg == null) {
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
"HashDbCreateDatabaseDialog.missingOrg"),
|
"HashDbCreateDatabaseDialog.missingOrg"),
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
"HashDbCreateDatabaseDialog.createHashDbErr"),
|
"HashDbCreateDatabaseDialog.createHashDbErr"),
|
||||||
JOptionPane.ERROR_MESSAGE);
|
JOptionPane.ERROR_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -487,7 +488,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
|
|||||||
String errorMessage = NbBundle
|
String errorMessage = NbBundle
|
||||||
.getMessage(this.getClass(), "HashDbCreateDatabaseDialog.errMsg.hashDbCreationErr");
|
.getMessage(this.getClass(), "HashDbCreateDatabaseDialog.errMsg.hashDbCreationErr");
|
||||||
|
|
||||||
if(fileTypeRadioButton.isSelected()){
|
if (fileTypeRadioButton.isSelected()) {
|
||||||
try {
|
try {
|
||||||
newHashDb = HashDbManager.getInstance().addNewHashDatabaseNoSave(hashSetNameTextField.getText(), fileChooser.getSelectedFile().getCanonicalPath(), true, sendIngestMessagesCheckbox.isSelected(), type);
|
newHashDb = HashDbManager.getInstance().addNewHashDatabaseNoSave(hashSetNameTextField.getText(), fileChooser.getSelectedFile().getCanonicalPath(), true, sendIngestMessagesCheckbox.isSelected(), type);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
@ -510,17 +511,17 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Check if a hash set with the same name/version already exists
|
// Check if a hash set with the same name/version already exists
|
||||||
try{
|
try {
|
||||||
if(CentralRepository.getInstance().referenceSetExists(hashSetNameTextField.getText(), "")){
|
if (CentralRepository.getInstance().referenceSetExists(hashSetNameTextField.getText(), "")) {
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
"HashDbCreateDatabaseDialog.duplicateName"),
|
"HashDbCreateDatabaseDialog.duplicateName"),
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
"HashDbCreateDatabaseDialog.createHashDbErr"),
|
"HashDbCreateDatabaseDialog.createHashDbErr"),
|
||||||
JOptionPane.ERROR_MESSAGE);
|
JOptionPane.ERROR_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (CentralRepoException ex){
|
} catch (CentralRepoException ex) {
|
||||||
Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Error looking up reference set", ex);
|
Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Error looking up reference set", ex);
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
@ -528,16 +529,16 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
|
|||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
"HashDbCreateDatabaseDialog.createHashDbErr"),
|
"HashDbCreateDatabaseDialog.createHashDbErr"),
|
||||||
JOptionPane.ERROR_MESSAGE);
|
JOptionPane.ERROR_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try {
|
||||||
int referenceSetID = CentralRepository.getInstance().newReferenceSet(new CentralRepoFileSet(selectedOrg.getOrgID(), hashSetNameTextField.getText(),
|
int referenceSetID = CentralRepository.getInstance().newReferenceSet(new CentralRepoFileSet(selectedOrg.getOrgID(), hashSetNameTextField.getText(),
|
||||||
"", fileKnown, false, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID)));
|
"", fileKnown, false, CentralRepository.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID)));
|
||||||
newHashDb = HashDbManager.getInstance().addExistingCentralRepoHashSet(hashSetNameTextField.getText(),
|
newHashDb = HashDbManager.getInstance().addExistingCentralRepoHashSet(hashSetNameTextField.getText(),
|
||||||
"", referenceSetID,
|
"", referenceSetID,
|
||||||
true, sendIngestMessagesCheckbox.isSelected(), type, false);
|
true, sendIngestMessagesCheckbox.isSelected(), type, false);
|
||||||
} catch (CentralRepoException | TskCoreException ex){
|
} catch (CentralRepoException | TskCoreException ex) {
|
||||||
Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Error creating new reference set", ex);
|
Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Error creating new reference set", ex);
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
@ -545,8 +546,8 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
|
|||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
"HashDbCreateDatabaseDialog.createHashDbErr"),
|
"HashDbCreateDatabaseDialog.createHashDbErr"),
|
||||||
JOptionPane.ERROR_MESSAGE);
|
JOptionPane.ERROR_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose();
|
dispose();
|
||||||
@ -561,11 +562,13 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
|
|||||||
// update the combobox options
|
// update the combobox options
|
||||||
if (dialog.isChanged()) {
|
if (dialog.isChanged()) {
|
||||||
populateCombobox();
|
populateCombobox();
|
||||||
}
|
}
|
||||||
}//GEN-LAST:event_orgButtonActionPerformed
|
}//GEN-LAST:event_orgButtonActionPerformed
|
||||||
|
|
||||||
private void orgComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orgComboBoxActionPerformed
|
private void orgComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orgComboBoxActionPerformed
|
||||||
if (null == orgComboBox.getSelectedItem()) return;
|
if (null == orgComboBox.getSelectedItem()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
String orgName = this.orgComboBox.getSelectedItem().toString();
|
String orgName = this.orgComboBox.getSelectedItem().toString();
|
||||||
for (CentralRepoOrganization org : orgs) {
|
for (CentralRepoOrganization org : orgs) {
|
||||||
if (org.getName().equals(orgName)) {
|
if (org.getName().equals(orgName)) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2018 Basis Technology Corp.
|
* Copyright 2013-2020 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -42,6 +42,7 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFile
|
|||||||
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDbManagerException;
|
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDbManagerException;
|
||||||
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb;
|
import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
|
||||||
|
import org.sleuthkit.autopsy.featureaccess.FeatureAccessUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instances of this class allow a user to select an existing hash database and
|
* Instances of this class allow a user to select an existing hash database and
|
||||||
@ -89,7 +90,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
|
|||||||
String[] EXTENSION = new String[]{"txt", "kdb", "idx", "hash", "Hash", "hsh"}; //NON-NLS
|
String[] EXTENSION = new String[]{"txt", "kdb", "idx", "hash", "Hash", "hsh"}; //NON-NLS
|
||||||
FileNameExtensionFilter filter = new FileNameExtensionFilter(
|
FileNameExtensionFilter filter = new FileNameExtensionFilter(
|
||||||
NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.fileNameExtFilter.text"), EXTENSION);
|
NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.fileNameExtFilter.text"), EXTENSION);
|
||||||
fileChooser.setFileFilter(filter);
|
fileChooser.setFileFilter(filter);
|
||||||
fileChooser.setMultiSelectionEnabled(false);
|
fileChooser.setMultiSelectionEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,29 +106,28 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
|
|||||||
}
|
}
|
||||||
return shortenedPath;
|
return shortenedPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enableComponents(){
|
private void enableComponents() {
|
||||||
|
|
||||||
|
if (!CentralRepository.isEnabled() || !FeatureAccessUtils.canAddHashSetsToCentralRepo()) {
|
||||||
if(! CentralRepository.isEnabled()){
|
|
||||||
centralRepoRadioButton.setEnabled(false);
|
centralRepoRadioButton.setEnabled(false);
|
||||||
fileTypeRadioButton.setSelected(true);
|
fileTypeRadioButton.setSelected(true);
|
||||||
} else {
|
} else {
|
||||||
populateCombobox();
|
populateCombobox();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isFileType = fileTypeRadioButton.isSelected();
|
boolean isFileType = fileTypeRadioButton.isSelected();
|
||||||
|
|
||||||
// Central repo only
|
// Central repo only
|
||||||
lbVersion.setEnabled((! isFileType) && (readOnlyCheckbox.isSelected()));
|
lbVersion.setEnabled((!isFileType) && (readOnlyCheckbox.isSelected()));
|
||||||
versionTextField.setEnabled((! isFileType) && (readOnlyCheckbox.isSelected()));
|
versionTextField.setEnabled((!isFileType) && (readOnlyCheckbox.isSelected()));
|
||||||
|
|
||||||
lbOrg.setEnabled(! isFileType);
|
lbOrg.setEnabled(!isFileType);
|
||||||
orgButton.setEnabled(! isFileType);
|
orgButton.setEnabled(!isFileType);
|
||||||
orgComboBox.setEnabled(! isFileType);
|
orgComboBox.setEnabled(!isFileType);
|
||||||
readOnlyCheckbox.setEnabled(! isFileType);
|
readOnlyCheckbox.setEnabled(!isFileType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NbBundle.Messages({"HashDbImportDatabaseDialog.populateOrgsError.message=Failure loading organizations."})
|
@NbBundle.Messages({"HashDbImportDatabaseDialog.populateOrgsError.message=Failure loading organizations."})
|
||||||
private void populateCombobox() {
|
private void populateCombobox() {
|
||||||
orgComboBox.removeAllItems();
|
orgComboBox.removeAllItems();
|
||||||
@ -136,7 +136,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
|
|||||||
orgs = dbManager.getOrganizations();
|
orgs = dbManager.getOrganizations();
|
||||||
orgs.forEach((org) -> {
|
orgs.forEach((org) -> {
|
||||||
orgComboBox.addItem(org.getName());
|
orgComboBox.addItem(org.getName());
|
||||||
if(CentralRepoDbUtil.isDefaultOrg(org)){
|
if (CentralRepoDbUtil.isDefaultOrg(org)) {
|
||||||
orgComboBox.setSelectedItem(org.getName());
|
orgComboBox.setSelectedItem(org.getName());
|
||||||
selectedOrg = org;
|
selectedOrg = org;
|
||||||
}
|
}
|
||||||
@ -468,28 +468,28 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
|
|||||||
JOptionPane.ERROR_MESSAGE);
|
JOptionPane.ERROR_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(centralRepoRadioButton.isSelected()){
|
if (centralRepoRadioButton.isSelected()) {
|
||||||
if(readOnlyCheckbox.isSelected() && versionTextField.getText().isEmpty()){
|
if (readOnlyCheckbox.isSelected() && versionTextField.getText().isEmpty()) {
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
"HashDbImportDatabaseDialog.missingVersion"),
|
"HashDbImportDatabaseDialog.missingVersion"),
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
"HashDbImportDatabaseDialog.importHashDbErr"),
|
"HashDbImportDatabaseDialog.importHashDbErr"),
|
||||||
JOptionPane.ERROR_MESSAGE);
|
JOptionPane.ERROR_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(selectedOrg == null){
|
if (selectedOrg == null) {
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
"HashDbImportDatabaseDialog.missingOrg"),
|
"HashDbImportDatabaseDialog.missingOrg"),
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
"HashDbImportDatabaseDialog.importHashDbErr"),
|
"HashDbImportDatabaseDialog.importHashDbErr"),
|
||||||
JOptionPane.ERROR_MESSAGE);
|
JOptionPane.ERROR_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedFilePath.isEmpty()) {
|
if (selectedFilePath.isEmpty()) {
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
@ -500,7 +500,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
|
|||||||
JOptionPane.ERROR_MESSAGE);
|
JOptionPane.ERROR_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
File file = new File(selectedFilePath);
|
File file = new File(selectedFilePath);
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
@ -523,11 +523,11 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
|
|||||||
String errorMessage = NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.unableToCopyToUserDirMsg", locationInUserConfigDir);
|
String errorMessage = NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.unableToCopyToUserDirMsg", locationInUserConfigDir);
|
||||||
Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, errorMessage, ex);
|
Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, errorMessage, ex);
|
||||||
JOptionPane.showMessageDialog(this, errorMessage, NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.importHashDbErr"),
|
JOptionPane.showMessageDialog(this, errorMessage, NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.importHashDbErr"),
|
||||||
JOptionPane.ERROR_MESSAGE);
|
JOptionPane.ERROR_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KnownFilesType type;
|
KnownFilesType type;
|
||||||
if (knownRadioButton.isSelected()) {
|
if (knownRadioButton.isSelected()) {
|
||||||
type = KnownFilesType.KNOWN;
|
type = KnownFilesType.KNOWN;
|
||||||
@ -536,9 +536,9 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String errorMessage = NbBundle.getMessage(this.getClass(),
|
String errorMessage = NbBundle.getMessage(this.getClass(),
|
||||||
"HashDbImportDatabaseDialog.errorMessage.failedToOpenHashDbMsg",
|
"HashDbImportDatabaseDialog.errorMessage.failedToOpenHashDbMsg",
|
||||||
selectedFilePath);
|
selectedFilePath);
|
||||||
if(fileTypeRadioButton.isSelected()){
|
if (fileTypeRadioButton.isSelected()) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
selectedHashDb = HashDbManager.getInstance().addExistingHashDatabaseNoSave(hashSetNameTextField.getText(), selectedFilePath, true, sendIngestMessagesCheckbox.isSelected(), type);
|
selectedHashDb = HashDbManager.getInstance().addExistingHashDatabaseNoSave(hashSetNameTextField.getText(), selectedFilePath, true, sendIngestMessagesCheckbox.isSelected(), type);
|
||||||
@ -552,19 +552,19 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Check if a hash set with the same name/version already exists
|
// Check if a hash set with the same name/version already exists
|
||||||
try{
|
try {
|
||||||
if(CentralRepository.getInstance().referenceSetExists(hashSetNameTextField.getText(), versionTextField.getText())){
|
if (CentralRepository.getInstance().referenceSetExists(hashSetNameTextField.getText(), versionTextField.getText())) {
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
"HashDbImportDatabaseDialog.duplicateName"),
|
"HashDbImportDatabaseDialog.duplicateName"),
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
"HashDbImportDatabaseDialog.importHashDbErr"),
|
"HashDbImportDatabaseDialog.importHashDbErr"),
|
||||||
JOptionPane.ERROR_MESSAGE);
|
JOptionPane.ERROR_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (CentralRepoException ex){
|
} catch (CentralRepoException ex) {
|
||||||
Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Error looking up reference set", ex);
|
Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Error looking up reference set", ex);
|
||||||
JOptionPane.showMessageDialog(this,
|
JOptionPane.showMessageDialog(this,
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
@ -572,20 +572,20 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
|
|||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
"HashDbImportDatabaseDialog.importHashDbErr"),
|
"HashDbImportDatabaseDialog.importHashDbErr"),
|
||||||
JOptionPane.ERROR_MESSAGE);
|
JOptionPane.ERROR_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String version;
|
String version;
|
||||||
if(readOnlyCheckbox.isSelected()){
|
if (readOnlyCheckbox.isSelected()) {
|
||||||
version = versionTextField.getText();
|
version = versionTextField.getText();
|
||||||
} else {
|
} else {
|
||||||
// Editable databases don't have a version
|
// Editable databases don't have a version
|
||||||
version = "";
|
version = "";
|
||||||
}
|
}
|
||||||
ImportCentralRepoDbProgressDialog progressDialog = new ImportCentralRepoDbProgressDialog();
|
ImportCentralRepoDbProgressDialog progressDialog = new ImportCentralRepoDbProgressDialog();
|
||||||
progressDialog.importFile(hashSetNameTextField.getText(), version,
|
progressDialog.importFile(hashSetNameTextField.getText(), version,
|
||||||
selectedOrg.getOrgID(), true, sendIngestMessagesCheckbox.isSelected(), type,
|
selectedOrg.getOrgID(), true, sendIngestMessagesCheckbox.isSelected(), type,
|
||||||
readOnlyCheckbox.isSelected(), selectedFilePath);
|
readOnlyCheckbox.isSelected(), selectedFilePath);
|
||||||
selectedHashDb = progressDialog.getDatabase();
|
selectedHashDb = progressDialog.getDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -609,11 +609,13 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
|
|||||||
// update the combobox options
|
// update the combobox options
|
||||||
if (dialog.isChanged()) {
|
if (dialog.isChanged()) {
|
||||||
populateCombobox();
|
populateCombobox();
|
||||||
}
|
}
|
||||||
}//GEN-LAST:event_orgButtonActionPerformed
|
}//GEN-LAST:event_orgButtonActionPerformed
|
||||||
|
|
||||||
private void orgComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orgComboBoxActionPerformed
|
private void orgComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orgComboBoxActionPerformed
|
||||||
if (null == orgComboBox.getSelectedItem()) return;
|
if (null == orgComboBox.getSelectedItem()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
String orgName = this.orgComboBox.getSelectedItem().toString();
|
String orgName = this.orgComboBox.getSelectedItem().toString();
|
||||||
for (CentralRepoOrganization org : orgs) {
|
for (CentralRepoOrganization org : orgs) {
|
||||||
if (org.getName().equals(orgName)) {
|
if (org.getName().equals(orgName)) {
|
||||||
|
@ -0,0 +1,242 @@
|
|||||||
|
/*
|
||||||
|
* 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.texttranslation.ui;
|
||||||
|
|
||||||
|
import java.awt.ComponentOrientation;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.SwingWorker;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.TextUtil;
|
||||||
|
import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException;
|
||||||
|
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
|
||||||
|
import org.sleuthkit.autopsy.texttranslation.TranslationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an abstract class for translating text and displaying to the user.
|
||||||
|
*/
|
||||||
|
public abstract class TranslateTextTask extends SwingWorker<TranslateTextTask.TranslateResult, Void> {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(TranslatedTextViewer.class.getName());
|
||||||
|
|
||||||
|
private final boolean translateText;
|
||||||
|
private final String contentDescriptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a result of running and processing the translation.
|
||||||
|
*/
|
||||||
|
public static class TranslateResult {
|
||||||
|
|
||||||
|
private final String errorMessage;
|
||||||
|
private final String result;
|
||||||
|
private final boolean successful;
|
||||||
|
|
||||||
|
public static TranslateResult error(String message) {
|
||||||
|
return new TranslateResult(null, message, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TranslateResult success(String content) {
|
||||||
|
return new TranslateResult(content, null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TranslateResult(String result, String errorMessage, boolean successful) {
|
||||||
|
this.successful = successful;
|
||||||
|
this.errorMessage = errorMessage;
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrorMessage() {
|
||||||
|
return errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSuccessful() {
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the main constructor for the TranslateTextTask.
|
||||||
|
* @param translateText whether or not to translate text
|
||||||
|
* @param fileDescriptor the content descriptor for the item being
|
||||||
|
* translated (used for logging errors)
|
||||||
|
*/
|
||||||
|
public TranslateTextTask(boolean translateText, String fileDescriptor) {
|
||||||
|
this.translateText = translateText;
|
||||||
|
this.contentDescriptor = fileDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method retrieves the original text content to be translated.
|
||||||
|
* @return the original text content
|
||||||
|
* @throws IOException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws IllegalStateException
|
||||||
|
*/
|
||||||
|
protected abstract String retrieveText() throws IOException, InterruptedException, IllegalStateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method should be overridden when a translated text result is received.
|
||||||
|
* @param text the text to display
|
||||||
|
* @param orientation the orientation of the text
|
||||||
|
* @param font the font style (returns plain)
|
||||||
|
*/
|
||||||
|
protected abstract void onTextDisplay(String text, ComponentOrientation orientation, int font);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a progress result is received, this method is called.
|
||||||
|
* This method can be overridden depending on the scenario, but defaults to just displaying using onTextDisplay.
|
||||||
|
* @param text the text of the status update
|
||||||
|
* @param orientation the orientation for the status
|
||||||
|
* @param font the font style of the status
|
||||||
|
*/
|
||||||
|
protected void onProgressDisplay(String text, ComponentOrientation orientation, int font) {
|
||||||
|
// This defaults to normal display unless overridden.
|
||||||
|
onTextDisplay(text, orientation, font);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When an error result is received, this method is called. This method can be overridden depending on the
|
||||||
|
* scenario but defaults to just displaying using onTextDisplay.
|
||||||
|
* @param text the text of the error
|
||||||
|
* @param orientation the orientation for the error
|
||||||
|
* @param font the font style of the error
|
||||||
|
*/
|
||||||
|
protected void onErrorDisplay(String text, ComponentOrientation orientation, int font) {
|
||||||
|
// This defaults to normal display unless overridden.
|
||||||
|
onTextDisplay(text, orientation, font);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"TranslatedContentViewer.translatingText=Translating text, please wait...",
|
||||||
|
"TranslatedContentViewer.fileHasNoText=File has no text.",
|
||||||
|
"TranslatedContentViewer.noServiceProvider=The machine translation software was not found.",
|
||||||
|
"# {0} - exception message", "TranslatedContentViewer.translationException=An error occurred while translating the text ({0})."
|
||||||
|
})
|
||||||
|
@Override
|
||||||
|
public TranslateResult doInBackground() throws InterruptedException {
|
||||||
|
if (this.isCancelled()) {
|
||||||
|
throw new InterruptedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
String fileText;
|
||||||
|
try {
|
||||||
|
fileText = retrieveText();
|
||||||
|
} catch (IOException | IllegalStateException ex) {
|
||||||
|
return TranslateResult.error(ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isCancelled()) {
|
||||||
|
throw new InterruptedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileText == null || fileText.isEmpty()) {
|
||||||
|
return TranslateResult.error(Bundle.TranslatedContentViewer_fileHasNoText());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.translateText) {
|
||||||
|
return TranslateResult.success(fileText);
|
||||||
|
}
|
||||||
|
|
||||||
|
return translateRetrievedText(fileText);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the final step in the translation swing worker prior to being {@link #done() done()}; translates the text if needed.
|
||||||
|
* @param fileText the text to translate
|
||||||
|
* @return the translated text
|
||||||
|
* @throws InterruptedException if operation is canclled, an interrupted exception is thrown
|
||||||
|
*/
|
||||||
|
private TranslateResult translateRetrievedText(String fileText) throws InterruptedException {
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
onProgressDisplay(Bundle.TranslatedContentViewer_translatingText(), ComponentOrientation.LEFT_TO_RIGHT, Font.ITALIC);
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
String translation = translate(fileText);
|
||||||
|
if (this.isCancelled()) {
|
||||||
|
throw new InterruptedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (translation == null || translation.isEmpty()) {
|
||||||
|
return TranslateResult.error(Bundle.TranslatedContentViewer_emptyTranslation());
|
||||||
|
} else {
|
||||||
|
return TranslateResult.success(translation);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (NoServiceProviderException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error translating text for file " + this.contentDescriptor, ex);
|
||||||
|
return TranslateResult.error(Bundle.TranslatedContentViewer_noServiceProvider());
|
||||||
|
} catch (TranslationException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error translating text for file " + this.contentDescriptor, ex);
|
||||||
|
return TranslateResult.error(Bundle.TranslatedContentViewer_translationException(ex.getMessage()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void done() {
|
||||||
|
try {
|
||||||
|
TranslateResult executionResult = get();
|
||||||
|
if (this.isCancelled()) {
|
||||||
|
throw new InterruptedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (executionResult.isSuccessful()) {
|
||||||
|
String result = executionResult.getResult();
|
||||||
|
int len = result.length();
|
||||||
|
int maxOrientChars = Math.min(len, 1024);
|
||||||
|
String orientDetectSubstring = result.substring(0, maxOrientChars);
|
||||||
|
ComponentOrientation orientation = TextUtil.getTextDirection(orientDetectSubstring);
|
||||||
|
onTextDisplay(result, orientation, Font.PLAIN);
|
||||||
|
} else {
|
||||||
|
onErrorDisplay(executionResult.getErrorMessage(), ComponentOrientation.LEFT_TO_RIGHT, Font.ITALIC);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException | CancellationException ignored) {
|
||||||
|
// Task cancelled, no error.
|
||||||
|
} catch (ExecutionException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error occurred during background task execution for file " + this.contentDescriptor, ex);
|
||||||
|
onErrorDisplay(Bundle.TranslatedContentViewer_translationException(ex.getMessage()), ComponentOrientation.LEFT_TO_RIGHT, Font.ITALIC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method passes the translation off to the {@link org.sleuthkit.autopsy.texttranslation.TextTranslationService translation service provider}.
|
||||||
|
*
|
||||||
|
* @param input text to be translated
|
||||||
|
*
|
||||||
|
* @return translated text or error message
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"TranslatedContentViewer.emptyTranslation=The machine translation software did not return any text."
|
||||||
|
})
|
||||||
|
protected String translate(String input) throws NoServiceProviderException, TranslationException {
|
||||||
|
TextTranslationService translatorInstance = TextTranslationService.getInstance();
|
||||||
|
return translatorInstance.translate(input);
|
||||||
|
}
|
||||||
|
}
|
@ -28,8 +28,6 @@ import java.awt.event.ActionListener;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.CancellationException;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ThreadFactory;
|
import java.util.concurrent.ThreadFactory;
|
||||||
@ -37,19 +35,15 @@ import org.openide.nodes.Node;
|
|||||||
import org.openide.util.lookup.ServiceProvider;
|
import org.openide.util.lookup.ServiceProvider;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.TextViewer;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.TextViewer;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import javax.swing.SwingWorker;
|
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.corecomponents.DataContentViewerUtility;
|
import org.sleuthkit.autopsy.corecomponents.DataContentViewerUtility;
|
||||||
import org.sleuthkit.autopsy.coreutils.ExecUtil.ProcessTerminator;
|
import org.sleuthkit.autopsy.coreutils.ExecUtil.ProcessTerminator;
|
||||||
import org.sleuthkit.autopsy.coreutils.TextUtil;
|
|
||||||
import org.sleuthkit.autopsy.textextractors.TextExtractor;
|
import org.sleuthkit.autopsy.textextractors.TextExtractor;
|
||||||
import org.sleuthkit.autopsy.textextractors.TextExtractorFactory;
|
import org.sleuthkit.autopsy.textextractors.TextExtractorFactory;
|
||||||
import org.sleuthkit.autopsy.textextractors.configs.ImageConfig;
|
import org.sleuthkit.autopsy.textextractors.configs.ImageConfig;
|
||||||
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
|
import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
|
||||||
import org.sleuthkit.autopsy.texttranslation.NoServiceProviderException;
|
|
||||||
import org.sleuthkit.autopsy.texttranslation.TranslationException;
|
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -160,114 +154,41 @@ public final class TranslatedTextViewer implements TextViewer {
|
|||||||
/**
|
/**
|
||||||
* Extracts text from a file and optionally translates it.
|
* Extracts text from a file and optionally translates it.
|
||||||
*/
|
*/
|
||||||
private class ExtractAndTranslateTextTask extends SwingWorker<String, Void> {
|
private class ExtractAndTranslateTextTask extends TranslateTextTask {
|
||||||
|
|
||||||
private final AbstractFile file;
|
private final AbstractFile file;
|
||||||
private final boolean translateText;
|
|
||||||
|
|
||||||
private ExtractAndTranslateTextTask(AbstractFile file, boolean translateText) {
|
private ExtractAndTranslateTextTask(AbstractFile file, boolean translateText) {
|
||||||
|
super(translateText, String.format("%s (objId=%d)", file.getName(), file.getId()));
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.translateText = translateText;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NbBundle.Messages({
|
|
||||||
"TranslatedContentViewer.extractingText=Extracting text, please wait...",
|
|
||||||
"TranslatedContentViewer.translatingText=Translating text, please wait...",
|
|
||||||
"# {0} - exception message", "TranslatedContentViewer.errorExtractingText=An error occurred while extracting the text ({0}).",
|
|
||||||
"TranslatedContentViewer.fileHasNoText=File has no text.",
|
|
||||||
"TranslatedContentViewer.noServiceProvider=The machine translation software was not found.",
|
|
||||||
"# {0} - exception message", "TranslatedContentViewer.translationException=An error occurred while translating the text ({0})."
|
|
||||||
})
|
|
||||||
@Override
|
|
||||||
public String doInBackground() throws InterruptedException {
|
|
||||||
if (this.isCancelled()) {
|
|
||||||
throw new InterruptedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
SwingUtilities.invokeLater(() -> {
|
|
||||||
panel.display(Bundle.TranslatedContentViewer_extractingText(), ComponentOrientation.LEFT_TO_RIGHT, Font.ITALIC);
|
|
||||||
});
|
|
||||||
String fileText;
|
|
||||||
try {
|
|
||||||
fileText = getFileText(file);
|
|
||||||
} catch (IOException | TextExtractor.InitReaderException ex) {
|
|
||||||
logger.log(Level.WARNING, String.format("Error extracting text for file %s (objId=%d)", file.getName(), file.getId()), ex);
|
|
||||||
return Bundle.TranslatedContentViewer_errorExtractingText(ex.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isCancelled()) {
|
|
||||||
throw new InterruptedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fileText == null || fileText.isEmpty()) {
|
|
||||||
return Bundle.TranslatedContentViewer_fileHasNoText();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.translateText) {
|
|
||||||
return fileText;
|
|
||||||
}
|
|
||||||
|
|
||||||
SwingUtilities.invokeLater(() -> {
|
|
||||||
panel.display(Bundle.TranslatedContentViewer_translatingText(), ComponentOrientation.LEFT_TO_RIGHT, Font.ITALIC);
|
|
||||||
});
|
|
||||||
String translation;
|
|
||||||
try {
|
|
||||||
translation = translate(fileText);
|
|
||||||
} catch (NoServiceProviderException ex) {
|
|
||||||
logger.log(Level.WARNING, String.format("Error translating text for file %s (objId=%d)", file.getName(), file.getId()), ex);
|
|
||||||
translation = Bundle.TranslatedContentViewer_noServiceProvider();
|
|
||||||
} catch (TranslationException ex) {
|
|
||||||
logger.log(Level.WARNING, String.format("Error translating text for file %s (objId=%d)", file.getName(), file.getId()), ex);
|
|
||||||
translation = Bundle.TranslatedContentViewer_translationException(ex.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isCancelled()) {
|
|
||||||
throw new InterruptedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
return translation;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void done() {
|
|
||||||
try {
|
|
||||||
String result = get();
|
|
||||||
if (this.isCancelled()) {
|
|
||||||
throw new InterruptedException();
|
|
||||||
}
|
|
||||||
int len = result.length();
|
|
||||||
int maxOrientChars = Math.min(len, 1024);
|
|
||||||
String orientDetectSubstring = result.substring(0, maxOrientChars);
|
|
||||||
ComponentOrientation orientation = TextUtil.getTextDirection(orientDetectSubstring);
|
|
||||||
panel.display(result, orientation, Font.PLAIN);
|
|
||||||
|
|
||||||
} catch (InterruptedException | CancellationException ignored) {
|
|
||||||
// Task cancelled, no error.
|
|
||||||
} catch (ExecutionException ex) {
|
|
||||||
logger.log(Level.WARNING, String.format("Error occurred during background task execution for file %s (objId=%d)", file.getName(), file.getId()), ex);
|
|
||||||
panel.display(Bundle.TranslatedContentViewer_translationException(ex.getMessage()), ComponentOrientation.LEFT_TO_RIGHT, Font.ITALIC);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pass the translation off to the Translation service provider.
|
* Extracts text from the current node
|
||||||
*
|
*
|
||||||
* @param input Text to be translated
|
* @return Extracted text
|
||||||
*
|
*
|
||||||
* @return Translated text or error message
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@NbBundle.Messages({
|
@NbBundle.Messages({
|
||||||
"TranslatedContentViewer.emptyTranslation=The machine translation software did not return any text."
|
"TranslatedContentViewer.extractingText=Extracting text, please wait...",
|
||||||
|
"# {0} - exception message", "TranslatedContentViewer.errorExtractingText=An error occurred while extracting the text ({0}).",
|
||||||
})
|
})
|
||||||
private String translate(String input) throws NoServiceProviderException, TranslationException {
|
protected String retrieveText() throws IOException, InterruptedException, IllegalStateException {
|
||||||
TextTranslationService translatorInstance = TextTranslationService.getInstance();
|
SwingUtilities.invokeLater(() -> {
|
||||||
String translatedResult = translatorInstance.translate(input);
|
onProgressDisplay(Bundle.TranslatedContentViewer_extractingText(), ComponentOrientation.LEFT_TO_RIGHT, Font.ITALIC);
|
||||||
if (translatedResult.isEmpty()) {
|
});
|
||||||
return Bundle.TranslatedContentViewer_emptyTranslation();
|
|
||||||
}
|
|
||||||
return translatedResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
return getFileText(file);
|
||||||
|
} catch (IOException | TextExtractor.InitReaderException ex) {
|
||||||
|
logger.log(Level.WARNING, String.format("Error extracting text for file %s (objId=%d)", file.getName(), file.getId()), ex);
|
||||||
|
// throw new exception with message to be displayed to user
|
||||||
|
throw new IllegalStateException(Bundle.TranslatedContentViewer_errorExtractingText(ex.getMessage()), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts text from the given node
|
* Extracts text from the given node
|
||||||
*
|
*
|
||||||
@ -280,9 +201,7 @@ public final class TranslatedTextViewer implements TextViewer {
|
|||||||
* @throws
|
* @throws
|
||||||
* org.sleuthkit.autopsy.textextractors.TextExtractor.InitReaderException
|
* org.sleuthkit.autopsy.textextractors.TextExtractor.InitReaderException
|
||||||
*/
|
*/
|
||||||
private String getFileText(AbstractFile file) throws IOException,
|
private String getFileText(AbstractFile file) throws IOException, InterruptedException, TextExtractor.InitReaderException {
|
||||||
InterruptedException, TextExtractor.InitReaderException {
|
|
||||||
|
|
||||||
final boolean isImage = file.getMIMEType().toLowerCase().startsWith("image/"); // NON-NLS
|
final boolean isImage = file.getMIMEType().toLowerCase().startsWith("image/"); // NON-NLS
|
||||||
String result;
|
String result;
|
||||||
if (isImage) {
|
if (isImage) {
|
||||||
@ -382,8 +301,15 @@ public final class TranslatedTextViewer implements TextViewer {
|
|||||||
return TextExtractorFactory.getStringsExtractor(file, context).getReader();
|
return TextExtractorFactory.getStringsExtractor(file, context).getReader();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onTextDisplay(String text, ComponentOrientation orientation, int font) {
|
||||||
|
panel.display(text, orientation, font);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listens for drop-down selection changes and pushes processing off of the
|
* Listens for drop-down selection changes and pushes processing off of the
|
||||||
* EDT and into a SwingWorker.
|
* EDT and into a SwingWorker.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2014-2019 Basis Technology Corp.
|
* Copyright 2014-2020 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -72,7 +72,6 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
|||||||
import org.sleuthkit.autopsy.coreutils.History;
|
import org.sleuthkit.autopsy.coreutils.History;
|
||||||
import org.sleuthkit.autopsy.coreutils.LoggedTask;
|
import org.sleuthkit.autopsy.coreutils.LoggedTask;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
|
||||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
@ -806,7 +805,6 @@ public class TimeLineController {
|
|||||||
future.get();
|
future.get();
|
||||||
} catch (InterruptedException | ExecutionException ex) {
|
} catch (InterruptedException | ExecutionException ex) {
|
||||||
logger.log(Level.SEVERE, errorLogMessage, ex);
|
logger.log(Level.SEVERE, errorLogMessage, ex);
|
||||||
MessageNotifyUtil.Message.error(errorUserMessage);
|
|
||||||
}
|
}
|
||||||
}, MoreExecutors.directExecutor());
|
}, MoreExecutors.directExecutor());
|
||||||
}
|
}
|
||||||
|
@ -130,8 +130,7 @@ public class CentralRepoDatamodelTest extends TestCase {
|
|||||||
|
|
||||||
dbSettingsSqlite.saveSettings();
|
dbSettingsSqlite.saveSettings();
|
||||||
CentralRepoDbUtil.setUseCentralRepo(true);
|
CentralRepoDbUtil.setUseCentralRepo(true);
|
||||||
CentralRepoPlatforms.setSelectedPlatform(CentralRepoPlatforms.SQLITE.name());
|
CentralRepoDbManager.saveDbChoice(CentralRepoDbChoice.SQLITE);
|
||||||
CentralRepoPlatforms.saveSelectedPlatform();
|
|
||||||
} catch (CentralRepoException ex) {
|
} catch (CentralRepoException ex) {
|
||||||
Exceptions.printStackTrace(ex);
|
Exceptions.printStackTrace(ex);
|
||||||
Assert.fail(ex.getMessage());
|
Assert.fail(ex.getMessage());
|
||||||
|
@ -47,6 +47,8 @@ import org.sleuthkit.autopsy.testutils.IngestUtils;
|
|||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
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.CorrelationAttributeInstance;
|
||||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
|
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
|
||||||
import org.sleuthkit.autopsy.coreutils.TimeStampUtils;
|
import org.sleuthkit.autopsy.coreutils.TimeStampUtils;
|
||||||
@ -303,8 +305,7 @@ class InterCaseTestUtils {
|
|||||||
centralRepoSchemaFactory.insertDefaultDatabaseContent();
|
centralRepoSchemaFactory.insertDefaultDatabaseContent();
|
||||||
|
|
||||||
crSettings.saveSettings();
|
crSettings.saveSettings();
|
||||||
CentralRepoPlatforms.setSelectedPlatform(CentralRepoPlatforms.SQLITE.name());
|
CentralRepoDbManager.saveDbChoice(CentralRepoDbChoice.SQLITE);
|
||||||
CentralRepoPlatforms.saveSelectedPlatform();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,7 +37,7 @@ public class ScalrWrapper {
|
|||||||
return Scalr.resize(input, size, Scalr.OP_ANTIALIAS);
|
return Scalr.resize(input, size, Scalr.OP_ANTIALIAS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static synchronized BufferedImage resize(BufferedImage bufferedImage, Method method, Scalr.Mode mode, int width, int height, BufferedImageOp... ops) {
|
public static synchronized BufferedImage resize(BufferedImage bufferedImage, Method method, Scalr.Mode mode, int width, int height, BufferedImageOp ...ops) {
|
||||||
return Scalr.resize(bufferedImage, method, mode, width, height, ops);
|
return Scalr.resize(bufferedImage, method, mode, width, height, ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,12 @@ from org.sleuthkit.datamodel import BlackboardArtifact
|
|||||||
from org.sleuthkit.datamodel import BlackboardAttribute
|
from org.sleuthkit.datamodel import BlackboardAttribute
|
||||||
from org.sleuthkit.datamodel import TskCoreException
|
from org.sleuthkit.datamodel import TskCoreException
|
||||||
from org.sleuthkit.datamodel.blackboardutils import GeoArtifactsHelper
|
from org.sleuthkit.datamodel.blackboardutils import GeoArtifactsHelper
|
||||||
from org.sleuthkit.datamodel.blackboardutils.attributes import GeoWaypoint
|
from org.sleuthkit.datamodel.blackboardutils.attributes import TskGeoWaypointsUtil
|
||||||
from org.sleuthkit.datamodel.blackboardutils.attributes import GeoTrackPoints
|
from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil import GeoWaypointList
|
||||||
|
from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoWaypointsUtil.GeoWaypointList import GeoWaypoint
|
||||||
|
from org.sleuthkit.datamodel.blackboardutils.attributes import TskGeoTrackpointsUtil
|
||||||
|
from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil import GeoTrackPointList
|
||||||
|
from org.sleuthkit.datamodel.blackboardutils.attributes.TskGeoTrackpointsUtil.GeoTrackPointList import GeoTrackPoint
|
||||||
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
||||||
from org.sleuthkit.autopsy.ingest import IngestModule
|
from org.sleuthkit.autopsy.ingest import IngestModule
|
||||||
from org.sleuthkit.autopsy.ingest.IngestModule import IngestModuleException
|
from org.sleuthkit.autopsy.ingest.IngestModule import IngestModuleException
|
||||||
@ -63,20 +67,15 @@ import gpxpy.parser
|
|||||||
class GPXParserDataSourceIngestModuleFactory(IngestModuleFactoryAdapter):
|
class GPXParserDataSourceIngestModuleFactory(IngestModuleFactoryAdapter):
|
||||||
|
|
||||||
moduleName = "GPX Parser"
|
moduleName = "GPX Parser"
|
||||||
|
|
||||||
# True - Verbose debugging messages sent to log file.
|
|
||||||
# False - Verbose debugging turned off.
|
|
||||||
debuglevel = False
|
|
||||||
|
|
||||||
def getModuleDisplayName(self):
|
def getModuleDisplayName(self):
|
||||||
return self.moduleName
|
return self.moduleName
|
||||||
|
|
||||||
# TODO: Give it a description
|
|
||||||
def getModuleDescription(self):
|
def getModuleDescription(self):
|
||||||
return "Module that extracts GEO data from GPX files."
|
return "Module that extracts GEO data from GPX files."
|
||||||
|
|
||||||
def getModuleVersionNumber(self):
|
def getModuleVersionNumber(self):
|
||||||
return "1.1"
|
return "1.2"
|
||||||
|
|
||||||
def isDataSourceIngestModuleFactory(self):
|
def isDataSourceIngestModuleFactory(self):
|
||||||
return True
|
return True
|
||||||
@ -88,10 +87,11 @@ class GPXParserDataSourceIngestModuleFactory(IngestModuleFactoryAdapter):
|
|||||||
# Data Source-level ingest module. One gets created per data source.
|
# Data Source-level ingest module. One gets created per data source.
|
||||||
class GPXParserDataSourceIngestModule(DataSourceIngestModule):
|
class GPXParserDataSourceIngestModule(DataSourceIngestModule):
|
||||||
|
|
||||||
_logger = Logger.getLogger(GPXParserDataSourceIngestModuleFactory.moduleName)
|
logger = Logger.getLogger(GPXParserDataSourceIngestModuleFactory.moduleName)
|
||||||
|
writeDebugMsgs = False
|
||||||
|
|
||||||
def log(self, level, msg):
|
def log(self, level, msg):
|
||||||
self._logger.logp(level, self.__class__.__name__, inspect.stack()[1][3], msg)
|
self.logger.logp(level, self.__class__.__name__, inspect.stack()[1][3], msg)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.context = None
|
self.context = None
|
||||||
@ -105,179 +105,130 @@ class GPXParserDataSourceIngestModule(DataSourceIngestModule):
|
|||||||
|
|
||||||
# We don't know how much work there is yet.
|
# We don't know how much work there is yet.
|
||||||
progressBar.switchToIndeterminate()
|
progressBar.switchToIndeterminate()
|
||||||
|
|
||||||
# This will work in 4.0.1 and beyond.
|
|
||||||
# Use blackboard class to index blackboard artifacts for keyword search.
|
|
||||||
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
|
||||||
|
|
||||||
# Get the sleuthkitcase
|
# Get the case database and its blackboard.
|
||||||
skCase = Case.getCurrentCase().getSleuthkitCase()
|
skCase = Case.getCurrentCase().getSleuthkitCase()
|
||||||
|
blackboard = skCase.getBlackboard()
|
||||||
|
|
||||||
# In the name and then count and read them.
|
# Get any files with a .gpx extension.
|
||||||
fileManager = Case.getCurrentCase().getServices().getFileManager()
|
# It would perhaps be better to get these files by MIME type instead.
|
||||||
|
# RC: It would also be better if this were a file level ingest module so it could process files extracted from archives.
|
||||||
|
fileManager = Case.getCurrentCase().getServices().getFileManager()
|
||||||
files = fileManager.findFiles(dataSource, "%.gpx")
|
files = fileManager.findFiles(dataSource, "%.gpx")
|
||||||
# TODO: Would like to change this to find files based on mimetype rather than extension.
|
|
||||||
#files = findFiles(dataSource, "text/xml")
|
|
||||||
#if (file.isMimeType('text/xml') == False):
|
|
||||||
|
|
||||||
|
# Update the progress bar now that we know how much work there is to do.
|
||||||
numFiles = len(files)
|
numFiles = len(files)
|
||||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "found " + str(numFiles) + " files")
|
if self.writeDebugMsgs: self.log(Level.INFO, "Found " + str(numFiles) + " GPX files")
|
||||||
progressBar.switchToDeterminate(numFiles)
|
progressBar.switchToDeterminate(numFiles)
|
||||||
fileCount = 0;
|
|
||||||
|
|
||||||
# Get module name for adding attributes
|
# Get the module name, it will be needed for adding attributes
|
||||||
moduleName = GPXParserDataSourceIngestModuleFactory.moduleName
|
moduleName = GPXParserDataSourceIngestModuleFactory.moduleName
|
||||||
|
|
||||||
|
# Check if a folder for this module is present in the case Temp directory.
|
||||||
|
# If not, create it.
|
||||||
|
dirName = os.path.join(Case.getCurrentCase().getTempDirectory(), "GPX_Parser_Module")
|
||||||
|
try:
|
||||||
|
os.stat(dirName)
|
||||||
|
except:
|
||||||
|
os.mkdir(dirName)
|
||||||
|
|
||||||
|
# Create a temp file name. It appears that we cannot close and delete
|
||||||
|
# this file, but we can overwrite it for each file we need to process.
|
||||||
|
fileName = os.path.join(dirName, "tmp.gpx")
|
||||||
|
|
||||||
|
fileCount = 0;
|
||||||
for file in files:
|
for file in files:
|
||||||
|
|
||||||
# Get the GeoArtifactsHelper
|
# Create a GeoArtifactsHelper for this file.
|
||||||
geoArtifactHelper = GeoArtifactsHelper(skCase, moduleName, file)
|
geoArtifactHelper = GeoArtifactsHelper(skCase, moduleName, None, file)
|
||||||
|
|
||||||
# Check if the user pressed cancel while we were busy.
|
# Check if the user pressed cancel while we were busy.
|
||||||
if self.context.isJobCancelled():
|
if self.context.isJobCancelled():
|
||||||
return IngestModule.ProcessResult.OK
|
return IngestModule.ProcessResult.OK
|
||||||
|
|
||||||
#self.log(Level.INFO, "GPX: Processing file: " + file.getName())
|
if self.writeDebugMsgs: self.log(Level.INFO, "Processing " + file.getUniquePath() + " (objID = " + str(file.getId()) + ")")
|
||||||
fileCount += 1
|
fileCount += 1
|
||||||
|
|
||||||
# Check if module folder is present. If not, create it.
|
# Write the file so that it can be parsed by gpxpy.
|
||||||
dirName = os.path.join(Case.getCurrentCase().getTempDirectory(), "GPX_Parser_Module")
|
|
||||||
try:
|
|
||||||
os.stat(dirName)
|
|
||||||
except:
|
|
||||||
os.mkdir(dirName)
|
|
||||||
fileName = os.path.join(dirName, "tmp.gpx")
|
|
||||||
|
|
||||||
# Check to see if temporary file exists. If it does, remove it.
|
|
||||||
if os.path.exists(fileName):
|
|
||||||
try:
|
|
||||||
os.remove(fileName)
|
|
||||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "GPX:\t" + "FILE DELETED " + fileName )
|
|
||||||
except:
|
|
||||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "GPX:\t" + "FILE NOT DELETED " + fileName)
|
|
||||||
|
|
||||||
# This writes the file to the local file system.
|
|
||||||
localFile = File(fileName)
|
localFile = File(fileName)
|
||||||
ContentUtils.writeToFile(file, localFile)
|
ContentUtils.writeToFile(file, localFile)
|
||||||
|
|
||||||
# Send to gpxpy for parsing.
|
# Send the file to gpxpy for parsing.
|
||||||
gpxfile = open(fileName)
|
gpxfile = open(fileName)
|
||||||
try:
|
try:
|
||||||
gpx = gpxpy.parse(gpxfile)
|
gpx = gpxpy.parse(gpxfile)
|
||||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "GPX:\t" + "FILE PARSED")
|
if self.writeDebugMsgs: self.log(Level.INFO, "Parsed " + file.getUniquePath() + " (objID = " + str(file.getId()) + ")")
|
||||||
except:
|
except Exception as e:
|
||||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.SEVERE, "GPX:\t" + file.getName() + " - FILE NOT PARSED")
|
self.log(Level.WARNING, "Error parsing file " + file.getUniquePath() + " (objID = " + str(file.getId()) + "):" + str(e))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if gpx:
|
if gpx:
|
||||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "GPX: TRACKS")
|
if self.writeDebugMsgs: self.log(Level.INFO, "Processing tracks from " + file.getUniquePath() + " (objID = " + str(file.getId()) + ")")
|
||||||
for track in gpx.tracks:
|
for track in gpx.tracks:
|
||||||
for segment in track.segments:
|
for segment in track.segments:
|
||||||
geoPointList = ArrayList()
|
geoPointList = TskGeoTrackpointsUtil.GeoTrackPointList()
|
||||||
for point in segment.points:
|
for point in segment.points:
|
||||||
|
|
||||||
elevation = 0
|
elevation = 0
|
||||||
if point.elevation != None:
|
if point.elevation != None:
|
||||||
elevation = point.elevation
|
elevation = point.elevation
|
||||||
|
|
||||||
dateTime = 0
|
timeStamp = 0
|
||||||
try:
|
try:
|
||||||
if (point.time != None):
|
if (point.time != None):
|
||||||
datetime = long(time.mktime(point.time.timetuple()))
|
timeStamp = long(time.mktime(point.time.timetuple()))
|
||||||
except:
|
except Exception as e:
|
||||||
pass
|
self.log(Level.WARNING, "Error getting track timestamp from " + file.getUniquePath() + " (objID = " + str(file.getId()) + "):" + str(e))
|
||||||
|
|
||||||
geoPointList.add(GeoWaypoint.GeoTrackPoint(point.latitude, point.longitude, elevation, 0, 0, 0, dateTime))
|
geoPointList.addPoint(GeoTrackPoint(point.latitude, point.longitude, elevation, None, 0, 0, 0, timeStamp))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Add the trackpoint using the helper class
|
geoArtifactHelper.addTrack("Track", geoPointList, None)
|
||||||
geoartifact = geoArtifactHelper.addTrack("Trackpoint", geoPointList)
|
|
||||||
except Blackboard.BlackboardException as e:
|
except Blackboard.BlackboardException as e:
|
||||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.SEVERE, "GPX: Error using geo artifact helper with blackboard " )
|
self.log(Level.SEVERE, "Error posting GPS track artifact for " + file.getUniquePath() + " (objID = " + str(file.getId()) + "):" + e.getMessage())
|
||||||
except TskCoreException as e:
|
except TskCoreException as e:
|
||||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.SEVERE, "GPX: Error using geo artifact helper tskcoreexception" )
|
self.log(Level.SEVERE, "Error creating GPS track artifact for " + file.getUniquePath() + " (objID = " + str(file.getId()) + "):" + e.getMessage())
|
||||||
|
|
||||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "GPX: WAYPOINTS")
|
if self.writeDebugMsgs: self.log(Level.INFO, "Processing waypoints from " + file.getUniquePath() + " (objID = " + str(file.getId()) + ")")
|
||||||
for waypoint in gpx.waypoints:
|
for waypoint in gpx.waypoints:
|
||||||
attributes = ArrayList()
|
|
||||||
art = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK)
|
|
||||||
|
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID(), moduleName, waypoint.latitude))
|
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID(), moduleName, waypoint.longitude))
|
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FLAG.getTypeID(), moduleName, "Waypoint"))
|
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), moduleName, waypoint.name))
|
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID(), moduleName, "GPXParser"))
|
|
||||||
|
|
||||||
art.addAttributes(attributes)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Post the artifact to blackboard
|
art = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_BOOKMARK)
|
||||||
skCase.getBlackboard().postArtifact(art, moduleName)
|
|
||||||
|
attributes = ArrayList()
|
||||||
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID(), moduleName, waypoint.latitude))
|
||||||
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID(), moduleName, waypoint.longitude))
|
||||||
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FLAG.getTypeID(), moduleName, "Waypoint"))
|
||||||
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), moduleName, waypoint.name))
|
||||||
|
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID(), moduleName, "GPXParser"))
|
||||||
|
art.addAttributes(attributes)
|
||||||
|
|
||||||
|
blackboard.postArtifact(art, moduleName)
|
||||||
|
|
||||||
except Blackboard.BlackboardException as e:
|
except Blackboard.BlackboardException as e:
|
||||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.SEVERE, "GPX: Error using geo artifact helper with blackboard for waypoints" )
|
self.log(Level.SEVERE, "Error posting GPS bookmark artifact for " + file.getUniquePath() + " (objID = " + str(file.getId()) + "):" + e.getMessage())
|
||||||
|
except TskCoreException as e:
|
||||||
|
self.log(Level.SEVERE, "Error creating GPS bookmark artifact for " + file.getUniquePath() + " (objID = " + str(file.getId()) + "):" + e.getMessage())
|
||||||
|
|
||||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "GPX: ROUTES")
|
if self.writeDebugMsgs: self.log(Level.INFO, "Processing routes from " + file.getUniquePath() + " (objID = " + str(file.getId()) + ")")
|
||||||
for route in gpx.routes:
|
for route in gpx.routes:
|
||||||
firstTimeThru = 0
|
|
||||||
startingPoint = list()
|
geoWaypointList = TskGeoWaypointsUtil.GeoWaypointList()
|
||||||
endingPoint = list()
|
|
||||||
for point in route.points:
|
for point in route.points:
|
||||||
# If first time in loop only populate starting point
|
geoWaypointList.addPoint(GeoWaypoint(point.latitude, point.longitude, point.elevation, point.name))
|
||||||
if (firstTimeThru == 0):
|
|
||||||
startingPoint.append((point.latitude, point.longitude))
|
|
||||||
firstTimeThru = 1
|
|
||||||
else:
|
|
||||||
startingPoint.append((point.latitude, point.longitude))
|
|
||||||
endingPoint.append((point.latitude, point.longitude))
|
|
||||||
|
|
||||||
if (len(endingPoint) > 0):
|
try:
|
||||||
# get length of ending point as this ensures that we have equal points to process.
|
geoArtifactHelper.addRoute(None, None, geoWaypointList, None)
|
||||||
for i in range(0,len(endingPoint) -1):
|
except Blackboard.BlackboardException as e:
|
||||||
attributes = ArrayList()
|
self.log("Error posting GPS route artifact for " + file.getUniquePath() + " (objID = " + str(file.getId()) + "):" + e.getMessage())
|
||||||
art = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE)
|
except TskCoreException as e:
|
||||||
|
self.log(Level.SEVERE, "Error creating GPS route artifact for " + file.getUniquePath() + " (objID = " + str(file.getId()) + "):" + e.getMessage())
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START.getTypeID(), moduleName, startingPoint[i][0]))
|
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START.getTypeID(), moduleName, startingPoint[i][1]))
|
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END.getTypeID(), moduleName, endingPoint[i][0]))
|
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END.getTypeID(), moduleName, endingPoint[i][1]))
|
|
||||||
|
|
||||||
art.addAttributes(attributes)
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Post the artifact to blackboard
|
|
||||||
skCase.getBlackboard().postArtifact(art, moduleName)
|
|
||||||
except Blackboard.BlackboardException as e:
|
|
||||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.SEVERE, "GPX: Error using geo artifact helper with blackboard for waypoints" )
|
|
||||||
else:
|
|
||||||
if (len(startingPoint) > 0):
|
|
||||||
attributes = ArrayList()
|
|
||||||
art = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE)
|
|
||||||
|
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START.getTypeID(), moduleName, startingPoint[0][0]))
|
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START.getTypeID(), moduleName, startingPoint[0][1]))
|
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END.getTypeID(), moduleName, startingPoint[0][0]))
|
|
||||||
attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END.getTypeID(), moduleName, startingPoint[0][1]))
|
|
||||||
|
|
||||||
art.addAttributes(attributes)
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Post the artifact to blackboard
|
|
||||||
skCase.getBlackboard().postArtifact(art, moduleName)
|
|
||||||
except Blackboard.BlackboardException as e:
|
|
||||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.SEVERE, "GPX: Error using geo artifact helper with blackboard for waypoints" )
|
|
||||||
|
|
||||||
|
|
||||||
# Update the progress bar.
|
# Update the progress bar.
|
||||||
progressBar.progress(fileCount)
|
progressBar.progress(fileCount)
|
||||||
if os.path.exists(fileName):
|
|
||||||
try:
|
|
||||||
os.remove(fileName)
|
|
||||||
if GPXParserDataSourceIngestModuleFactory.debuglevel: self.log(Level.INFO, "GPX:\t" + "FILE DELETED")
|
|
||||||
except:
|
|
||||||
self.log(Level.SEVERE, "GPX:\t" + "FILE NOT DELETED")
|
|
||||||
|
|
||||||
# Post a message to the ingest messages inbox.
|
# Post a message to the ingest messages inbox.
|
||||||
message = IngestMessage.createMessage(IngestMessage.MessageType.DATA, "GPX Parser Data Source Ingest Module", "Found %d files" % fileCount)
|
message = IngestMessage.createMessage(IngestMessage.MessageType.DATA, moduleName, "Processed %d files" % fileCount)
|
||||||
IngestServices.getInstance().postMessage(message)
|
IngestServices.getInstance().postMessage(message)
|
||||||
return IngestModule.ProcessResult.OK;
|
return IngestModule.ProcessResult.OK;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user