mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
Merge remote-tracking branch 'upstream/develop' into improve-open-multi-user-case-dialog-performance
This commit is contained in:
commit
690aab95c3
@ -77,6 +77,7 @@ import org.sleuthkit.autopsy.casemodule.events.CommentChangedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.DataSourceNameChangedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ReportAddedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.services.Services;
|
||||
import org.sleuthkit.autopsy.commonpropertiessearch.CommonAttributeSearchAction;
|
||||
@ -310,6 +311,11 @@ public class Case {
|
||||
* was deleted (type: Long), the new value is null.
|
||||
*/
|
||||
DATA_SOURCE_DELETED,
|
||||
/**
|
||||
* A data source's name has changed. The new value of the property
|
||||
* change event is the new name.
|
||||
*/
|
||||
DATA_SOURCE_NAME_CHANGED,
|
||||
/**
|
||||
* The current case has changed.
|
||||
*
|
||||
@ -1583,6 +1589,19 @@ public class Case {
|
||||
public void notifyDataSourceAdded(Content dataSource, UUID addingDataSourceEventId) {
|
||||
eventPublisher.publish(new DataSourceAddedEvent(dataSource, addingDataSourceEventId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies case event subscribers that a data source has been added to the
|
||||
* case database.
|
||||
*
|
||||
* This should not be called from the event dispatch thread (EDT)
|
||||
*
|
||||
* @param dataSource The data source.
|
||||
* @param newName The new name for the data source
|
||||
*/
|
||||
public void notifyDataSourceNameChanged(Content dataSource, String newName) {
|
||||
eventPublisher.publish(new DataSourceNameChangedEvent(dataSource, newName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies case event subscribers that a content tag has been added.
|
||||
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2015-2019 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.casemodule.events;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class DataSourceNameChangedEvent extends AutopsyEvent implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger logger = Logger.getLogger(DataSourceAddedEvent.class.getName());
|
||||
private transient Content dataSource;
|
||||
private final String newName;
|
||||
|
||||
/**
|
||||
* Constructs an event published when a data source is added to a case.
|
||||
*
|
||||
* @param dataSource The data source that was added.
|
||||
* @param newName The new name of the data source
|
||||
*/
|
||||
public DataSourceNameChangedEvent(Content dataSource, String newName) {
|
||||
/**
|
||||
* Putting the object id of the data source into newValue to allow for
|
||||
* lazy loading of the Content object. This bypasses the issues related
|
||||
* to the serialization and de-serialization of Content objects when the
|
||||
* event is published over a network.
|
||||
*/
|
||||
super(Case.Events.DATA_SOURCE_NAME_CHANGED.toString(), null, dataSource.getId());
|
||||
this.dataSource = dataSource;
|
||||
this.newName = newName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the new name for the data source
|
||||
*
|
||||
* @return The new name for the data source
|
||||
*/
|
||||
@Override
|
||||
public Object getNewValue() {
|
||||
return newName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data source that was added.
|
||||
*
|
||||
* @return The data source.
|
||||
*/
|
||||
public Content getDataSource() {
|
||||
/**
|
||||
* The dataSource field is set in the constructor, but it is transient
|
||||
* so it will become null when the event is serialized for publication
|
||||
* over a network. Doing a lazy load of the Content object bypasses the
|
||||
* issues related to the serialization and de-serialization of Content
|
||||
* objects and may also save database round trips from other nodes since
|
||||
* subscribers to this event are often not interested in the event data.
|
||||
*/
|
||||
if (null != dataSource) {
|
||||
return dataSource;
|
||||
}
|
||||
try {
|
||||
long id = (Long) super.getNewValue();
|
||||
dataSource = Case.getCurrentCaseThrows().getSleuthkitCase().getContentById(id);
|
||||
return dataSource;
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error doing lazy load for remote event", ex); //NON-NLS
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -900,6 +900,50 @@ abstract class AbstractSqlEamDb implements EamDb {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the name of a data source in the DB
|
||||
*
|
||||
* @param eamDataSource The data source
|
||||
* @param newName The new name
|
||||
*
|
||||
* @throws EamDbException
|
||||
*/
|
||||
@Override
|
||||
public void updateDataSourceName(CorrelationDataSource eamDataSource, String newName) throws EamDbException {
|
||||
|
||||
Connection conn = connect();
|
||||
|
||||
PreparedStatement preparedStatement = null;
|
||||
|
||||
String sql = "UPDATE data_sources SET name = ? WHERE id = ?";
|
||||
|
||||
try {
|
||||
preparedStatement = conn.prepareStatement(sql);
|
||||
preparedStatement.setString(1, newName);
|
||||
preparedStatement.setInt(2, eamDataSource.getID());
|
||||
preparedStatement.executeUpdate();
|
||||
|
||||
CorrelationDataSource updatedDataSource = new CorrelationDataSource(
|
||||
eamDataSource.getCaseID(),
|
||||
eamDataSource.getID(),
|
||||
eamDataSource.getDeviceID(),
|
||||
newName,
|
||||
eamDataSource.getDataSourceObjectID(),
|
||||
eamDataSource.getMd5(),
|
||||
eamDataSource.getSha1(),
|
||||
eamDataSource.getSha256());
|
||||
|
||||
dataSourceCacheByDsObjectId.put(getDataSourceByDSObjectIdCacheKey(updatedDataSource.getCaseID(), updatedDataSource.getDataSourceObjectID()), updatedDataSource);
|
||||
dataSourceCacheById.put(getDataSourceByIdCacheKey(updatedDataSource.getCaseID(), updatedDataSource.getID()), updatedDataSource);
|
||||
} catch (SQLException ex) {
|
||||
throw new EamDbException("Error updating name of data source with ID " + eamDataSource.getDataSourceObjectID()
|
||||
+ " to " + newName, ex); // NON-NLS
|
||||
} finally {
|
||||
EamDbUtil.closeStatement(preparedStatement);
|
||||
EamDbUtil.closeConnection(conn);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts new Artifact(s) into the database. Should add associated Case and
|
||||
* Data Source first.
|
||||
|
@ -133,6 +133,9 @@ public class EamArtifactUtil {
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_SIM_ATTACHED.getTypeID()) {
|
||||
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IMSI, CorrelationAttributeInstance.IMSI_TYPE_ID);
|
||||
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ICCID, CorrelationAttributeInstance.ICCID_TYPE_ID);
|
||||
} else if (artifactTypeID == ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS.getTypeID()) {
|
||||
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, CorrelationAttributeInstance.PHONE_TYPE_ID);
|
||||
addCorrelationAttributeToList(eamArtifacts, artifactForInstance, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, CorrelationAttributeInstance.EMAIL_TYPE_ID);
|
||||
}
|
||||
}
|
||||
} catch (EamDbException ex) {
|
||||
|
@ -255,6 +255,16 @@ public interface EamDb {
|
||||
*/
|
||||
List<CorrelationDataSource> getDataSources() throws EamDbException;
|
||||
|
||||
/**
|
||||
* Changes the name of a data source in the DB
|
||||
*
|
||||
* @param eamDataSource The data source
|
||||
* @param newName The new name
|
||||
*
|
||||
* @throws EamDbException
|
||||
*/
|
||||
void updateDataSourceName(CorrelationDataSource eamDataSource, String newName) throws EamDbException;
|
||||
|
||||
/**
|
||||
* Inserts new Artifact(s) into the database. Should add associated Case and
|
||||
* Data Source first.
|
||||
|
@ -434,6 +434,24 @@ final class SqliteEamDb extends AbstractSqlEamDb {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the name of a data source in the DB
|
||||
*
|
||||
* @param eamDataSource The data source
|
||||
* @param newName The new name
|
||||
*
|
||||
* @throws EamDbException
|
||||
*/
|
||||
@Override
|
||||
public void updateDataSourceName(CorrelationDataSource eamDataSource, String newName) throws EamDbException {
|
||||
try {
|
||||
acquireExclusiveLock();
|
||||
super.updateDataSourceName(eamDataSource, newName);
|
||||
} finally {
|
||||
releaseExclusiveLock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the MD5 hash value in an existing data source in the database.
|
||||
*
|
||||
|
@ -26,6 +26,7 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
@ -34,6 +35,7 @@ import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.DataSourceAddedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.events.DataSourceNameChangedEvent;
|
||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
|
||||
@ -106,6 +108,10 @@ final class CaseEventListener implements PropertyChangeListener {
|
||||
jobProcessingExecutor.submit(new CurrentCaseTask(dbManager, evt));
|
||||
}
|
||||
break;
|
||||
case DATA_SOURCE_NAME_CHANGED: {
|
||||
jobProcessingExecutor.submit(new DataSourceNameChangedTask(dbManager, evt));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -489,4 +495,40 @@ final class CaseEventListener implements PropertyChangeListener {
|
||||
}
|
||||
} // CURRENT_CASE
|
||||
}
|
||||
|
||||
private final class DataSourceNameChangedTask implements Runnable {
|
||||
|
||||
private final EamDb dbManager;
|
||||
private final PropertyChangeEvent event;
|
||||
|
||||
private DataSourceNameChangedTask(EamDb db, PropertyChangeEvent evt) {
|
||||
dbManager = db;
|
||||
event = evt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
final DataSourceNameChangedEvent dataSourceNameChangedEvent = (DataSourceNameChangedEvent) event;
|
||||
Content dataSource = dataSourceNameChangedEvent.getDataSource();
|
||||
String newName = (String) event.getNewValue();
|
||||
|
||||
if (! StringUtils.isEmpty(newName)) {
|
||||
|
||||
if (!EamDb.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
CorrelationCase correlationCase = dbManager.getCase(Case.getCurrentCaseThrows());
|
||||
CorrelationDataSource existingEamDataSource = dbManager.getDataSource(correlationCase, dataSource.getId());
|
||||
dbManager.updateDataSourceName(existingEamDataSource, newName);
|
||||
} catch (EamDbException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error updating data source with ID " + dataSource.getId() + " to " + newName, ex); //NON-NLS
|
||||
} catch (NoCurrentCaseException ex) {
|
||||
LOGGER.log(Level.SEVERE, "No open case", ex);
|
||||
}
|
||||
}
|
||||
} // DATA_SOURCE_NAME_CHANGED
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2014-2018 Basis Technology Corp.
|
||||
* Copyright 2014-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -27,7 +27,6 @@ import java.util.prefs.Preferences;
|
||||
import org.openide.util.NbPreferences;
|
||||
import org.python.icu.util.TimeZone;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.TextConverterException;
|
||||
import org.sleuthkit.autopsy.coreutils.Version;
|
||||
import org.sleuthkit.datamodel.CaseDbConnectionInfo;
|
||||
@ -76,6 +75,7 @@ public final class UserPreferences {
|
||||
public static final String HIDE_CENTRAL_REPO_COMMENTS_AND_OCCURRENCES = "HideCentralRepoCommentsAndOccurrences";
|
||||
public static final String DISPLAY_TRANSLATED_NAMES = "DisplayTranslatedNames";
|
||||
public static final String EXTERNAL_HEX_EDITOR_PATH = "ExternalHexEditorPath";
|
||||
public static final String SOLR_MAX_JVM_SIZE = "SolrMaxJVMSize";
|
||||
|
||||
// Prevent instantiation.
|
||||
private UserPreferences() {
|
||||
@ -473,6 +473,24 @@ public final class UserPreferences {
|
||||
preferences.putInt(MAX_NUM_OF_LOG_FILE, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum JVM heap size (in MB) for the embedded Solr server.
|
||||
*
|
||||
* @return Saved value or default (512)
|
||||
*/
|
||||
public static int getMaxSolrVMSize() {
|
||||
return preferences.getInt(SOLR_MAX_JVM_SIZE, 512);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum JVM heap size (in MB) for the embedded Solr server.
|
||||
*
|
||||
* @param maxSize
|
||||
*/
|
||||
public static void setMaxSolrVMSize(int maxSize) {
|
||||
preferences.putInt(SOLR_MAX_JVM_SIZE, maxSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HdX path.
|
||||
*
|
||||
|
@ -78,7 +78,7 @@
|
||||
</folder>
|
||||
<folder name="Tools">
|
||||
<file name="org-sleuthkit-autopsy-filesearch-FileSearchAction.instance"/>
|
||||
<file name="org-sleuthkit-autopsy-commonfilesearch-CommonAttributeSearchAction.instance"/>
|
||||
<file name="org-sleuthkit-autopsy-commonpropertiessearch-CommonAttributeSearchAction.instance"/>
|
||||
<file name="org-sleuthkit-autopsy-ingest-IngestMessagesAction.instance">
|
||||
<attr name="delegate" newvalue="org.sleuthkit.autopsy.ingest.IngestMessagesAction"/>
|
||||
</file>
|
||||
@ -202,8 +202,8 @@
|
||||
<file name="org-netbeans-modules-options-OptionsWindowAction.shadow"/>
|
||||
<file name="org-netbeans-modules-templates-actions-TemplatesAction.shadow_hidden"/>
|
||||
<file name="org-openide-actions-ToolsAction.shadow_hidden"/>
|
||||
<file name="org-sleuthkit-autopsy-commonfilesearch-CommonFilesAction.shadow">
|
||||
<attr name="originalFile" stringvalue="Actions/Tools/org-sleuthkit-autopsy-commonfilesearch-CommonAttributeSearchAction.instance"/>
|
||||
<file name="org-sleuthkit-autopsy-commonpropertiessearch-CommonFilesAction.shadow">
|
||||
<attr name="originalFile" stringvalue="Actions/Tools/org-sleuthkit-autopsy-commonpropertiessearch-CommonAttributeSearchAction.instance"/>
|
||||
<attr name="position" intvalue="202"/>
|
||||
</file>
|
||||
<file name="org-sleuthkit-autopsy-filesearch-FileSearchAction.shadow">
|
||||
|
@ -68,7 +68,7 @@
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="runtimePanel" max="32767" attributes="0"/>
|
||||
<Component id="logoPanel" alignment="0" pref="1002" max="32767" attributes="0"/>
|
||||
<Component id="logoPanel" alignment="0" pref="1010" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
@ -81,7 +81,7 @@
|
||||
<Component id="runtimePanel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="logoPanel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="185" max="32767" attributes="0"/>
|
||||
<EmptySpace pref="191" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@ -121,7 +121,7 @@
|
||||
</Group>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="agencyLogoPreview" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace pref="479" max="32767" attributes="0"/>
|
||||
<EmptySpace pref="456" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@ -241,39 +241,37 @@
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="totalMemoryLabel" linkSize="1" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="maxSolrMemoryLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="maxMemoryLabel" linkSize="1" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="maxLogFileCount" linkSize="1" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="12" pref="12" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="logFileCount" linkSize="3" alignment="1" min="-2" pref="37" max="-2" attributes="0"/>
|
||||
<Component id="solrMaxHeapSpinner" alignment="1" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="memField" linkSize="3" alignment="1" min="-2" pref="37" max="-2" attributes="0"/>
|
||||
<Component id="systemMemoryTotal" alignment="1" min="-2" pref="37" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="maxMemoryUnitsLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="maxMemoryUnitsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="maxMemoryUnitsLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="totalMemoryLabel" linkSize="1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="systemMemoryTotal" min="-2" pref="37" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="maxMemoryUnitsLabel1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="restartNecessaryWarning" pref="783" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="maxMemoryUnitsLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="memFieldValidationLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="maxMemoryLabel" linkSize="1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="memField" linkSize="3" min="-2" pref="37" max="-2" attributes="0"/>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="maxLogFileCount" linkSize="1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="logFileCount" linkSize="3" min="-2" pref="37" max="-2" attributes="0"/>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="120" max="-2" attributes="0"/>
|
||||
<Component id="logNumAlert" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="23" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="restartNecessaryWarning" alignment="0" pref="718" max="32767" attributes="0"/>
|
||||
<Component id="memFieldValidationLabel" alignment="0" min="-2" pref="478" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
@ -292,21 +290,27 @@
|
||||
<Component id="systemMemoryTotal" alignment="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="maxMemoryLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="memField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="maxMemoryUnitsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="maxMemoryLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="memField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="maxMemoryUnitsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="memFieldValidationLabel" alignment="0" min="-2" pref="16" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="logNumAlert" min="-2" max="-2" attributes="0"/>
|
||||
<Group type="103" alignment="0" groupAlignment="3" attributes="0">
|
||||
<Component id="maxSolrMemoryLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="maxMemoryUnitsLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="solrMaxHeapSpinner" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Component id="memFieldValidationLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="maxLogFileCount" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="logFileCount" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="logNumAlert" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<EmptySpace pref="14" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@ -404,6 +408,25 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="maxSolrMemoryLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.maxSolrMemoryLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="maxMemoryUnitsLabel2">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.maxMemoryUnitsLabel2.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JSpinner" name="solrMaxHeapSpinner">
|
||||
<Events>
|
||||
<EventHandler event="stateChanged" listener="javax.swing.event.ChangeListener" parameters="javax.swing.event.ChangeEvent" handler="solrMaxHeapSpinnerStateChanged"/>
|
||||
</Events>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2018 Basis Technology Corp.
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -75,7 +75,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
private static final String ETC_FOLDER_NAME = "etc";
|
||||
private static final String CONFIG_FILE_EXTENSION = ".conf";
|
||||
private static final long ONE_BILLION = 1000000000L; //used to roughly convert system memory from bytes to gigabytes
|
||||
private static final long MEGA_IN_GIGA = 1024; //used to convert memory settings saved as megabytes to gigabytes
|
||||
private static final int MEGA_IN_GIGA = 1024; //used to convert memory settings saved as megabytes to gigabytes
|
||||
private static final int MIN_MEMORY_IN_GB = 2; //the enforced minimum memory in gigabytes
|
||||
private static final Logger logger = Logger.getLogger(AutopsyOptionsPanel.class.getName());
|
||||
private String initialMemValue = Long.toString(Runtime.getRuntime().maxMemory() / ONE_BILLION);
|
||||
@ -96,8 +96,13 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
//Is the safest course of action
|
||||
//And the file won't exist in the install folder when running through netbeans
|
||||
memField.setEnabled(false);
|
||||
solrMaxHeapSpinner.setEnabled(false);
|
||||
}
|
||||
systemMemoryTotal.setText(Long.toString(getSystemMemoryInGB()));
|
||||
// The cast to int in the following is to ensure that the correct SpinnerNumberModel
|
||||
// constructor is called.
|
||||
solrMaxHeapSpinner.setModel(new javax.swing.SpinnerNumberModel(UserPreferences.getMaxSolrVMSize(),
|
||||
512, ((int)getSystemMemoryInGB()) * MEGA_IN_GIGA, 512));
|
||||
|
||||
textFieldListener = new TextFieldListener();
|
||||
agencyLogoPathField.getDocument().addDocumentListener(textFieldListener);
|
||||
@ -292,6 +297,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
agencyLogoPathField.setEnabled(!useDefault);
|
||||
browseLogosButton.setEnabled(!useDefault);
|
||||
logFileCount.setText(String.valueOf(UserPreferences.getLogFileCount()));
|
||||
solrMaxHeapSpinner.setValue(UserPreferences.getMaxSolrVMSize());
|
||||
try {
|
||||
updateAgencyLogo(path);
|
||||
} catch (IOException ex) {
|
||||
@ -349,6 +355,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
} else {
|
||||
ModuleSettings.setConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP, "");
|
||||
}
|
||||
UserPreferences.setMaxSolrVMSize((int)solrMaxHeapSpinner.getValue());
|
||||
if (memField.isEnabled()) { //if the field could of been changed we need to try and save it
|
||||
try {
|
||||
writeEtcConfFile();
|
||||
@ -531,6 +538,9 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
maxLogFileCount = new javax.swing.JLabel();
|
||||
logFileCount = new javax.swing.JTextField();
|
||||
logNumAlert = new javax.swing.JTextField();
|
||||
maxSolrMemoryLabel = new javax.swing.JLabel();
|
||||
maxMemoryUnitsLabel2 = new javax.swing.JLabel();
|
||||
solrMaxHeapSpinner = new javax.swing.JSpinner();
|
||||
|
||||
setPreferredSize(new java.awt.Dimension(1022, 488));
|
||||
|
||||
@ -595,7 +605,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
.addComponent(agencyLogoPathFieldValidationLabel))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(agencyLogoPreview, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(479, Short.MAX_VALUE))
|
||||
.addContainerGap(456, Short.MAX_VALUE))
|
||||
);
|
||||
logoPanelLayout.setVerticalGroup(
|
||||
logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
@ -653,39 +663,47 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
logNumAlert.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.logNumAlert.text")); // NOI18N
|
||||
logNumAlert.setBorder(null);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(maxSolrMemoryLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.maxSolrMemoryLabel.text")); // NOI18N
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(maxMemoryUnitsLabel2, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.maxMemoryUnitsLabel2.text")); // NOI18N
|
||||
|
||||
solrMaxHeapSpinner.addChangeListener(new javax.swing.event.ChangeListener() {
|
||||
public void stateChanged(javax.swing.event.ChangeEvent evt) {
|
||||
solrMaxHeapSpinnerStateChanged(evt);
|
||||
}
|
||||
});
|
||||
|
||||
javax.swing.GroupLayout runtimePanelLayout = new javax.swing.GroupLayout(runtimePanel);
|
||||
runtimePanel.setLayout(runtimePanelLayout);
|
||||
runtimePanelLayout.setHorizontalGroup(
|
||||
runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(runtimePanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(totalMemoryLabel)
|
||||
.addComponent(maxSolrMemoryLabel)
|
||||
.addComponent(maxMemoryLabel)
|
||||
.addComponent(maxLogFileCount))
|
||||
.addGap(12, 12, 12)
|
||||
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(logFileCount, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(solrMaxHeapSpinner, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(memField, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(systemMemoryTotal, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGap(18, 18, 18)
|
||||
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(maxMemoryUnitsLabel1)
|
||||
.addComponent(maxMemoryUnitsLabel)
|
||||
.addComponent(maxMemoryUnitsLabel2))
|
||||
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(runtimePanelLayout.createSequentialGroup()
|
||||
.addComponent(totalMemoryLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(systemMemoryTotal, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(6, 6, 6)
|
||||
.addGap(120, 120, 120)
|
||||
.addComponent(logNumAlert))
|
||||
.addGroup(runtimePanelLayout.createSequentialGroup()
|
||||
.addGap(23, 23, 23)
|
||||
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(runtimePanelLayout.createSequentialGroup()
|
||||
.addComponent(maxMemoryUnitsLabel1)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(restartNecessaryWarning, javax.swing.GroupLayout.DEFAULT_SIZE, 783, Short.MAX_VALUE))
|
||||
.addGroup(runtimePanelLayout.createSequentialGroup()
|
||||
.addComponent(maxMemoryUnitsLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(memFieldValidationLabel)
|
||||
.addGap(0, 0, Short.MAX_VALUE))))
|
||||
.addGroup(runtimePanelLayout.createSequentialGroup()
|
||||
.addComponent(maxMemoryLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(memField, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(0, 0, Short.MAX_VALUE))
|
||||
.addGroup(runtimePanelLayout.createSequentialGroup()
|
||||
.addComponent(maxLogFileCount)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(logFileCount, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(logNumAlert)))
|
||||
.addComponent(restartNecessaryWarning, javax.swing.GroupLayout.DEFAULT_SIZE, 718, Short.MAX_VALUE)
|
||||
.addComponent(memFieldValidationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 478, javax.swing.GroupLayout.PREFERRED_SIZE))))
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
@ -704,18 +722,23 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
.addComponent(maxMemoryUnitsLabel1))
|
||||
.addComponent(systemMemoryTotal, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(maxMemoryLabel)
|
||||
.addComponent(memField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(maxMemoryUnitsLabel)
|
||||
.addComponent(memFieldValidationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(logNumAlert, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(maxMemoryLabel)
|
||||
.addComponent(memField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(maxMemoryUnitsLabel))
|
||||
.addComponent(memFieldValidationLabel))
|
||||
.addComponent(maxSolrMemoryLabel)
|
||||
.addComponent(maxMemoryUnitsLabel2)
|
||||
.addComponent(solrMaxHeapSpinner, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(maxLogFileCount)
|
||||
.addComponent(logFileCount, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(logNumAlert, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addComponent(logFileCount, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addContainerGap(14, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
|
||||
@ -726,7 +749,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
.addContainerGap()
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(runtimePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(logoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1002, Short.MAX_VALUE))
|
||||
.addComponent(logoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1010, Short.MAX_VALUE))
|
||||
.addContainerGap())
|
||||
);
|
||||
jPanel1Layout.setVerticalGroup(
|
||||
@ -736,7 +759,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
.addComponent(runtimePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(logoPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addContainerGap(185, Short.MAX_VALUE))
|
||||
.addContainerGap(191, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
jScrollPane1.setViewportView(jPanel1);
|
||||
@ -824,6 +847,15 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
}
|
||||
}//GEN-LAST:event_browseLogosButtonActionPerformed
|
||||
|
||||
private void solrMaxHeapSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_solrMaxHeapSpinnerStateChanged
|
||||
int value = (int)solrMaxHeapSpinner.getValue();
|
||||
if (value == UserPreferences.getMaxSolrVMSize()) {
|
||||
// if the value hasn't changed there's nothing to do.
|
||||
return;
|
||||
}
|
||||
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||
}//GEN-LAST:event_solrMaxHeapSpinnerStateChanged
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JTextField agencyLogoPathField;
|
||||
private javax.swing.JLabel agencyLogoPathFieldValidationLabel;
|
||||
@ -842,10 +874,13 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||
private javax.swing.JLabel maxMemoryLabel;
|
||||
private javax.swing.JLabel maxMemoryUnitsLabel;
|
||||
private javax.swing.JLabel maxMemoryUnitsLabel1;
|
||||
private javax.swing.JLabel maxMemoryUnitsLabel2;
|
||||
private javax.swing.JLabel maxSolrMemoryLabel;
|
||||
private javax.swing.JTextField memField;
|
||||
private javax.swing.JLabel memFieldValidationLabel;
|
||||
private javax.swing.JLabel restartNecessaryWarning;
|
||||
private javax.swing.JPanel runtimePanel;
|
||||
private javax.swing.JSpinner solrMaxHeapSpinner;
|
||||
private javax.swing.JRadioButton specifyLogoRB;
|
||||
private javax.swing.JLabel systemMemoryTotal;
|
||||
private javax.swing.JLabel totalMemoryLabel;
|
||||
|
@ -155,7 +155,7 @@ AutopsyOptionsPanel.totalMemoryLabel.text=Total System Memory:
|
||||
AutopsyOptionsPanel.maxMemoryLabel.text=Maximum JVM Memory:
|
||||
AutopsyOptionsPanel.maxLogFileCount.text=Maximum Log Files:
|
||||
AutopsyOptionsPanel.maxMemoryUnitsLabel.text=GB
|
||||
AutopsyOptionsPanel.restartNecessaryWarning.text=A restart is necessary for any changes to max memory to take effect.
|
||||
AutopsyOptionsPanel.restartNecessaryWarning.text=A restart is necessary for any memory changes to take effect.
|
||||
AutopsyOptionsPanel.browseLogosButton.text=Browse
|
||||
AutopsyOptionsPanel.defaultLogoRB.text=Use default
|
||||
AutopsyOptionsPanel.specifyLogoRB.text=Specify a logo
|
||||
@ -224,3 +224,5 @@ ExternalViewerGlobalSettingsPanel.deleteRuleButton.text_1=Delete Rule
|
||||
ExternalViewerGlobalSettingsPanel.externalViewerTitleLabel.text_1=Set aplication viewer to use for files with specific mime types/extensions:
|
||||
ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title1_1=Application
|
||||
ExternalViewerGlobalSettingsPanel.jTable1.columnModel.title0_1=Mime type/Extension
|
||||
AutopsyOptionsPanel.maxSolrMemoryLabel.text=Maximum Solr JVM Memory:
|
||||
AutopsyOptionsPanel.maxMemoryUnitsLabel2.text=MB
|
||||
|
@ -207,6 +207,7 @@ class AddArchiveTask implements Runnable {
|
||||
DataSource ds = (DataSource) c;
|
||||
String newName = Paths.get(archivePath).getFileName() + "/" + ds.getName();
|
||||
ds.setDisplayName(newName);
|
||||
currentCase.notifyDataSourceNameChanged(c, newName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Copyright 2011-2019 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -182,7 +182,6 @@ public class Server {
|
||||
private String javaPath = "java";
|
||||
public static final Charset DEFAULT_INDEXED_TEXT_CHARSET = Charset.forName("UTF-8"); ///< default Charset to index text as
|
||||
private Process curSolrProcess = null;
|
||||
private static final int MAX_SOLR_MEM_MB = 512; //TODO set dynamically based on avail. system resources
|
||||
static final String PROPERTIES_FILE = KeywordSearchSettings.MODULE_NAME;
|
||||
static final String PROPERTIES_CURRENT_SERVER_PORT = "IndexingServerPort"; //NON-NLS
|
||||
static final String PROPERTIES_CURRENT_STOP_PORT = "IndexingServerStopPort"; //NON-NLS
|
||||
@ -362,7 +361,8 @@ public class Server {
|
||||
* @throws IOException
|
||||
*/
|
||||
private Process runSolrCommand(List<String> solrArguments) throws IOException {
|
||||
final String MAX_SOLR_MEM_MB_PAR = "-Xmx" + Integer.toString(MAX_SOLR_MEM_MB) + "m"; //NON-NLS
|
||||
final String MAX_SOLR_MEM_MB_PAR = "-Xmx" + UserPreferences.getMaxSolrVMSize() + "m"; //NON-NLS
|
||||
|
||||
List<String> commandLine = new ArrayList<>();
|
||||
commandLine.add(javaPath);
|
||||
commandLine.add(MAX_SOLR_MEM_MB_PAR);
|
||||
|
@ -22,6 +22,8 @@ Chrome.getDownload.errMsg.errGettingFiles=Error when trying to get Chrome histor
|
||||
Chrome.getDownload.errMsg.errAnalyzeFiles1={0}\: Error while trying to analyze file\:{1}
|
||||
Chrome.getLogin.errMsg.errGettingFiles=Error when trying to get Chrome history files.
|
||||
Chrome.getLogin.errMsg.errAnalyzingFiles={0}\: Error while trying to analyze file\:{1}
|
||||
Chrome.getAutofill.errMsg.errGettingFiles=Error when trying to get Chrome Web Data files.
|
||||
Chrome.getAutofill.errMsg.errAnalyzingFiles={0}\: Error while trying to analyze file\:{1}
|
||||
Extract.dbConn.errMsg.failedToQueryDb={0}\: Failed to query database.
|
||||
ExtractIE.moduleName.text=Internet Explorer
|
||||
ExtractIE.getBookmark.errMsg.errGettingBookmarks={0}\: Error getting Internet Explorer Bookmarks.
|
||||
@ -54,6 +56,12 @@ Firefox.moduleName=FireFox
|
||||
Firefox.getHistory.errMsg.errFetchingFiles=Error fetching internet history files for Firefox.
|
||||
Firefox.getHistory.errMsg.noFilesFound=No FireFox history files found.
|
||||
Firefox.getHistory.errMsg.errAnalyzeFile={0}\: Error while trying to analyze file\:{1}
|
||||
Firefox.getFormsAutofill.errMsg.errFetchingFiles=Error fetching form history file for Firefox.
|
||||
Firefox.getFormsAutofill.errMsg.noFilesFound=No FireFox form history files found.
|
||||
Firefox.getFormsAutofill.errMsg.errAnalyzeFile={0}\: Error while trying to analyze file\:{1}
|
||||
Firefox.getAutofillProfiles.errMsg.errFetchingFiles=Error fetching Autofill Profiles file for Firefox.
|
||||
Firefox.getAutofillProfiles.errMsg.noFilesFound=No FireFox Autofill Profiles files found.
|
||||
Firefox.getAutofillProfiles.errMsg.errAnalyzeFile={0}\: Error while trying to analyze file\:{1}
|
||||
Firefox.parentModuleName.noSpace=RecentActivity
|
||||
Firefox.parentModuleName=Recent Activity
|
||||
Firefox.getBookmark.errMsg.errFetchFiles=Error fetching bookmark files for Firefox.
|
||||
|
@ -37,12 +37,15 @@ import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
|
||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
@ -62,7 +65,19 @@ class Chrome extends Extract {
|
||||
private static final String COOKIE_QUERY = "SELECT name, value, host_key, expires_utc,last_access_utc, creation_utc FROM cookies"; //NON-NLS
|
||||
private static final String DOWNLOAD_QUERY = "SELECT full_path, url, start_time, received_bytes FROM downloads"; //NON-NLS
|
||||
private static final String DOWNLOAD_QUERY_V30 = "SELECT current_path AS full_path, url, start_time, received_bytes FROM downloads, downloads_url_chains WHERE downloads.id=downloads_url_chains.id"; //NON-NLS
|
||||
private static final String LOGIN_QUERY = "SELECT origin_url, username_value, signon_realm from logins"; //NON-NLS
|
||||
private static final String LOGIN_QUERY = "SELECT origin_url, username_value, date_created, signon_realm from logins"; //NON-NLS
|
||||
private static final String AUTOFILL_QUERY = "SELECT name, value, count, date_created " +
|
||||
" FROM autofill, autofill_dates " +
|
||||
" WHERE autofill.pair_id = autofill_dates.pair_id"
|
||||
; //NON-NLS
|
||||
private static final String AUTOFILL_QUERY_V8X = "SELECT name, value, count, date_created, date_last_used from autofill"; //NON-NLS
|
||||
private static final String WEBFORM_ADDRESS_QUERY = "SELECT first_name, middle_name, last_name, address_line_1, address_line_2, city, state, zipcode, country_code, number, email, date_modified " +
|
||||
" FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones" +
|
||||
" WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
|
||||
|
||||
private static final String WEBFORM_ADDRESS_QUERY_V8X = "SELECT first_name, middle_name, last_name, full_name, street_address, city, state, zipcode, country_code, number, email, date_modified, use_date, use_count" +
|
||||
" FROM autofill_profiles, autofill_profile_names, autofill_profile_emails, autofill_profile_phones" +
|
||||
" WHERE autofill_profiles.guid = autofill_profile_names.guid AND autofill_profiles.guid = autofill_profile_emails.guid AND autofill_profiles.guid = autofill_profile_phones.guid";
|
||||
private final Logger logger = Logger.getLogger(this.getClass().getName());
|
||||
private Content dataSource;
|
||||
private IngestJobContext context;
|
||||
@ -79,6 +94,8 @@ class Chrome extends Extract {
|
||||
this.getHistory();
|
||||
this.getBookmark();
|
||||
this.getCookie();
|
||||
this.getLogins();
|
||||
this.getAutofill();
|
||||
this.getDownload();
|
||||
}
|
||||
|
||||
@ -517,6 +534,348 @@ class Chrome extends Extract {
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, bbartifacts));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets user logins from Login Data sqlite database
|
||||
*/
|
||||
private void getLogins() {
|
||||
|
||||
FileManager fileManager = currentCase.getServices().getFileManager();
|
||||
List<AbstractFile> loginDataFiles;
|
||||
try {
|
||||
loginDataFiles = fileManager.findFiles(dataSource, "Login Data", "Chrome"); //NON-NLS
|
||||
} catch (TskCoreException ex) {
|
||||
String msg = NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errGettingFiles");
|
||||
logger.log(Level.SEVERE, msg, ex);
|
||||
this.addErrorMessage(this.getName() + ": " + msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (loginDataFiles.isEmpty()) {
|
||||
logger.log(Level.INFO, "Didn't find any Chrome Login Data files."); //NON-NLS
|
||||
return;
|
||||
}
|
||||
|
||||
dataFound = true;
|
||||
Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
|
||||
int j = 0;
|
||||
while (j < loginDataFiles.size()) {
|
||||
AbstractFile loginDataFile = loginDataFiles.get(j++);
|
||||
if (loginDataFile.getSize() == 0) {
|
||||
continue;
|
||||
}
|
||||
String temps = RAImageIngestModule.getRATempPath(currentCase, "chrome") + File.separator + loginDataFile.getName() + j + ".db"; //NON-NLS
|
||||
try {
|
||||
ContentUtils.writeToFile(loginDataFile, new File(temps), context::dataSourceIngestIsCancelled);
|
||||
} catch (ReadContentInputStreamException ex) {
|
||||
logger.log(Level.WARNING, String.format("Error reading Chrome login artifacts file '%s' (id=%d).",
|
||||
loginDataFile.getName(), loginDataFile.getId()), ex); //NON-NLS
|
||||
this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
|
||||
this.getName(), loginDataFile.getName()));
|
||||
continue;
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome login artifacts file '%s' (id=%d).",
|
||||
temps, loginDataFile.getName(), loginDataFile.getId()), ex); //NON-NLS
|
||||
this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
|
||||
this.getName(), loginDataFile.getName()));
|
||||
continue;
|
||||
}
|
||||
File dbFile = new File(temps);
|
||||
if (context.dataSourceIngestIsCancelled()) {
|
||||
dbFile.delete();
|
||||
break;
|
||||
}
|
||||
List<HashMap<String, Object>> tempList = this.dbConnect(temps, LOGIN_QUERY);
|
||||
logger.log(Level.INFO, "{0}- Now getting login information from {1} with {2}artifacts identified.", new Object[]{moduleName, temps, tempList.size()}); //NON-NLS
|
||||
for (HashMap<String, Object> result : tempList) {
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
((result.get("origin_url").toString() != null) ? result.get("origin_url").toString() : ""))); //NON-NLS
|
||||
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
(Long.valueOf(result.get("date_created").toString()) / 1000000) - Long.valueOf("11644473600"))); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
(NetworkUtils.extractDomain((result.get("origin_url").toString() != null) ? result.get("origin_url").toString() : "")))); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
((result.get("username_value").toString() != null) ? result.get("username_value").toString().replaceAll("'", "''") : ""))); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
((result.get("signon_realm").toString() != null) ? result.get("signon_realm").toString() : ""))); //NON-NLS
|
||||
|
||||
BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT, loginDataFile, bbattributes);
|
||||
if (bbart != null) {
|
||||
this.indexArtifact(bbart);
|
||||
bbartifacts.add(bbart);
|
||||
}
|
||||
}
|
||||
|
||||
dbFile.delete();
|
||||
}
|
||||
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_SERVICE_ACCOUNT, bbartifacts));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets and parses Autofill data from 'Web Data' database,
|
||||
* and creates TSK_WEB_FORM_AUTOFILL, TSK_WEB_FORM_ADDRESS artifacts
|
||||
*/
|
||||
private void getAutofill() {
|
||||
|
||||
FileManager fileManager = currentCase.getServices().getFileManager();
|
||||
List<AbstractFile> webDataFiles;
|
||||
try {
|
||||
webDataFiles = fileManager.findFiles(dataSource, "Web Data", "Chrome"); //NON-NLS
|
||||
} catch (TskCoreException ex) {
|
||||
String msg = NbBundle.getMessage(this.getClass(), "Chrome.getAutofills.errMsg.errGettingFiles");
|
||||
logger.log(Level.SEVERE, msg, ex);
|
||||
this.addErrorMessage(this.getName() + ": " + msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (webDataFiles.isEmpty()) {
|
||||
logger.log(Level.INFO, "Didn't find any Chrome Web Data files."); //NON-NLS
|
||||
return;
|
||||
}
|
||||
|
||||
dataFound = true;
|
||||
Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
|
||||
int j = 0;
|
||||
while (j < webDataFiles.size()) {
|
||||
AbstractFile webDataFile = webDataFiles.get(j++);
|
||||
if (webDataFile.getSize() == 0) {
|
||||
continue;
|
||||
}
|
||||
String tempFilePath = RAImageIngestModule.getRATempPath(currentCase, "chrome") + File.separator + webDataFile.getName() + j + ".db"; //NON-NLS
|
||||
try {
|
||||
ContentUtils.writeToFile(webDataFile, new File(tempFilePath), context::dataSourceIngestIsCancelled);
|
||||
} catch (ReadContentInputStreamException ex) {
|
||||
logger.log(Level.WARNING, String.format("Error reading Chrome Autofill artifacts file '%s' (id=%d).",
|
||||
webDataFile.getName(), webDataFile.getId()), ex); //NON-NLS
|
||||
this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getAutofill.errMsg.errAnalyzingFiles",
|
||||
this.getName(), webDataFile.getName()));
|
||||
continue;
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Chrome Web data file '%s' (id=%d).",
|
||||
tempFilePath, webDataFile.getName(), webDataFile.getId()), ex); //NON-NLS
|
||||
this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Chrome.getLogin.errMsg.errAnalyzingFiles",
|
||||
this.getName(), webDataFile.getName()));
|
||||
continue;
|
||||
}
|
||||
File dbFile = new File(tempFilePath);
|
||||
if (context.dataSourceIngestIsCancelled()) {
|
||||
dbFile.delete();
|
||||
break;
|
||||
}
|
||||
|
||||
// The DB schema is little different in schema version 8x vs older versions
|
||||
boolean isSchemaV8X = Util.checkColumn("date_created", "autofill", tempFilePath);
|
||||
|
||||
// get form autofill artifacts
|
||||
bbartifacts.addAll(getFormAutofillArtifacts(webDataFile, tempFilePath, isSchemaV8X));
|
||||
// get form address atifacts
|
||||
bbartifacts.addAll(getFormAddressArtifacts(webDataFile, tempFilePath, isSchemaV8X));
|
||||
|
||||
dbFile.delete();
|
||||
}
|
||||
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL, bbartifacts));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts and returns autofill artifacts from the given database file
|
||||
*
|
||||
* @param webDataFile - the database file in the data source
|
||||
* @param dbFilePath - path to a temporary file where the DB file is extracted
|
||||
* @param isSchemaV8X - indicates of the DB schema version is 8X or greater
|
||||
*
|
||||
* @return collection of TSK_WEB_FORM_AUTOFILL artifacts
|
||||
*/
|
||||
private Collection<BlackboardArtifact> getFormAutofillArtifacts (AbstractFile webDataFile, String dbFilePath , boolean isSchemaV8X ) {
|
||||
|
||||
Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
|
||||
|
||||
// The DB Schema is little different in version 8x vs older versions
|
||||
String autoFillquery = (isSchemaV8X) ? AUTOFILL_QUERY_V8X
|
||||
: AUTOFILL_QUERY;
|
||||
|
||||
List<HashMap<String, Object>> autofills = this.dbConnect(dbFilePath, autoFillquery);
|
||||
logger.log(Level.INFO, "{0}- Now getting Autofill information from {1} with {2}artifacts identified.", new Object[]{moduleName, dbFilePath, autofills.size()}); //NON-NLS
|
||||
for (HashMap<String, Object> result : autofills) {
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
|
||||
|
||||
// extract all common attributes
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
((result.get("name").toString() != null) ? result.get("name").toString() : ""))); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
((result.get("value").toString() != null) ? result.get("value").toString() : ""))); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
(Integer.valueOf(result.get("count").toString())))); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
Long.valueOf(result.get("date_created").toString()))); //NON-NLS
|
||||
|
||||
// get schema version specific attributes
|
||||
if (isSchemaV8X) {
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
Long.valueOf(result.get("date_last_used").toString()))); //NON-NLS
|
||||
}
|
||||
|
||||
// Add an artifact
|
||||
BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL, webDataFile, bbattributes);
|
||||
if (bbart != null) {
|
||||
this.indexArtifact(bbart);
|
||||
bbartifacts.add(bbart);
|
||||
}
|
||||
}
|
||||
|
||||
// return all extracted artifacts
|
||||
return bbartifacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts and returns autofill form address artifacts from the given database file
|
||||
*
|
||||
* @param webDataFile - the database file in the data source
|
||||
* @param dbFilePath - path to a temporary file where the DB file is extracted
|
||||
* @param isSchemaV8X - indicates of the DB schema version is 8X or greater
|
||||
*
|
||||
* @return collection of TSK_WEB_FORM_ADDRESS artifacts
|
||||
*/
|
||||
private Collection<BlackboardArtifact> getFormAddressArtifacts (AbstractFile webDataFile, String dbFilePath , boolean isSchemaV8X ) {
|
||||
Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
|
||||
|
||||
String webformAddressQuery = (isSchemaV8X) ? WEBFORM_ADDRESS_QUERY_V8X
|
||||
: WEBFORM_ADDRESS_QUERY;
|
||||
|
||||
// Get Web form addresses
|
||||
List<HashMap<String, Object>> addresses = this.dbConnect(dbFilePath, webformAddressQuery);
|
||||
logger.log(Level.INFO, "{0}- Now getting Web form addresses from {1} with {2}artifacts identified.", new Object[]{moduleName, dbFilePath, addresses.size()}); //NON-NLS
|
||||
for (HashMap<String, Object> result : addresses) {
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
|
||||
|
||||
// get name fields
|
||||
String first_name = result.get("first_name").toString() != null ? result.get("first_name").toString() : "";
|
||||
String middle_name = result.get("middle_name").toString() != null ? result.get("middle_name").toString() : "";
|
||||
String last_name = result.get("last_name").toString() != null ? result.get("last_name").toString() : "";
|
||||
|
||||
// get email and phone
|
||||
String email_Addr = result.get("email").toString() != null ? result.get("email").toString() : "";
|
||||
String phone_number = result.get("number").toString() != null ? result.get("number").toString() : "";
|
||||
|
||||
// Get the address fields
|
||||
String city = result.get("city").toString() != null ? result.get("city").toString() : "";
|
||||
String state = result.get("state").toString() != null ? result.get("state").toString() : "";
|
||||
String zipcode = result.get("zipcode").toString() != null ? result.get("zipcode").toString() : "";
|
||||
String country_code = result.get("country_code").toString() != null ? result.get("country_code").toString() : "";
|
||||
|
||||
// schema version specific fields
|
||||
String full_name = "";
|
||||
String street_address = "";
|
||||
long date_modified = 0;
|
||||
int use_count = 0;
|
||||
long use_date = 0;
|
||||
|
||||
if (isSchemaV8X) {
|
||||
full_name = result.get("full_name").toString() != null ? result.get("full_name").toString() : "";
|
||||
street_address = result.get("street_address").toString() != null ? result.get("street_address").toString() : "";
|
||||
date_modified = result.get("date_modified").toString() != null ? Long.valueOf(result.get("date_modified").toString()) : 0;
|
||||
use_count = result.get("use_count").toString() != null ? Integer.valueOf(result.get("use_count").toString()) : 0;
|
||||
use_date = result.get("use_date").toString() != null ? Long.valueOf(result.get("use_date").toString()) : 0;
|
||||
} else {
|
||||
String address_line_1 = result.get("address_line_1").toString() != null ? result.get("street_address").toString() : "";
|
||||
String address_line_2 = result.get("address_line_2").toString() != null ? result.get("address_line_2").toString() : "";
|
||||
street_address = String.join(" ", address_line_1, address_line_2);
|
||||
}
|
||||
|
||||
// If an email address is found, create an account instance for it
|
||||
if (email_Addr != null && !email_Addr.isEmpty()) {
|
||||
try {
|
||||
Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, email_Addr, NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"), webDataFile);
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error creating email account instance for '%s' from Chrome WebData file '%s' .",
|
||||
email_Addr, webDataFile.getName()), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
// If a phone number is found, create an account instance for it
|
||||
if (phone_number != null && !phone_number.isEmpty()) {
|
||||
try {
|
||||
Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.PHONE, phone_number, NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"), webDataFile);
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error creating phone account instance for '%s' from Chrome WebData file '%s' .",
|
||||
phone_number, webDataFile.getName()), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
// Create atrributes from extracted fields
|
||||
if (full_name == null || full_name.isEmpty()) {
|
||||
full_name = String.join(" ", first_name, middle_name, last_name);
|
||||
}
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME_PERSON,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
full_name)); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
email_Addr)); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
phone_number)); //NON-NLS
|
||||
|
||||
String locationAddress = String.join(", ", street_address, city, state, zipcode, country_code);
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LOCATION,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
locationAddress)); //NON-NLS
|
||||
|
||||
if (date_modified > 0) {
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
date_modified)); //NON-NLS
|
||||
}
|
||||
|
||||
if (use_count > 0 ){
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
use_count)); //NON-NLS
|
||||
}
|
||||
|
||||
if (use_date > 0) {
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
|
||||
NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
|
||||
use_date)); //NON-NLS
|
||||
}
|
||||
|
||||
// Create artifact
|
||||
BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS, webDataFile, bbattributes);
|
||||
if (bbart != null) {
|
||||
this.indexArtifact(bbart);
|
||||
bbartifacts.add(bbart);
|
||||
}
|
||||
}
|
||||
|
||||
// return all extracted artifacts
|
||||
return bbartifacts;
|
||||
}
|
||||
|
||||
private boolean isChromePreVersion30(String temps) {
|
||||
String query = "PRAGMA table_info(downloads)"; //NON-NLS
|
||||
List<HashMap<String, Object>> columns = this.dbConnect(temps, query);
|
||||
|
@ -2,7 +2,7 @@
|
||||
*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2012-2018 Basis Technology Corp.
|
||||
* Copyright 2012-2019 Basis Technology Corp.
|
||||
*
|
||||
* Copyright 2012 42six Solutions.
|
||||
* Contact: aebadirad <at> 42six <dot> com
|
||||
@ -22,17 +22,30 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.recentactivity;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonIOException;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
|
||||
@ -41,6 +54,7 @@ import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||
import org.sleuthkit.autopsy.ingest.IngestServices;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Account;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
@ -56,12 +70,22 @@ class Firefox extends Extract {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Firefox.class.getName());
|
||||
private static final String PLACE_URL_PREFIX = "place:";
|
||||
private static final String HISTORY_QUERY = "SELECT moz_historyvisits.id,url,title,visit_count,(visit_date/1000000) AS visit_date,from_visit,(SELECT url FROM moz_places WHERE id=moz_historyvisits.from_visit) as ref FROM moz_places, moz_historyvisits WHERE moz_places.id = moz_historyvisits.place_id AND hidden = 0"; //NON-NLS
|
||||
private static final String HISTORY_QUERY = "SELECT moz_historyvisits.id, url, title, visit_count,(visit_date/1000000) AS visit_date,from_visit,"
|
||||
+ "(SELECT url FROM moz_historyvisits history, moz_places places where history.id = moz_historyvisits.from_visit and history.place_id = places.id ) as ref "
|
||||
+ "FROM moz_places, moz_historyvisits "
|
||||
+ "WHERE moz_places.id = moz_historyvisits.place_id "
|
||||
+ "AND hidden = 0"; //NON-NLS
|
||||
private static final String COOKIE_QUERY = "SELECT name,value,host,expiry,(lastAccessed/1000000) AS lastAccessed,(creationTime/1000000) AS creationTime FROM moz_cookies"; //NON-NLS
|
||||
private static final String COOKIE_QUERY_V3 = "SELECT name,value,host,expiry,(lastAccessed/1000000) AS lastAccessed FROM moz_cookies"; //NON-NLS
|
||||
private static final String BOOKMARK_QUERY = "SELECT fk, moz_bookmarks.title, url, (moz_bookmarks.dateAdded/1000000) AS dateAdded FROM moz_bookmarks INNER JOIN moz_places ON moz_bookmarks.fk=moz_places.id"; //NON-NLS
|
||||
private static final String DOWNLOAD_QUERY = "SELECT target, source,(startTime/1000000) AS startTime, maxBytes FROM moz_downloads"; //NON-NLS
|
||||
private static final String DOWNLOAD_QUERY_V24 = "SELECT url, content AS target, (lastModified/1000000) AS lastModified FROM moz_places, moz_annos WHERE moz_places.id = moz_annos.place_id AND moz_annos.anno_attribute_id = 3"; //NON-NLS
|
||||
private static final String DOWNLOAD_QUERY_V24 = "SELECT url, content AS target, (lastModified/1000000) AS lastModified "
|
||||
+ " FROM moz_places, moz_annos, moz_anno_attributes "
|
||||
+ " WHERE moz_places.id = moz_annos.place_id"
|
||||
+ " AND moz_annos.anno_attribute_id = moz_anno_attributes.id"
|
||||
+ " AND moz_anno_attributes.name='downloads/destinationFileURI'"; //NON-NLS
|
||||
private static final String FORMHISTORY_QUERY = "SELECT fieldname, value FROM moz_formhistory";
|
||||
private static final String FORMHISTORY_QUERY_V64 = "SELECT fieldname, value, timesUsed, firstUsed, lastUsed FROM moz_formhistory";
|
||||
private final IngestServices services = IngestServices.getInstance();
|
||||
private Content dataSource;
|
||||
private IngestJobContext context;
|
||||
@ -79,6 +103,8 @@ class Firefox extends Extract {
|
||||
this.getBookmark();
|
||||
this.getDownload();
|
||||
this.getCookie();
|
||||
this.getFormsHistory();
|
||||
this.getAutofillProfiles();
|
||||
}
|
||||
|
||||
private void getHistory() {
|
||||
@ -650,6 +676,320 @@ class Firefox extends Extract {
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_DOWNLOAD, bbartifacts));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data from formshistory.sqlite database.
|
||||
* Parses and creates artifacts.
|
||||
*/
|
||||
private void getFormsHistory() {
|
||||
FileManager fileManager = currentCase.getServices().getFileManager();
|
||||
List<AbstractFile> formHistoryFiles;
|
||||
|
||||
// Some fields are just noisy and can me excluded
|
||||
Set<String> excludedFieldNames = new HashSet<>(Arrays.asList(
|
||||
"it", // some kind of timestamp
|
||||
"ts" // some kind of timestamp
|
||||
));
|
||||
|
||||
try {
|
||||
formHistoryFiles = fileManager.findFiles(dataSource, "formhistory.sqlite", "Firefox"); //NON-NLS
|
||||
} catch (TskCoreException ex) {
|
||||
String msg = NbBundle.getMessage(this.getClass(), "Firefox.getFormsAutofill.errMsg.errFetchingFiles");
|
||||
logger.log(Level.WARNING, msg);
|
||||
this.addErrorMessage(this.getName() + ": " + msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (formHistoryFiles.isEmpty()) {
|
||||
String msg = NbBundle.getMessage(this.getClass(), "Firefox.getFormsAutofill.errMsg.noFilesFound");
|
||||
logger.log(Level.INFO, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
dataFound = true;
|
||||
Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
|
||||
int j = 0;
|
||||
for (AbstractFile formHistoryFile : formHistoryFiles) {
|
||||
if (formHistoryFile.getSize() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String fileName = formHistoryFile.getName();
|
||||
String tempFilePath = RAImageIngestModule.getRATempPath(currentCase, "firefox") + File.separator + fileName + j + ".db"; //NON-NLS
|
||||
try {
|
||||
ContentUtils.writeToFile(formHistoryFile, new File(tempFilePath), context::dataSourceIngestIsCancelled);
|
||||
} catch (ReadContentInputStreamException ex) {
|
||||
logger.log(Level.WARNING, String.format("Error reading Firefox web history artifacts file '%s' (id=%d).",
|
||||
fileName, formHistoryFile.getId()), ex); //NON-NLS
|
||||
this.addErrorMessage(
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.getFormsAutofill.errMsg.errAnalyzeFile", this.getName(),
|
||||
fileName));
|
||||
continue;
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error writing temp sqlite db file '%s' for Firefox web history artifacts file '%s' (id=%d).",
|
||||
tempFilePath, fileName, formHistoryFile.getId()), ex); //NON-NLS
|
||||
this.addErrorMessage(
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.getFormsAutofill.errMsg.errAnalyzeFile", this.getName(),
|
||||
fileName));
|
||||
continue;
|
||||
}
|
||||
File dbFile = new File(tempFilePath);
|
||||
if (context.dataSourceIngestIsCancelled()) {
|
||||
dbFile.delete();
|
||||
break;
|
||||
}
|
||||
|
||||
// The table schema is a little different in newer version of Firefox
|
||||
boolean isFirefoxV64 = Util.checkColumn("timesUsed", "moz_formhistory", tempFilePath);
|
||||
String formHistoryQuery = (isFirefoxV64) ? FORMHISTORY_QUERY_V64 : FORMHISTORY_QUERY;
|
||||
|
||||
List<HashMap<String, Object>> tempList = this.dbConnect(tempFilePath, formHistoryQuery);
|
||||
logger.log(Level.INFO, "{0} - Now getting history from {1} with {2} artifacts identified.", new Object[]{moduleName, tempFilePath, tempList.size()}); //NON-NLS
|
||||
for (HashMap<String, Object> result : tempList) {
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
|
||||
|
||||
String fieldName = ((result.get("fieldname").toString() != null) ? result.get("fieldname").toString() : "");
|
||||
// filter out unuseful values
|
||||
if (excludedFieldNames.contains(fieldName.toLowerCase())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME,
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
|
||||
fieldName)); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE,
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
|
||||
((result.get("value").toString() != null) ? result.get("value").toString() : ""))); //NON-NLS
|
||||
|
||||
// Newer versions of firefox have additional columns
|
||||
if (isFirefoxV64) {
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
|
||||
(Long.valueOf(result.get("firstUsed").toString()) / 1000000))); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
|
||||
(Long.valueOf(result.get("lastUsed").toString()) / 1000000))); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
|
||||
(Integer.valueOf(result.get("timesUsed").toString())))); //NON-NLS
|
||||
|
||||
}
|
||||
// Add artifact
|
||||
BlackboardArtifact bbart = this.addArtifact(ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL, formHistoryFile, bbattributes);
|
||||
if (bbart != null) {
|
||||
this.indexArtifact(bbart);
|
||||
bbartifacts.add(bbart);
|
||||
}
|
||||
}
|
||||
++j;
|
||||
dbFile.delete();
|
||||
}
|
||||
|
||||
services.fireModuleDataEvent(new ModuleDataEvent(
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_FORM_AUTOFILL, bbartifacts));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets data from autofill-profiles.json file.
|
||||
* Parses file and makes artifacts.
|
||||
*
|
||||
*/
|
||||
private void getAutofillProfiles() {
|
||||
FileManager fileManager = currentCase.getServices().getFileManager();
|
||||
List<AbstractFile> autofillProfilesFiles;
|
||||
try {
|
||||
autofillProfilesFiles = fileManager.findFiles(dataSource, "autofill-profiles.json", "Firefox"); //NON-NLS
|
||||
} catch (TskCoreException ex) {
|
||||
String msg = NbBundle.getMessage(this.getClass(), "Firefox.getAutofillProfiles.errMsg.errGettingFiles");
|
||||
logger.log(Level.SEVERE, msg, ex);
|
||||
this.addErrorMessage(this.getName() + ": " + msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (autofillProfilesFiles.isEmpty()) {
|
||||
logger.log(Level.INFO, "Didn't find any Firefox Autofill Profiles files."); //NON-NLS
|
||||
return;
|
||||
}
|
||||
|
||||
dataFound = true;
|
||||
Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
|
||||
int j = 0;
|
||||
|
||||
while (j < autofillProfilesFiles.size()) {
|
||||
AbstractFile profileFile = autofillProfilesFiles.get(j++);
|
||||
if (profileFile.getSize() == 0) {
|
||||
continue;
|
||||
}
|
||||
String temps = RAImageIngestModule.getRATempPath(currentCase, "Firefox") + File.separator + profileFile.getName() + j + ".json"; //NON-NLS
|
||||
try {
|
||||
ContentUtils.writeToFile(profileFile, new File(temps), context::dataSourceIngestIsCancelled);
|
||||
} catch (ReadContentInputStreamException ex) {
|
||||
logger.log(Level.WARNING, String.format("Error reading Firefox Autofill profiles artifacts file '%s' (id=%d).",
|
||||
profileFile.getName(), profileFile.getId()), ex); //NON-NLS
|
||||
this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Firefox.getAutofillProfiles.errMsg.errAnalyzingFile",
|
||||
this.getName(), profileFile.getName()));
|
||||
continue;
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error writing temp file '%s' for Firefox Autofill profiles file '%s' (id=%d).",
|
||||
temps, profileFile.getName(), profileFile.getId()), ex); //NON-NLS
|
||||
this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Firefox.getAutofillProfiles.errMsg.errAnalyzingFile",
|
||||
this.getName(), profileFile.getName()));
|
||||
continue;
|
||||
}
|
||||
|
||||
logger.log(Level.INFO, "{0}- Now getting Bookmarks from {1}", new Object[]{moduleName, temps}); //NON-NLS
|
||||
File dbFile = new File(temps);
|
||||
if (context.dataSourceIngestIsCancelled()) {
|
||||
dbFile.delete();
|
||||
break;
|
||||
}
|
||||
|
||||
FileReader tempReader;
|
||||
try {
|
||||
tempReader = new FileReader(temps);
|
||||
} catch (FileNotFoundException ex) {
|
||||
logger.log(Level.SEVERE, "Error while trying to read the Autofill profiles json file for Firefox.", ex); //NON-NLS
|
||||
this.addErrorMessage(
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.getAutofillProfiles.errMsg.errAnalyzeFile", this.getName(),
|
||||
profileFile.getName()));
|
||||
continue;
|
||||
}
|
||||
|
||||
final JsonParser parser = new JsonParser();
|
||||
|
||||
JsonObject jsonRootObject;
|
||||
JsonArray jAddressesArray;
|
||||
|
||||
try {
|
||||
jsonRootObject = parser.parse(tempReader).getAsJsonObject();
|
||||
jAddressesArray = jsonRootObject.getAsJsonArray("addresses"); //NON-NLS
|
||||
} catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
|
||||
logger.log(Level.WARNING, "Error parsing Json for Firefox Autofill profiles.", ex); //NON-NLS
|
||||
this.addErrorMessage(NbBundle.getMessage(this.getClass(), "Firefox.getAutofillProfiles.errMsg.errAnalyzingFile3",
|
||||
this.getName(), profileFile.getName()));
|
||||
continue;
|
||||
}
|
||||
|
||||
for (JsonElement result : jAddressesArray) {
|
||||
JsonObject address = result.getAsJsonObject();
|
||||
if (address == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
JsonElement nameEl = address.get("name"); //NON-NLS
|
||||
String name = (nameEl != null) ? nameEl.getAsString() : "";
|
||||
|
||||
JsonElement emailEl = address.get("email"); //NON-NLS
|
||||
String email = (emailEl != null) ? emailEl.getAsString() : "";
|
||||
|
||||
JsonElement telEl = address.get("tel"); //NON-NLS
|
||||
String tel = (telEl != null) ? telEl.getAsString() : "";
|
||||
JsonElement telCountryCodeEl = address.get("tel-country-code"); //NON-NLS
|
||||
String telCountryCode = (telCountryCodeEl != null) ? telCountryCodeEl.getAsString() : "";
|
||||
JsonElement telNationalEl = address.get("tel-national"); //NON-NLS
|
||||
String telNational = (telNationalEl != null) ? telNationalEl.getAsString() : "";
|
||||
|
||||
String phoneNumber = makeTelNumber(tel, telCountryCode, telNational);
|
||||
|
||||
JsonElement createdEl = address.get("timeCreated"); //NON-NLS
|
||||
Long datetimeCreated = (createdEl != null) ? createdEl.getAsLong()/1000 : Long.valueOf(0);
|
||||
JsonElement lastusedEl = address.get("timeLastUsed"); //NON-NLS
|
||||
Long datetimeLastUsed = (lastusedEl != null) ? lastusedEl.getAsLong()/1000 : Long.valueOf(0);
|
||||
JsonElement timesUsedEl = address.get("timesUsed"); //NON-NLS
|
||||
Integer timesUsed = (timesUsedEl != null) ? timesUsedEl.getAsShort() : Integer.valueOf(0);
|
||||
|
||||
JsonElement addressLine1El = address.get("address-line1"); //NON-NLS
|
||||
String addressLine1 = (addressLine1El != null) ? addressLine1El.getAsString() : "";
|
||||
JsonElement addressLine2El = address.get("address-line2"); //NON-NLS
|
||||
String addressLine2 = (addressLine2El != null) ? addressLine2El.getAsString() : "";
|
||||
JsonElement addressLine3El = address.get("address-line3"); //NON-NLS
|
||||
String addressLine3 = (addressLine3El != null) ? addressLine3El.getAsString() : "";
|
||||
|
||||
JsonElement postalCodeEl = address.get("postal-code"); //NON-NLS
|
||||
String postalCode = (postalCodeEl != null) ? postalCodeEl.getAsString() : "";
|
||||
JsonElement countryEl = address.get("country"); //NON-NLS
|
||||
String country = (countryEl != null) ? countryEl.getAsString() : "";
|
||||
|
||||
String mailingAddress = makeFullAddress(addressLine1, addressLine2, addressLine3, postalCode, country );
|
||||
|
||||
try {
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME_PERSON,
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
|
||||
name)); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_EMAIL,
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
|
||||
email)); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER,
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
|
||||
phoneNumber)); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LOCATION,
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
|
||||
mailingAddress)); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_CREATED,
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
|
||||
datetimeCreated)); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED,
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
|
||||
datetimeLastUsed)); //NON-NLS
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNT,
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
|
||||
timesUsed)); //NON-NLS
|
||||
|
||||
BlackboardArtifact bbart = profileFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS);
|
||||
|
||||
// index the artifact for keyword search
|
||||
if (bbart != null) {
|
||||
bbart.addAttributes(bbattributes);
|
||||
this.indexArtifact(bbart);
|
||||
bbartifacts.add(bbart);
|
||||
}
|
||||
|
||||
// If an email address is found, create an account instance for it
|
||||
if (email != null && !email.isEmpty()) {
|
||||
try {
|
||||
Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.EMAIL, email, NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"), profileFile);
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error creating email account instance for '%s' from Firefox profiles file '%s' .",
|
||||
email, profileFile.getName()), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
// If a phone number is found, create an account instance for it
|
||||
if (phoneNumber != null && !phoneNumber.isEmpty()) {
|
||||
try {
|
||||
Case.getCurrentCaseThrows().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.PHONE, phoneNumber, NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"), profileFile);
|
||||
} catch (NoCurrentCaseException | TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, String.format("Error creating phone number account instance for '%s' from Chrome profiles file '%s' .",
|
||||
phoneNumber, profileFile.getName()), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error while trying to insert Firefox Autofill profile artifact{0}", ex); //NON-NLS
|
||||
this.addErrorMessage(
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.getAutofillProfiles.errMsg.errAnalyzingFile4",
|
||||
this.getName(), profileFile.getName()));
|
||||
}
|
||||
}
|
||||
dbFile.delete();
|
||||
}
|
||||
|
||||
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(
|
||||
NbBundle.getMessage(this.getClass(), "Firefox.parentModuleName"),
|
||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_FORM_ADDRESS, bbartifacts));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the domain from the supplied URL. This method does additional
|
||||
* checks to detect invalid URLs.
|
||||
@ -672,4 +1012,72 @@ class Firefox extends Extract {
|
||||
|
||||
return NetworkUtils.extractDomain(url);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a phone number based on input number or components of phone number.
|
||||
*
|
||||
* @param tel full number, if available
|
||||
* @param telCountryCode country code
|
||||
* @param telNational full national number
|
||||
*
|
||||
* @return phone number, or an empty string if no number can be deciphered from input
|
||||
*/
|
||||
private String makeTelNumber(String tel, String telCountryCode, String telNational) {
|
||||
|
||||
if (tel != null && !tel.isEmpty()) {
|
||||
return tel;
|
||||
}
|
||||
|
||||
if ((telCountryCode != null && !telCountryCode.isEmpty()) &&
|
||||
(telNational != null && !telNational.isEmpty())) {
|
||||
return telCountryCode + telNational;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a full postal address from multiple address fields.
|
||||
*
|
||||
* @parm addressLine1
|
||||
* @parm addressLine2
|
||||
* @parm addressLine3
|
||||
* @parm postalCode
|
||||
* @parm country
|
||||
*
|
||||
* @return full address
|
||||
*/
|
||||
private String makeFullAddress(String addressLine1, String addressLine2, String addressLine3, String postalCode, String country ) {
|
||||
String fullAddress = "";
|
||||
fullAddress = appendAddressField(fullAddress, addressLine1 );
|
||||
fullAddress = appendAddressField(fullAddress, addressLine2 );
|
||||
fullAddress = appendAddressField(fullAddress, addressLine3 );
|
||||
fullAddress = appendAddressField(fullAddress, postalCode );
|
||||
fullAddress = appendAddressField(fullAddress, country );
|
||||
|
||||
return fullAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the given address field to given address, if not empty.
|
||||
* Adds delimiter in between if needed.
|
||||
*
|
||||
* @param address
|
||||
* @param addressfield
|
||||
* @return updated address
|
||||
*/
|
||||
private String appendAddressField(String address, String addressfield) {
|
||||
|
||||
String updatedAddress = address;
|
||||
if (addressfield != null && !addressfield.isEmpty()) {
|
||||
if (!updatedAddress.isEmpty()) {
|
||||
updatedAddress += ", ";
|
||||
}
|
||||
updatedAddress += addressfield;
|
||||
}
|
||||
|
||||
return updatedAddress;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user