Merge branch 'develop' of github.com:sleuthkit/autopsy into 7399-heapDumpFile

This commit is contained in:
Greg DiCristofaro 2021-04-07 11:03:04 -04:00
commit 9f6633a286
44 changed files with 970 additions and 267 deletions

View File

@ -166,7 +166,7 @@ class AddImageWizardSelectHostVisual extends javax.swing.JPanel {
if (specifyNewHostRadio.isSelected() && StringUtils.isNotEmpty(specifyNewHostTextField.getText())) { if (specifyNewHostRadio.isSelected() && StringUtils.isNotEmpty(specifyNewHostTextField.getText())) {
String newHostName = specifyNewHostTextField.getText(); String newHostName = specifyNewHostTextField.getText();
try { try {
return Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().createHost(newHostName); return Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().newHost(newHostName);
} catch (NoCurrentCaseException | TskCoreException ex) { } catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.WARNING, String.format("Unable to create host '%s'.", newHostName), ex); logger.log(Level.WARNING, String.format("Unable to create host '%s'.", newHostName), ex);
return null; return null;
@ -186,7 +186,7 @@ class AddImageWizardSelectHostVisual extends javax.swing.JPanel {
*/ */
private void loadHostData() { private void loadHostData() {
try { try {
Collection<Host> hosts = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHosts(); Collection<Host> hosts = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getAllHosts();
sanitizedHostSet = HostNameValidator.getSanitizedHostNames(hosts); sanitizedHostSet = HostNameValidator.getSanitizedHostNames(hosts);
Vector<HostListItem> hostListItems = hosts.stream() Vector<HostListItem> hostListItems = hosts.stream()

View File

@ -76,7 +76,7 @@ public class HostsEvent extends TskDataModelChangeEvent<Host> {
continue; continue;
} }
Optional<Host> thisHostOpt = hostManager.getHost(id); Optional<Host> thisHostOpt = hostManager.getHostById(id);
thisHostOpt.ifPresent((h) -> toRet.add(h)); thisHostOpt.ifPresent((h) -> toRet.add(h));
} }
} }

View File

@ -45,7 +45,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.Host; import org.sleuthkit.datamodel.Host;
import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.OsAccount;
import org.sleuthkit.datamodel.OsAccountAttribute; import org.sleuthkit.datamodel.OsAccount.OsAccountAttribute;
import org.sleuthkit.datamodel.OsAccountInstance; import org.sleuthkit.datamodel.OsAccountInstance;
import org.sleuthkit.datamodel.OsAccountManager; import org.sleuthkit.datamodel.OsAccountManager;
import org.sleuthkit.datamodel.OsAccountRealm; import org.sleuthkit.datamodel.OsAccountRealm;
@ -390,10 +390,10 @@ public class OsAccountDataPanel extends JPanel {
account = osAccountManager.getOsAccountByObjectId(accountId); account = osAccountManager.getOsAccountByObjectId(accountId);
} }
OsAccountRealm realm = skCase.getOsAccountRealmManager().getRealmById(account.getRealmId()); OsAccountRealm realm = skCase.getOsAccountRealmManager().getRealmByRealmId(account.getRealmId());
List<Host> hosts = osAccountManager.getHosts(account); List<Host> hosts = osAccountManager.getHosts(account);
List<OsAccountAttribute> attributeList = account.getOsAccountAttributes(); List<OsAccountAttribute> attributeList = account.getExtendedOsAccountAttributes();
if (attributeList != null) { if (attributeList != null) {
if (hosts != null) { if (hosts != null) {

View File

@ -14,12 +14,17 @@
<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,44,0,0,1,-112"/> <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,44,0,0,1,-112"/>
</AuxValues> </AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents> <SubComponents>
<Container class="javax.swing.JScrollPane" name="mainScrollPane"> <Container class="javax.swing.JScrollPane" name="mainScrollPane">
<Properties>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[200, 0]"/>
</Property>
</Properties>
<Constraints> <Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription"> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<BorderConstraints direction="Center"/> <GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="1.0"/>
</Constraint> </Constraint>
</Constraints> </Constraints>

View File

@ -18,7 +18,10 @@
*/ */
package org.sleuthkit.autopsy.contentviewers.osaccount; package org.sleuthkit.autopsy.contentviewers.osaccount;
import java.awt.BorderLayout;
import java.awt.Component; import java.awt.Component;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Optional; import java.util.Optional;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.nodes.Node; import org.openide.nodes.Node;
@ -153,8 +156,14 @@ public class OsAccountViewer extends javax.swing.JPanel implements DataContentVi
mainScrollPane = new javax.swing.JScrollPane(); mainScrollPane = new javax.swing.JScrollPane();
setLayout(new java.awt.BorderLayout()); setLayout(new java.awt.GridBagLayout());
add(mainScrollPane, java.awt.BorderLayout.CENTER);
mainScrollPane.setPreferredSize(new java.awt.Dimension(200, 0));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
add(mainScrollPane, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents

View File

@ -24,6 +24,7 @@ import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.UIManager.LookAndFeelInfo;
@ -75,6 +76,16 @@ public class Installer extends ModuleInstall {
} }
private void setLookAndFeel() { private void setLookAndFeel() {
ImageIcon questionIcon = new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/question_32.png"));
ImageIcon warningIcon = new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/warning_32.png"));
ImageIcon informationIcon = new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/information_32.png"));
ImageIcon errorIcon = new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/error_32.png"));
UIManager.put("OptionPane.errorIcon", errorIcon);
UIManager.put("OptionPane.warningIcon", warningIcon);
UIManager.put("OptionPane.questionIcon", questionIcon);
UIManager.put("OptionPane.informationIcon", informationIcon);
if (System.getProperty("os.name").toLowerCase().contains("mac")) { //NON-NLS if (System.getProperty("os.name").toLowerCase().contains("mac")) { //NON-NLS
setUnixLookAndFeel(); setUnixLookAndFeel();
setModuleSettings("false"); setModuleSettings("false");

View File

@ -115,7 +115,7 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable<Objec
return true; return true;
} else { } else {
// otherwise, just show host level // otherwise, just show host level
tskCase.getHostManager().getHosts().stream() tskCase.getHostManager().getAllHosts().stream()
.map(HostGrouping::new) .map(HostGrouping::new)
.sorted() .sorted()
.forEach(list::add); .forEach(list::add);

View File

@ -85,7 +85,7 @@ public class DataSourcesByTypeNode extends DisplayableItemNode {
@Override @Override
protected boolean createKeys(List<HostDataSources> toPopulate) { protected boolean createKeys(List<HostDataSources> toPopulate) {
try { try {
Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHosts().stream() Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getAllHosts().stream()
.map(HostDataSources::new) .map(HostDataSources::new)
.sorted() .sorted()
.forEach(toPopulate::add); .forEach(toPopulate::add);

View File

@ -32,6 +32,7 @@ import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import org.apache.commons.lang3.tuple.Pair;
import org.openide.nodes.ChildFactory; import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children; import org.openide.nodes.Children;
import org.openide.nodes.Node; import org.openide.nodes.Node;
@ -77,7 +78,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
*/ */
public static final Map<String, String> parsePath(String path) { public static final Map<String, String> parsePath(String path) {
Map<String, String> parsed = new HashMap<>(); Map<String, String> parsed = new HashMap<>();
String[] split = path.split(MAIL_PATH_SEPARATOR); String[] split = path == null ? new String[0] : path.split(MAIL_PATH_SEPARATOR);
if (split.length < 4) { if (split.length < 4) {
parsed.put(MAIL_ACCOUNT, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultAcct.text")); parsed.put(MAIL_ACCOUNT, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultAcct.text"));
parsed.put(MAIL_FOLDER, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultFolder.text")); parsed.put(MAIL_FOLDER, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultFolder.text"));
@ -146,55 +147,59 @@ public class EmailExtracted implements AutopsyVisitableItem {
} }
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public void update() { public void update() {
synchronized (accounts) { // clear cache if no case
accounts.clear();
}
if (skCase == null) { if (skCase == null) {
synchronized (accounts) {
accounts.clear();
}
return; return;
} }
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID(); // get artifact id and path (if present) of all email artifacts
int emailArtifactId = BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID();
int pathAttrId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID(); int pathAttrId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH.getTypeID();
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS
+ "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS String query = "SELECT \n" +
+ "attribute_type_id=" + pathAttrId //NON-NLS " art.artifact_id AS artifact_id,\n" +
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS " (SELECT value_text FROM blackboard_attributes attr\n" +
+ " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS " WHERE attr.artifact_id = art.artifact_id AND attr.attribute_type_id = " + pathAttrId + "\n" +
if (filteringDSObjId > 0) { " LIMIT 1) AS value_text\n" +
query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId; "FROM \n" +
} " blackboard_artifacts art\n" +
" WHERE art.artifact_type_id = " + emailArtifactId + "\n" +
((filteringDSObjId > 0) ? " AND art.data_source_obj_id = " + filteringDSObjId : "");
// form hierarchy of account -> folder -> account id
Map<String, Map<String, List<Long>>> newMapping = new HashMap<>();
try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { try (CaseDbQuery dbQuery = skCase.executeQuery(query)) {
ResultSet resultSet = dbQuery.getResultSet(); ResultSet resultSet = dbQuery.getResultSet();
synchronized (accounts) { while (resultSet.next()) {
while (resultSet.next()) { Long artifactId = resultSet.getLong("artifact_id");
final String path = resultSet.getString("value_text"); //NON-NLS Map<String, String> accountFolderMap = parsePath(resultSet.getString("value_text"));
final long artifactId = resultSet.getLong("artifact_id"); //NON-NLS String account = accountFolderMap.get(MAIL_ACCOUNT);
final Map<String, String> parsedPath = parsePath(path); String folder = accountFolderMap.get(MAIL_FOLDER);
final String account = parsedPath.get(MAIL_ACCOUNT);
final String folder = parsedPath.get(MAIL_FOLDER); Map<String, List<Long>> folders = newMapping.computeIfAbsent(account, (str) -> new LinkedHashMap<>());
List<Long> messages = folders.computeIfAbsent(folder, (str) -> new ArrayList<>());
Map<String, List<Long>> folders = accounts.get(account); messages.add(artifactId);
if (folders == null) {
folders = new LinkedHashMap<>();
accounts.put(account, folders);
}
List<Long> messages = folders.get(folder);
if (messages == null) {
messages = new ArrayList<>();
folders.put(folder, messages);
}
messages.add(artifactId);
}
} }
} catch (TskCoreException | SQLException ex) { } catch (TskCoreException | SQLException ex) {
logger.log(Level.WARNING, "Cannot initialize email extraction: ", ex); //NON-NLS logger.log(Level.WARNING, "Cannot initialize email extraction: ", ex); //NON-NLS
} }
synchronized (accounts) {
accounts.clear();
accounts.putAll(newMapping);
}
setChanged(); setChanged();
notifyObservers(); notifyObservers();
} }
} }
/** /**
* Mail root node grouping all mail accounts, supports account-> folder * Mail root node grouping all mail accounts, supports account-> folder

View File

@ -146,7 +146,7 @@ public final class OsAccounts implements AutopsyVisitableItem {
if (filteringDSObjId == 0) { if (filteringDSObjId == 0) {
list.addAll(skCase.getOsAccountManager().getOsAccounts()); list.addAll(skCase.getOsAccountManager().getOsAccounts());
} else { } else {
Host host = skCase.getHostManager().getHost(skCase.getDataSource(filteringDSObjId)); Host host = skCase.getHostManager().getHostByDataSource(skCase.getDataSource(filteringDSObjId));
list.addAll(skCase.getOsAccountManager().getOsAccounts(host)); list.addAll(skCase.getOsAccountManager().getOsAccounts(host));
} }
} catch (TskCoreException | TskDataException ex) { } catch (TskCoreException | TskDataException ex) {

View File

@ -65,7 +65,7 @@ public class AssociateNewPersonAction extends AbstractAction {
try { try {
newPersonName = getAddDialogName(); newPersonName = getAddDialogName();
if (StringUtils.isNotBlank(newPersonName)) { if (StringUtils.isNotBlank(newPersonName)) {
Person person = Case.getCurrentCaseThrows().getSleuthkitCase().getPersonManager().createPerson(newPersonName); Person person = Case.getCurrentCaseThrows().getSleuthkitCase().getPersonManager().newPerson(newPersonName);
Case.getCurrentCaseThrows().getSleuthkitCase().getPersonManager().setPerson(host, person); Case.getCurrentCaseThrows().getSleuthkitCase().getPersonManager().setPerson(host, person);
} }
} catch (NoCurrentCaseException | TskCoreException ex) { } catch (NoCurrentCaseException | TskCoreException ex) {

View File

@ -166,7 +166,7 @@ public class ManageHostsDialog extends javax.swing.JDialog {
if (newHostName != null) { if (newHostName != null) {
Long selectedId = null; Long selectedId = null;
try { try {
Host newHost = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().createHost(newHostName); Host newHost = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().newHost(newHostName);
selectedId = newHost == null ? null : newHost.getHostId(); selectedId = newHost == null ? null : newHost.getHostId();
} catch (NoCurrentCaseException | TskCoreException e) { } catch (NoCurrentCaseException | TskCoreException e) {
logger.log(Level.WARNING, String.format("Unable to add new host '%s' at this time.", newHostName), e); logger.log(Level.WARNING, String.format("Unable to add new host '%s' at this time.", newHostName), e);
@ -234,9 +234,8 @@ public class ManageHostsDialog extends javax.swing.JDialog {
if (selectedHost != null) { if (selectedHost != null) {
String newHostName = getAddEditDialogName(selectedHost); String newHostName = getAddEditDialogName(selectedHost);
if (newHostName != null) { if (newHostName != null) {
selectedHost.setName(newHostName);
try { try {
Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().updateHost(selectedHost); Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().updateHostName(selectedHost, newHostName);
} catch (NoCurrentCaseException | TskCoreException e) { } catch (NoCurrentCaseException | TskCoreException e) {
logger.log(Level.WARNING, String.format("Unable to update host '%s' with id: %d at this time.", selectedHost.getName(), selectedHost.getHostId()), e); logger.log(Level.WARNING, String.format("Unable to update host '%s' with id: %d at this time.", selectedHost.getName(), selectedHost.getHostId()), e);
} }
@ -322,7 +321,7 @@ public class ManageHostsDialog extends javax.swing.JDialog {
Map<Host, List<DataSource>> hostMapping = new HashMap<>(); Map<Host, List<DataSource>> hostMapping = new HashMap<>();
try { try {
SleuthkitCase curCase = Case.getCurrentCaseThrows().getSleuthkitCase(); SleuthkitCase curCase = Case.getCurrentCaseThrows().getSleuthkitCase();
List<Host> hosts = curCase.getHostManager().getHosts(); List<Host> hosts = curCase.getHostManager().getAllHosts();
List<DataSource> dataSources = curCase.getDataSources(); List<DataSource> dataSources = curCase.getDataSources();
if (dataSources != null) { if (dataSources != null) {

View File

@ -67,7 +67,7 @@ public class MergeHostMenuAction extends AbstractAction implements Presenter.Pop
// Get a list of all other hosts // Get a list of all other hosts
List<Host> otherHosts = Collections.emptyList(); List<Host> otherHosts = Collections.emptyList();
try { try {
otherHosts = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHosts(); otherHosts = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getAllHosts();
otherHosts.remove(sourceHost); otherHosts.remove(sourceHost);
} catch (NoCurrentCaseException | TskCoreException ex) { } catch (NoCurrentCaseException | TskCoreException ex) {
logger.log(Level.WARNING, "Error getting hosts for case.", ex); logger.log(Level.WARNING, "Error getting hosts for case.", ex);

View File

@ -18,9 +18,6 @@
*/ */
package org.sleuthkit.autopsy.discovery.ui; package org.sleuthkit.autopsy.discovery.ui;
import java.util.ArrayList;
import java.util.List;
import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository;
import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.DiscoveryAttributes;
import org.sleuthkit.autopsy.discovery.search.ResultsSorter; import org.sleuthkit.autopsy.discovery.search.ResultsSorter;
@ -46,14 +43,7 @@ public class DomainFilterPanel extends AbstractFiltersPanel {
addFilter(new KnownAccountTypeFilterPanel(), false, null, 1); addFilter(new KnownAccountTypeFilterPanel(), false, null, 1);
addFilter(new ArtifactTypeFilterPanel(), false, null, 1); addFilter(new ArtifactTypeFilterPanel(), false, null, 1);
addFilter(new DateFilterPanel(), false, null, 1); addFilter(new DateFilterPanel(), false, null, 1);
List<SearchData.Frequency> defaultFrequencies = null; addFilter(new PastOccurrencesFilterPanel(TYPE), false, null, 0);
if (CentralRepository.isEnabled()) {
defaultFrequencies = new ArrayList<>();
defaultFrequencies.add(SearchData.Frequency.RARE);
defaultFrequencies.add(SearchData.Frequency.UNIQUE);
defaultFrequencies.add(SearchData.Frequency.COMMON);
}
addFilter(new PastOccurrencesFilterPanel(TYPE), true, defaultFrequencies, 0);
addPanelsToScrollPane(domainFiltersSplitPane); addPanelsToScrollPane(domainFiltersSplitPane);
setLastGroupingAttributeType(DiscoveryAttributes.GroupingAttributeType.LAST_ACTIVITY_DATE); setLastGroupingAttributeType(DiscoveryAttributes.GroupingAttributeType.LAST_ACTIVITY_DATE);
setLastSortingMethod(ResultsSorter.SortingMethod.BY_DOMAIN_NAME); setLastSortingMethod(ResultsSorter.SortingMethod.BY_DOMAIN_NAME);

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -77,6 +77,11 @@ import org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper;
import org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper.CallMediaType; import org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper.CallMediaType;
import org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper.CommunicationDirection; import org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper.CommunicationDirection;
import org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper.MessageReadStatus; import org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper.MessageReadStatus;
import org.sleuthkit.datamodel.blackboardutils.GeoArtifactsHelper;
import org.sleuthkit.datamodel.blackboardutils.attributes.GeoTrackPoints;
import org.sleuthkit.datamodel.blackboardutils.attributes.GeoTrackPoints.TrackPoint;
import org.sleuthkit.datamodel.blackboardutils.attributes.GeoWaypoints;
import org.sleuthkit.datamodel.blackboardutils.attributes.GeoWaypoints.Waypoint;
import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments; import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments;
import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments.FileAttachment; import org.sleuthkit.datamodel.blackboardutils.attributes.MessageAttachments.FileAttachment;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -149,23 +154,41 @@ public final class LeappFileProcessor {
.build(); .build();
private static final Map<String, String> ACCOUNT_RELATIONSHIPS = ImmutableMap.<String, String>builder() private static final Map<String, String> ACCOUNT_RELATIONSHIPS = ImmutableMap.<String, String>builder()
.put("Zapya.tsv", "message") .put("zapya.tsv", "message")
.put("sms messages.tsv", "message") .put("sms messages.tsv", "message")
.put("mms messages.tsv", "message") .put("mms messages.tsv", "message")
.put("Viber - Messages.tsv", "message") .put("viber - messages.tsv", "message")
.put("Viber - Contacts.tsv", "contact") .put("viber - contacts.tsv", "contact")
.put("Viber - Call Logs.tsv", "calllog") .put("viber - call logs.tsv", "calllog")
.put("Xender file transfer - Messages.tsv", "message") .put("xender file transfer - messages.tsv", "message")
.put("Whatsapp - Contacts.tsv", "contact") .put("xender file transfer - contacts.tsv", "contact")
.put("Whatsapp - Group Call Logs.tsv", "calllog") .put("whatsapp - contacts.tsv", "contact")
.put("Whatsapp - Single Call Logs.tsv", "calllog") .put("whatsapp - group call logs.tsv", "calllog")
.put("Whatsapp - Messages Logs.tsv", "message") .put("whatsapp - single call logs.tsv", "calllog")
.put("Shareit file transfer.tsv", "message") .put("whatsapp - messages logs.tsv", "message")
.put("shareit file transfer.tsv", "message")
.put("tangomessages messages.tsv", "message") .put("tangomessages messages.tsv", "message")
.put("contacts.tsv", "contact")
.put("imo - accountid.tsv", "contact")
.put("imo - messages.tsv", "message")
.put("textnow - contacts.tsv", "contact")
.put("textnow - messages.tsv", "message")
.put("line - messages.tsv", "message")
.put("line - contacts.tsv", "contact")
.put("line - calllogs.tsv", "calllog")
.put("skype - messages logs.tsv", "message")
.put("skype - contacts.tsv", "contact")
.put("skype - call logs.tsv", "calllog")
.put("facebook messenger - chats.tsv", "message")
.put("facebook messenger - contacts.tsv", "contact")
.put("facebook messenger - calls.tsv", "calllog")
.put("call logs2.tsv", "calllog")
.put("call logs.tsv", "calllog")
.put("oruxmaps tracks.tsv", "trackpoint")
.put("google map locations.tsv", "route")
.put("Contacts.tsv", "contact") .put("Contacts.tsv", "contact")
.put("IMO - AccountId.tsv", "contact") .put("sms - imessage.tsv", "message")
.put("IMO - messages.tsv", "message") .put("call history.tsv", "calllog")
.build(); .build();
Blackboard blkBoard; Blackboard blkBoard;
@ -318,6 +341,10 @@ public final class LeappFileProcessor {
List<BlackboardArtifact> bbartifacts, Content dataSource) throws FileNotFoundException, IOException, IngestModuleException, List<BlackboardArtifact> bbartifacts, Content dataSource) throws FileNotFoundException, IOException, IngestModuleException,
TskCoreException { TskCoreException {
String trackpointSegmentName = null;
GeoTrackPoints pointList = new GeoTrackPoints();
AbstractFile geoAbstractFile = null;
if (LeappFile == null || !LeappFile.exists() || fileName == null) { if (LeappFile == null || !LeappFile.exists() || fileName == null) {
logger.log(Level.WARNING, String.format("Leap file: %s is null or does not exist", LeappFile == null ? LeappFile.toString() : "<null>")); logger.log(Level.WARNING, String.format("Leap file: %s is null or does not exist", LeappFile == null ? LeappFile.toString() : "<null>"));
return; return;
@ -348,7 +375,7 @@ public final class LeappFileProcessor {
Collection<BlackboardAttribute> bbattributes = processReadLine(columnItems, columnIndexes, attrList, fileName, lineNum); Collection<BlackboardAttribute> bbattributes = processReadLine(columnItems, columnIndexes, attrList, fileName, lineNum);
if (!bbattributes.isEmpty()) { if (!bbattributes.isEmpty()) {
switch (ACCOUNT_RELATIONSHIPS.getOrDefault(fileName, "norelationship").toLowerCase()) { switch (ACCOUNT_RELATIONSHIPS.getOrDefault(fileName.toLowerCase(), "norelationship").toLowerCase()) {
case "message": case "message":
createMessageRelationship(bbattributes, dataSource, fileName); createMessageRelationship(bbattributes, dataSource, fileName);
break; break;
@ -358,6 +385,12 @@ public final class LeappFileProcessor {
case "calllog": case "calllog":
createCalllogRelationship(bbattributes, dataSource, fileName); createCalllogRelationship(bbattributes, dataSource, fileName);
break; break;
case "route":
createRoute(bbattributes, dataSource, fileName);
break;
case "trackpoint":
geoAbstractFile = createTrackpoint(bbattributes, dataSource, fileName, trackpointSegmentName, pointList);
break;
default: // There is no relationship defined so just process the artifact normally default: // There is no relationship defined so just process the artifact normally
BlackboardArtifact bbartifact = createArtifactWithAttributes(artifactType.getTypeID(), dataSource, bbattributes); BlackboardArtifact bbartifact = createArtifactWithAttributes(artifactType.getTypeID(), dataSource, bbattributes);
if (bbartifact != null) { if (bbartifact != null) {
@ -371,8 +404,158 @@ public final class LeappFileProcessor {
} }
} }
} }
try {
if (ACCOUNT_RELATIONSHIPS.getOrDefault(fileName.toLowerCase(), "norelationship").toLowerCase() == "trackpoint") {
(new GeoArtifactsHelper(Case.getCurrentCaseThrows().getSleuthkitCase(), moduleName, "", geoAbstractFile)).addTrack(trackpointSegmentName, pointList, new ArrayList<>());
}
} catch (NoCurrentCaseException | TskCoreException | BlackboardException ex) {
throw new IngestModuleException(Bundle.LeappFileProcessor_cannot_create_message_relationship() + ex.getLocalizedMessage(), ex); //NON-NLS
}
} }
@NbBundle.Messages({
"LeappFileProcessor.cannot.create.waypoint.relationship=Cannot create TSK_WAYPOINT artifact.",
})
private void createRoute (Collection<BlackboardAttribute> bbattributes, Content dataSource, String fileName) throws IngestModuleException {
Double startLatitude = Double.valueOf(0);
Double startLongitude = Double.valueOf(0);
Double endLatitude = Double.valueOf(0);
Double endLongitude = Double.valueOf(0);
Double zeroValue = Double.valueOf(0);
String destinationName = "";
String locationName = "";
Long dateTime = Long.valueOf(0);
Collection<BlackboardAttribute> otherAttributes = new ArrayList<>();
String sourceFile = null;
AbstractFile absFile = null;
String comment = "";
try {
for (BlackboardAttribute bba : bbattributes) {
switch (bba.getAttributeType().getTypeName()) {
case "TSK_GEO_LATITUDE_START":
startLatitude = bba.getValueDouble();
break;
case "TSK_GEO_LONGITUDE_START":
startLongitude = bba.getValueDouble();
break;
case "TSK_GEO_LATITUDE_END":
startLatitude = bba.getValueDouble();
break;
case "TSK_GEO_LONGITUDE_END":
startLongitude = bba.getValueDouble();
break;
case "TSK_DATETIME":
dateTime = bba.getValueLong();
break;
case "TSK_NAME":
destinationName = bba.getValueString();
break;
case "TSK_LOCATION":
locationName = bba.getValueString();
break;
case "TSK_TEXT_FILE":
sourceFile = bba.getValueString();
break;
case "TSK_COMMENT":
comment = bba.getValueString();
break;
default:
otherAttributes.add(bba);
break;
}
}
absFile = findAbstractFile(dataSource, sourceFile);
if (absFile == null) {
absFile = (AbstractFile) dataSource;
}
GeoWaypoints waypointList = new GeoWaypoints();
waypointList.addPoint(new Waypoint(startLatitude, startLongitude, zeroValue, ""));
waypointList.addPoint(new Waypoint(endLatitude, endLongitude, zeroValue, locationName));
(new GeoArtifactsHelper(Case.getCurrentCaseThrows().getSleuthkitCase(), moduleName, comment, absFile)).addRoute(destinationName, dateTime, waypointList, new ArrayList<>());
} catch (NoCurrentCaseException | TskCoreException | BlackboardException ex) {
throw new IngestModuleException(Bundle.LeappFileProcessor_cannot_create_waypoint_relationship() + ex.getLocalizedMessage(), ex); //NON-NLS
}
}
@NbBundle.Messages({
"LeappFileProcessor.cannot.create.trackpoint.relationship=Cannot create TSK_TRACK_POINT artifact.",
})
private AbstractFile createTrackpoint(Collection<BlackboardAttribute> bbattributes, Content dataSource, String fileName, String trackpointSegmentName, GeoTrackPoints pointList) throws IngestModuleException {
Double latitude = Double.valueOf(0);
Double longitude = Double.valueOf(0);
Double altitude = Double.valueOf(0);
Double zeroValue = Double.valueOf(0);
String segmentName = null;
Long dateTime = Long.valueOf(0);
Collection<BlackboardAttribute> otherAttributes = new ArrayList<>();
String sourceFile = null;
String comment = null;
AbstractFile absFile = null;
try {
for (BlackboardAttribute bba : bbattributes) {
switch (bba.getAttributeType().getTypeName()) {
case "TSK_GEO_LATITUDE":
latitude = bba.getValueDouble();
break;
case "TSK_GEO_LONGITUDE":
longitude = bba.getValueDouble();
break;
case "TSK_GEO_ALTITUDE":
altitude = bba.getValueDouble();
break;
case "TSK_DATETIME":
dateTime = bba.getValueLong();
break;
case "TSK_NAME":
segmentName = bba.getValueString();
break;
case "TSK_TEXT_FILE":
sourceFile = bba.getValueString();
break;
case "TSK_COMMENT":
comment = bba.getValueString();
otherAttributes.add(bba);
break;
default:
otherAttributes.add(bba);
break;
}
}
absFile = findAbstractFile(dataSource, sourceFile);
if (absFile == null) {
absFile = (AbstractFile) dataSource;
}
if ((trackpointSegmentName == null) || (trackpointSegmentName == segmentName)) {
trackpointSegmentName = segmentName;
pointList.addPoint(new TrackPoint(latitude, longitude, altitude, segmentName, zeroValue, zeroValue, zeroValue, dateTime));
} else {
(new GeoArtifactsHelper(Case.getCurrentCaseThrows().getSleuthkitCase(), moduleName, comment, absFile)).addTrack(segmentName, pointList, new ArrayList<>());
trackpointSegmentName = segmentName;
pointList = new GeoTrackPoints();
pointList.addPoint(new TrackPoint(latitude, longitude, altitude, segmentName, zeroValue, zeroValue, zeroValue, dateTime));
}
} catch (NoCurrentCaseException | TskCoreException | BlackboardException ex) {
throw new IngestModuleException(Bundle.LeappFileProcessor_cannot_create_trackpoint_relationship() + ex.getLocalizedMessage(), ex); //NON-NLS
}
return absFile;
}
@NbBundle.Messages({ @NbBundle.Messages({
"LeappFileProcessor.cannot.create.message.relationship=Cannot create TSK_MESSAGE Relationship.", "LeappFileProcessor.cannot.create.message.relationship=Cannot create TSK_MESSAGE Relationship.",
}) })
@ -380,6 +563,7 @@ public final class LeappFileProcessor {
private void createMessageRelationship(Collection<BlackboardAttribute> bbattributes, Content dataSource, String fileName) throws IngestModuleException { private void createMessageRelationship(Collection<BlackboardAttribute> bbattributes, Content dataSource, String fileName) throws IngestModuleException {
String messageType = null; String messageType = null;
String alternateId = null;
CommunicationDirection communicationDirection = CommunicationDirection.UNKNOWN; CommunicationDirection communicationDirection = CommunicationDirection.UNKNOWN;
String senderId = null; String senderId = null;
String receipentId = null; String receipentId = null;
@ -441,23 +625,34 @@ public final class LeappFileProcessor {
case "TSK_SUBJECT": case "TSK_SUBJECT":
subject = bba.getValueString(); subject = bba.getValueString();
break; break;
case "TSK_ID":
alternateId = bba.getValueString();
otherAttributes.add(bba);
break;
default: default:
otherAttributes.add(bba); otherAttributes.add(bba);
break; break;
} }
} }
AbstractFile absFile = findAbstractFile(dataSource, sourceFile); AbstractFile absFile = findAbstractFile(dataSource, sourceFile);
Account.Type accountType = getAccountType(fileName); if (absFile == null) {
if ((absFile != null) || (accountType != null)) { absFile = (AbstractFile) dataSource;
CommunicationArtifactsHelper accountArtifact = new CommunicationArtifactsHelper(Case.getCurrentCaseThrows().getSleuthkitCase(), }
CommunicationArtifactsHelper accountArtifact;
Account.Type accountType = getAccountType(fileName);
if (alternateId == null) {
accountArtifact = new CommunicationArtifactsHelper(Case.getCurrentCaseThrows().getSleuthkitCase(),
moduleName, absFile, accountType); moduleName, absFile, accountType);
BlackboardArtifact messageArtifact = accountArtifact.addMessage(messageType, communicationDirection, senderId, } else {
receipentId, dateTime, messageStatus, subject, accountArtifact = new CommunicationArtifactsHelper(Case.getCurrentCaseThrows().getSleuthkitCase(),
messageText, threadId, otherAttributes); moduleName, absFile, accountType, accountType, alternateId);
if (!fileAttachments.isEmpty()) { }
messageAttachments = new MessageAttachments(fileAttachments, new ArrayList<>()); BlackboardArtifact messageArtifact = accountArtifact.addMessage(messageType, communicationDirection, senderId,
accountArtifact.addAttachments(messageArtifact, messageAttachments); receipentId, dateTime, messageStatus, subject,
} messageText, threadId, otherAttributes);
if (!fileAttachments.isEmpty()) {
messageAttachments = new MessageAttachments(fileAttachments, new ArrayList<>());
accountArtifact.addAttachments(messageArtifact, messageAttachments);
} }
} catch (NoCurrentCaseException | TskCoreException | BlackboardException ex) { } catch (NoCurrentCaseException | TskCoreException | BlackboardException ex) {
throw new IngestModuleException(Bundle.LeappFileProcessor_cannot_create_message_relationship() + ex.getLocalizedMessage(), ex); //NON-NLS throw new IngestModuleException(Bundle.LeappFileProcessor_cannot_create_message_relationship() + ex.getLocalizedMessage(), ex); //NON-NLS
@ -465,6 +660,9 @@ public final class LeappFileProcessor {
} }
@NbBundle.Messages({
"LeappFileProcessor.cannot.create.contact.relationship=Cannot create TSK_CONTACT Relationship.",
})
private void createContactRelationship(Collection<BlackboardAttribute> bbattributes, Content dataSource, String fileName) throws IngestModuleException { private void createContactRelationship(Collection<BlackboardAttribute> bbattributes, Content dataSource, String fileName) throws IngestModuleException {
String alternateId = null; String alternateId = null;
@ -503,6 +701,7 @@ public final class LeappFileProcessor {
break; break;
case "TSK_ID": case "TSK_ID":
alternateId = bba.getValueString(); alternateId = bba.getValueString();
otherAttributes.add(bba);
break; break;
default: default:
otherAttributes.add(bba); otherAttributes.add(bba);
@ -510,8 +709,11 @@ public final class LeappFileProcessor {
} }
} }
AbstractFile absFile = findAbstractFile(dataSource, sourceFile); AbstractFile absFile = findAbstractFile(dataSource, sourceFile);
if (absFile == null) {
absFile = (AbstractFile) dataSource;
}
Account.Type accountType = getAccountType(fileName); Account.Type accountType = getAccountType(fileName);
if ((absFile != null) || (accountType != null)) { if (accountType != null) {
CommunicationArtifactsHelper accountArtifact; CommunicationArtifactsHelper accountArtifact;
if (alternateId == null) { if (alternateId == null) {
@ -524,14 +726,18 @@ public final class LeappFileProcessor {
BlackboardArtifact messageArtifact = accountArtifact.addContact(contactName, phoneNumber, homePhoneNumber, mobilePhoneNumber, emailAddr, otherAttributes); BlackboardArtifact messageArtifact = accountArtifact.addContact(contactName, phoneNumber, homePhoneNumber, mobilePhoneNumber, emailAddr, otherAttributes);
} }
} catch (NoCurrentCaseException | TskCoreException | BlackboardException ex) { } catch (NoCurrentCaseException | TskCoreException | BlackboardException ex) {
throw new IngestModuleException(Bundle.LeappFileProcessor_cannot_create_message_relationship() + ex.getLocalizedMessage(), ex); //NON-NLS throw new IngestModuleException(Bundle.LeappFileProcessor_cannot_create_contact_relationship() + ex.getLocalizedMessage(), ex); //NON-NLS
} }
} }
@NbBundle.Messages({
"LeappFileProcessor.cannot.create.calllog.relationship=Cannot create TSK_CALLLOG Relationship.",
})
private void createCalllogRelationship(Collection<BlackboardAttribute> bbattributes, Content dataSource, String fileName) throws IngestModuleException { private void createCalllogRelationship(Collection<BlackboardAttribute> bbattributes, Content dataSource, String fileName) throws IngestModuleException {
String callerId = null; String callerId = null;
String alternateId = null;
List<String> calleeId = Arrays.asList(); List<String> calleeId = Arrays.asList();
CommunicationDirection communicationDirection = CommunicationDirection.UNKNOWN; CommunicationDirection communicationDirection = CommunicationDirection.UNKNOWN;
Long startDateTime = Long.valueOf(0); Long startDateTime = Long.valueOf(0);
@ -570,6 +776,10 @@ public final class LeappFileProcessor {
calleeId = Arrays.asList(calleeTempList); calleeId = Arrays.asList(calleeTempList);
} }
break; break;
case "TSK_ID":
alternateId = bba.getValueString();
otherAttributes.add(bba);
break;
default: default:
otherAttributes.add(bba); otherAttributes.add(bba);
break; break;
@ -582,14 +792,21 @@ public final class LeappFileProcessor {
callerId = null; callerId = null;
} }
AbstractFile absFile = findAbstractFile(dataSource, sourceFile); AbstractFile absFile = findAbstractFile(dataSource, sourceFile);
Account.Type accountType = getAccountType(fileName); if (absFile == null) {
if ((absFile != null) || (accountType != null)) { absFile = (AbstractFile) dataSource;
CommunicationArtifactsHelper accountArtifact = new CommunicationArtifactsHelper(Case.getCurrentCaseThrows().getSleuthkitCase(),
moduleName, absFile, accountType);
BlackboardArtifact callLogArtifact = accountArtifact.addCalllog(communicationDirection, callerId, calleeId, startDateTime, endDateTime, mediaType, otherAttributes);
} }
Account.Type accountType = getAccountType(fileName);
CommunicationArtifactsHelper accountArtifact;
if (accountType != null) {
accountArtifact = new CommunicationArtifactsHelper(Case.getCurrentCaseThrows().getSleuthkitCase(),
moduleName, absFile, accountType);
} else {
accountArtifact = new CommunicationArtifactsHelper(Case.getCurrentCaseThrows().getSleuthkitCase(),
moduleName, absFile, accountType, accountType, alternateId);
}
BlackboardArtifact callLogArtifact = accountArtifact.addCalllog(communicationDirection, callerId, calleeId, startDateTime, endDateTime, mediaType, otherAttributes);
} catch (NoCurrentCaseException | TskCoreException | BlackboardException ex) { } catch (NoCurrentCaseException | TskCoreException | BlackboardException ex) {
throw new IngestModuleException(Bundle.LeappFileProcessor_cannot_create_message_relationship() + ex.getLocalizedMessage(), ex); //NON-NLS throw new IngestModuleException(Bundle.LeappFileProcessor_cannot_create_calllog_relationship() + ex.getLocalizedMessage(), ex); //NON-NLS
} }
} }
@ -606,6 +823,10 @@ public final class LeappFileProcessor {
return Account.Type.IMO; return Account.Type.IMO;
case "imo - messages.tsv": case "imo - messages.tsv":
return Account.Type.IMO; return Account.Type.IMO;
case "textnow - contacts.tsv":
return Account.Type.TEXTNOW;
case "textnow - messages.tsv":
return Account.Type.TEXTNOW;
case "mms messages.tsv": case "mms messages.tsv":
return Account.Type.PHONE; return Account.Type.PHONE;
case "viber - call logs.tsv": case "viber - call logs.tsv":
@ -616,6 +837,8 @@ public final class LeappFileProcessor {
return Account.Type.VIBER; return Account.Type.VIBER;
case "xender file transfer - messages.tsv": case "xender file transfer - messages.tsv":
return Account.Type.XENDER; return Account.Type.XENDER;
case "xender file transfer - contacts.tsv":
return Account.Type.XENDER;
case "whatsapp - single call logs.tsv": case "whatsapp - single call logs.tsv":
return Account.Type.WHATSAPP; return Account.Type.WHATSAPP;
case "whatsapp - messages logs.tsv": case "whatsapp - messages logs.tsv":
@ -627,9 +850,33 @@ public final class LeappFileProcessor {
case "tangomessages messages.tsv": case "tangomessages messages.tsv":
return Account.Type.TANGO; return Account.Type.TANGO;
case "shareit file transfer.tsv": case "shareit file transfer.tsv":
return Account.Type.SHAREIT; return Account.Type.SHAREIT;
case "line - calllogs.tsv":
return Account.Type.LINE;
case "line - contacts.tsv":
return Account.Type.LINE;
case "line - messages.tsv":
return Account.Type.LINE;
case "skype - call logs.tsv":
return Account.Type.SKYPE;
case "skype - contacts.tsv":
return Account.Type.SKYPE;
case "skype - messages logs.tsv":
return Account.Type.SKYPE;
case "facebook messenger - calls.tsv":
return Account.Type.FACEBOOK;
case "facebook messenger - contacts.tsv":
return Account.Type.FACEBOOK;
case "facebook messenger - chats.tsv":
return Account.Type.FACEBOOK;
case "call logs2.tsv":
return Account.Type.PHONE;
case "call logs.tsv":
return Account.Type.PHONE;
case "sms - imessage.tsv":
return Account.Type.PHONE;
default: default:
return null; return Account.Type.PHONE;
} }
} }

View File

@ -355,15 +355,6 @@
</ArtifactName> </ArtifactName>
</FileName> </FileName>
<!-- <FileName filename="partner settings.tsv" description="Partner Settings">
<ArtifactName artifactname="TSK_" comment="null">
<AttributeName attributename="null" columnName="Name" required="no" />
<AttributeName attributename="null" columnName="Value ) # Dont remove the comma" required="no" />
<AttributeName attributename="null" columnName=" that is required to make this a tuple as there is only 1 eleme" required="no" />
</ArtifactName>
</FileName>
-->
<FileName filename="sms messages.tsv" description="SMS messages"> <FileName filename="sms messages.tsv" description="SMS messages">
<ArtifactName artifactname="TSK_MESSAGE" comment="SMS messages"> <ArtifactName artifactname="TSK_MESSAGE" comment="SMS messages">
<AttributeName attributename="null" columnName="Date" required="no"/> <AttributeName attributename="null" columnName="Date" required="no"/>
@ -379,8 +370,9 @@
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/> <AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName> </ArtifactName>
</FileName> </FileName>
<FileName filename="Viber - Messages.tsv" description="Viber"> <!-- Commented out as they are part of the android analyzer python module and may duplicate outcomes if run with it -->
<!-- <FileName filename="Viber - Messages.tsv" description="Viber">
<ArtifactName artifactname="TSK_MESSAGE" comment="Viber Message"> <ArtifactName artifactname="TSK_MESSAGE" comment="Viber Message">
<AttributeName attributename="TSK_DATETIME" columnName="Message Date" required="yes" /> <AttributeName attributename="TSK_DATETIME" columnName="Message Date" required="yes" />
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="From Phone Number" required="yes"/> <AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="From Phone Number" required="yes"/>
@ -396,8 +388,8 @@
<FileName filename="Viber - Contacts.tsv" description="Viber"> <FileName filename="Viber - Contacts.tsv" description="Viber">
<ArtifactName artifactname="TSK_CONTACT" comment="Viber Contacts"> <ArtifactName artifactname="TSK_CONTACT" comment="Viber Contacts">
<AttributeName attributename="TSK_NAME" columnName="display name" required="yes" /> <AttributeName attributename="TSK_NAME" columnName="Display Name" required="yes" />
<AttributeName attributename="TSK_PHONE_NUMBER" columnName="phone number" required="yes"/> <AttributeName attributename="TSK_PHONE_NUMBER" columnName="Phone Number" required="yes"/>
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/> <AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName> </ArtifactName>
</FileName> </FileName>
@ -405,7 +397,7 @@
<FileName filename="Viber - Call Logs.tsv" description="Viber"> <FileName filename="Viber - Call Logs.tsv" description="Viber">
<ArtifactName artifactname="TSK_CALLLOG" comment="Viber Contacts"> <ArtifactName artifactname="TSK_CALLLOG" comment="Viber Contacts">
<AttributeName attributename="TSK_DATETIME_START" columnName="Call Start Time" required="yes" /> <AttributeName attributename="TSK_DATETIME_START" columnName="Call Start Time" required="yes" />
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="phone number" required="yes"/> <AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="Phone Number" required="yes"/>
<AttributeName attributename="TSK_DIRECTION" columnName="Call Direction" required="yes"/> <AttributeName attributename="TSK_DIRECTION" columnName="Call Direction" required="yes"/>
<AttributeName attributename="TSK_DATETIME_END" columnName="Call End Time" required="yes"/> <AttributeName attributename="TSK_DATETIME_END" columnName="Call End Time" required="yes"/>
<AttributeName attributename="null" columnName="Call Type" required="no"/> <AttributeName attributename="null" columnName="Call Type" required="no"/>
@ -447,45 +439,56 @@
<FileName filename="Whatsapp - Single Call Logs.tsv" description="Whatsapp"> <FileName filename="Whatsapp - Single Call Logs.tsv" description="Whatsapp">
<ArtifactName artifactname="TSK_CALLLOG" comment="Whatsapp Single Call Log"> <ArtifactName artifactname="TSK_CALLLOG" comment="Whatsapp Single Call Log">
<AttributeName attributename="TSK_DATETIME_START" columnName="start_time" required="yes" /> <AttributeName attributename="TSK_DATETIME_START" columnName="Start Time" required="yes" />
<AttributeName attributename="null" columnName="call_type" required="no"/> <AttributeName attributename="null" columnName="Call Type" required="no"/>
<AttributeName attributename="TSK_DATETIME_END" columnName="end_time" required="yes"/> <AttributeName attributename="TSK_DATETIME_END" columnName="End Time" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="num" required="yes"/> <AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="Number" required="yes"/>
<AttributeName attributename="TSK_DIRECTION" columnName="call_direction" required="yes"/> <AttributeName attributename="TSK_DIRECTION" columnName="Call Direction" required="yes"/>
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/> <AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName> </ArtifactName>
</FileName> </FileName>
<FileName filename="Whatsapp - Group Call Logs.tsv" description="Whatsapp"> <FileName filename="Whatsapp - Group Call Logs.tsv" description="Whatsapp">
<ArtifactName artifactname="TSK_CALLLOG" comment="Whatsapp Group Call Log"> <ArtifactName artifactname="TSK_CALLLOG" comment="Whatsapp Group Call Log">
<AttributeName attributename="null" columnName="call_type" required="no"/> <AttributeName attributename="TSK_DATETIME_START" columnName="Start Time" required="yes" />
<AttributeName attributename="TSK_DATETIME_START" columnName="start_time" required="yes" /> <AttributeName attributename="TSK_DATETIME_END" columnName="End Time" required="yes"/>
<AttributeName attributename="TSK_DATETIME_END" columnName="end_time" required="yes"/> <AttributeName attributename="null" columnName="Call Type" required="no"/>
<AttributeName attributename="TSK_DIRECTION" columnName="call_direction" required="yes"/> <AttributeName attributename="TSK_DIRECTION" columnName="Call Direction" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="from_id" required="yes"/> <AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="From ID" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="group_members" required="yes"/> <AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="Group Members" required="yes"/>
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Line - Calllogs.tsv" description="Line - Calllogs">
<ArtifactName artifactname="TSK_CALLLOG" comment="LineCall Log">
<AttributeName attributename="TSK_DATETIME_START" columnName="Start Time" required="yes" />
<AttributeName attributename="TSK_DATETIME_END" columnName="End Time" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="To ID" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="From ID" required="yes"/>
<AttributeName attributename="TSK_DIRECTION" columnName="Direction" required="yes"/>
<AttributeName attributename="null" columnName="Call Type" required="no"/>
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/> <AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName> </ArtifactName>
</FileName> </FileName>
<FileName filename="Whatsapp - Contacts.tsv" description="Whatsapp"> <FileName filename="Whatsapp - Contacts.tsv" description="Whatsapp">
<ArtifactName artifactname="TSK_CONTACT" comment="Whatsapp Contacts"> <ArtifactName artifactname="TSK_CONTACT" comment="Whatsapp Contacts">
<AttributeName attributename="TSK_EMAIL" columnName="number" required="yes"/> <AttributeName attributename="TSK_ID" columnName="Number" required="yes"/>
<AttributeName attributename="TSK_NAME" columnName="name" required="yes" /> <AttributeName attributename="TSK_NAME" columnName="Name" required="yes" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/> <AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName> </ArtifactName>
</FileName> </FileName>
<FileName filename="Whatsapp - Messages.tsv" description="Whatsapp"> <FileName filename="Whatsapp - Messages Logs.tsv" description="Whatsapp">
<ArtifactName artifactname="TSK_MESSAGE" comment="Whatsapp Messages"> <ArtifactName artifactname="TSK_MESSAGE" comment="Whatsapp Messages">
<AttributeName attributename="TSK_THREAD_ID" columnName="messages_id" required="yes"/> <AttributeName attributename="TSK_DATETIME" columnName="Send Timestamp" required="yes" />
<AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="recipients" required="yes"/> <AttributeName attributename="TSK_THREAD_ID" columnName="Message ID" required="yes"/>
<AttributeName attributename="TSK_DIRECTION" columnName="direction" required="yes"/> <AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="Recipients" required="yes"/>
<AttributeName attributename="TSK_TEXT" columnName="content" required="yes"/> <AttributeName attributename="TSK_DIRECTION" columnName="Direction" required="yes"/>
<AttributeName attributename="TSK_DATETIME" columnName="send_timestamp" required="yes" /> <AttributeName attributename="TSK_TEXT" columnName="Content" required="yes"/>
<AttributeName attributename="null" columnName="received_timestamp" required="no"/> <AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="Group Sender" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="number" required="yes"/> <AttributeName attributename="TSK_ATTACHMENTS" columnName="Attachment" required="yes" />
<AttributeName attributename="TSK_ATTACHMENTS" columnName="name" required="yes" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/> <AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName> </ArtifactName>
</FileName> </FileName>
@ -501,4 +504,243 @@
</ArtifactName> </ArtifactName>
</FileName> </FileName>
<FileName filename="Textnow - Contacts.tsv" description="Textnow - Contacts">
<ArtifactName artifactname="TSK_CONTACT" comment="Textnow Contacts">
<AttributeName attributename="TSK_PHONE_NUMBER" columnName="number" required="yes"/>
<AttributeName attributename="TSK_NAME" columnName="name" required="yes" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Textnow - Messages.tsv" description="Textnow - Messages">
<ArtifactName artifactname="TSK_MESSAGE" comment="Textnow Messages">
<AttributeName attributename="TSK_DATETIME_START" columnName="Send T imestamp" required="yes" />
<AttributeName attributename="TSK_THREAD_ID" columnName="Message ID" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="From ID" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="To ID" required="yes"/>
<AttributeName attributename="TSK_DIRECTION" columnName="Direction" required="yes"/>
<AttributeName attributename="TSK_TEXT" columnName="Message" required="yes"/>
<AttributeName attributename="TSK_READ_STATUS" columnName="Read" required="yes"/>
<AttributeName attributename="TSK_ATTACHMENTS" columnName="Attachment" required="yes" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Shareit file transfer.tsv" description="Shareit - Messages">
<ArtifactName artifactname="TSK_MESSAGE" comment="Shareit Messages">
<AttributeName attributename="TSK_DIRECTION" columnName="direction" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="from_id" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="to_id" required="yes"/>
<AttributeName attributename="null" columnName="device_name" required="no"/>
<AttributeName attributename="null" columnName="description" required="no"/>
<AttributeName attributename="TSK_DATETIME_START" columnName="timestamp" required="yes" />
<AttributeName attributename="TSK_ATTACHMENTS" columnName="file_path" required="yes" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Xender file transfer - contacts.tsv" description="Xender file transfer - contacts">
<ArtifactName artifactname="TSK_CONTACT" comment="Xender Contacts">
<AttributeName attributename="TSK_ID" columnName="device_id" required="yes"/>
<AttributeName attributename="TSK_NAME" columnName="nick_name" required="yes" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="IMO - AccountId.tsv" description="IMO - Contacts">
<ArtifactName artifactname="TSK_CONTACT" comment="IMO Contacts">
<AttributeName attributename="TSK_ID" columnName="Account ID" required="yes"/>
<AttributeName attributename="TSK_NAME" columnName="Name" required="yes" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="IMO - Messages.tsv" description="IMO - Messages">
<ArtifactName artifactname="TSK_MESSAGE" comment="IMO Messages">
<AttributeName attributename="TSK_DATETIME_START" columnName="Timestamp" required="yes" />
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="From ID" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="To ID" required="yes"/>
<AttributeName attributename="TSK_TEXT" columnName="Last Message" required="yes"/>
<AttributeName attributename="TSK_DIRECTION" columnName="Direction" required="yes"/>
<AttributeName attributename="TSK_READ_STATUS" columnName="Message Read" required="yes"/>
<AttributeName attributename="TSK_ATTACHMENTS" columnName="Attachment" required="yes" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="tangomessages messages.tsv" description="tangomessages messages">
<ArtifactName artifactname="TSK_MESSAGE" comment="Tango Messages">
<AttributeName attributename="TSK_DATETIME_START" columnName="Create Time" required="yes" />
<AttributeName attributename="TSK_DIRECTION" columnName="Direction" required="yes"/>
<AttributeName attributename="TSK_TEXT" columnName="Message" required="yes"/>
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Line - messages.tsv" description="Line - Messages">
<ArtifactName artifactname="TSK_MESSAGE" comment="Line Messages">
<AttributeName attributename="TSK_DATETIME_START" columnName="Start Time" required="yes" />
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="From ID" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="To ID" required="yes"/>
<AttributeName attributename="TSK_DIRECTION" columnName="Direction" required="yes"/>
<AttributeName attributename="TSK_THREAD_ID" columnName="Thread ID" required="yes"/>
<AttributeName attributename="TSK_TEXT" columnName="Message" required="yes"/>
<AttributeName attributename="TSK_ATTACHMENTS" columnName="Attachments" required="yes" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Line - Contacts.tsv" description="Line - Contacts">
<ArtifactName artifactname="TSK_CONTACT" comment="Line Contacts">
<AttributeName attributename="TSK_ID" columnName="user_id" required="yes"/>
<AttributeName attributename="TSK_NAME" columnName="user_name" required="yes" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Skype - Contacts.tsv" description="Skype - Contacts">
<ArtifactName artifactname="TSK_CONTACT" comment="Skype Contacts">
<AttributeName attributename="TSK_ID" columnName="Entry ID" required="yes"/>
<AttributeName attributename="TSK_NAME" columnName="Name" required="yes" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Skype - Call Logs.tsv" description="Skype - Calllogs">
<ArtifactName artifactname="TSK_CALLLOG" comment="Skype Call Log">
<AttributeName attributename="TSK_DATETIME_START" columnName="Start Time" required="yes" />
<AttributeName attributename="TSK_DATETIME_END" columnName="End Time" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="From ID" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="To Id" required="yes"/>
<AttributeName attributename="TSK_DIRECTION" columnName="Call Direction" required="yes"/>
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Skype - Messages Logs.tsv" description="Skype - Messages">
<ArtifactName artifactname="TSK_MESSAGE" comment="Skype Messages">
<AttributeName attributename="TSK_DATETIME_START" columnName="Send Time" required="yes" />
<AttributeName attributename="TSK_THREAD_ID" columnName="Thread ID" required="yes"/>
<AttributeName attributename="TSK_TEXT" columnName="Content" required="yes"/>
<AttributeName attributename="TSK_DIRECTION" columnName="Direction" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="From ID" required="yes"/>
<AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="To ID" required="yes"/>
<AttributeName attributename="TSK_ATTACHMENTS" columnName="Attachment" required="yes" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Facebook Messenger - Contacts.tsv" description="Facebook Messenger - Contacts">
<ArtifactName artifactname="TSK_CONTACT" comment="Facebook Messenger - Contacts">
<AttributeName attributename="TSK_ID" columnName="User ID" required="yes"/>
<AttributeName attributename="null" columnName="First Name" required="no"/>
<AttributeName attributename="null" columnName="Last Name" required="no"/>
<AttributeName attributename="TSK_NAME" columnName="Username" required="yes" />
<AttributeName attributename="null" columnName="Profile Pic URL" required="no"/>
<AttributeName attributename="null" columnName="Is App User" required="no"/>
<AttributeName attributename="null" columnName="Is Friend" required="no"/>
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Facebook Messenger - Calls.tsv" description="Facebook Messenger - Calls">
<ArtifactName artifactname="TSK_CALLLOG" comment="Facebook Messenger - Calls">
<AttributeName attributename="TSK_DATETIME_START" columnName="Timestamp" required="yes" />
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="Caller ID" required="no"/>
<AttributeName attributename="null" columnName="Receiver Name" required="no"/>
<AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="Receiver ID" required="yes"/>
<AttributeName attributename="null" columnName="Call Duration" required="no"/>
<AttributeName attributename="null" columnName="Video Call" required="no"/>
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Facebook Messenger - Chats.tsv" description="Facebook Messenger - Chats">
<ArtifactName artifactname="TSK_MESSAGE" comment="Facebook Messenger - Chats">
<AttributeName attributename="TSK_DATETIME_START" columnName="Timestamp" required="yes" />
<AttributeName attributename="null" columnName="Sender Name" required="no"/>
<AttributeName attributename="TSK_ID" columnName="Sender ID" required="yes"/>
<AttributeName attributename="TSK_THREAD_ID" columnName="Thread Key" required="yes"/>
<AttributeName attributename="TSK_TEXT" columnName="Message" required="yes"/>
<AttributeName attributename="null" columnName="Snippet" required="no"/>
<AttributeName attributename="TSK_ATTACHMENTS" columnName="Attachment Name" required="yes" />
<AttributeName attributename="null" columnName="Share Name" required="no"/>
<AttributeName attributename="null" columnName="Share Description" required="no"/>
<AttributeName attributename="null" columnName="Share Link" required="no"/>
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Call Logs2.tsv" description="Call Logs.tsv">
<ArtifactName artifactname="TSK_CALLLOG" comment="Call Logs">
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="from_id" required="no"/>
<AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="to_id" required="yes"/>
<AttributeName attributename="TSK_DATETIME_START" columnName="start_date" required="yes" />
<AttributeName attributename="TSK_DATETIME_END" columnName="end_date" required="yes" />
<AttributeName attributename="TSK_DIRECTION" columnName="direction" required="no"/>
<AttributeName attributename="null" columnName="name" required="no"/>
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Cache Locations.tsv" description="Browser Locations.tsv">
<ArtifactName artifactname="TSK_GPS_BOOKMARK" comment="Cache Location">
<AttributeName attributename="null" columnName="accuracy" required="no" />
<AttributeName attributename="null" columnName="confidence" required="no" />
<AttributeName attributename="TSK_GEO_LATITUDE" columnName="latitude" required="yes"/>
<AttributeName attributename="TSK_GEO_LONGITUDE" columnName="longitude" required="yes"/>
<AttributeName attributename="TSK_DATETIME" columnName="readtime" required="yes" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Browser Locations.tsv" description="Browser Locations.tsv">
<ArtifactName artifactname="TSK_GPS_BOOKMARK" comment="Browser Location">
<AttributeName attributename="TSK_DATETIME" columnName="timestamp" required="yes" />
<AttributeName attributename="TSK_GEO_LATITUDE" columnName="latitude" required="yes"/>
<AttributeName attributename="TSK_GEO_LONGITUDE" columnName="longitude" required="yes"/>
<AttributeName attributename="null" columnName="accuracy" required="no" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Oruxmaps POI.tsv" description="Oruxmaps POI.tsv">
<ArtifactName artifactname="TSK_GPS_BOOKMARK" comment="Oruxmaps POI">
<AttributeName attributename="TSK_GEO_LATITUDE" columnName="poilat" required="yes"/>
<AttributeName attributename="TSK_GEO_LONGITUDE" columnName="poilon" required="yes"/>
<AttributeName attributename="TSK_GEO_ALTITUDE" columnName="poialt" required="yes" />
<AttributeName attributename="TSK_DATETIME" columnName="poitime" required="yes" />
<AttributeName attributename="TSK_NAME" columnName="poiname" required="yes"/>
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Oruxmaps Tracks.tsv" description="Oruxmaps Tracks">
<ArtifactName artifactname="TSK_GPS_TRACK" comment="Oruxmaps Tracks">
<AttributeName attributename="null" columnName="track id" required="no"/>
<AttributeName attributename="null" columnName="track name" required="no"/>
<AttributeName attributename="null" columnName="track description" required="no"/>
<AttributeName attributename="TSK_NAME" columnName="segment name" required="yes"/>
<AttributeName attributename="TSK_GEO_LATITUDE" columnName="latitude" required="yes"/>
<AttributeName attributename="TSK_GEO_LONGITUDE" columnName="longitude" required="yes"/>
<AttributeName attributename="TSK_GEO_ALTITUDE" columnName="altimeter" required="yes" />
<AttributeName attributename="TSK_DATETIME" columnName="datetime" required="yes" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
<FileName filename="Google Map Locations.tsv" description="Google Map Locations">
<ArtifactName artifactname="TSK_GPS_ROUTE" comment="Google Map Locations">
<AttributeName attributename="TSK_DATETIME" columnName="timestamp" required="yes" />
<AttributeName attributename="TSK_GEO_LATITUDE_END" columnName="destination_latitude" required="yes"/>
<AttributeName attributename="TSK_GEO_LONGITUDE_END" columnName="destination_longitude" required="yes"/>
<AttributeName attributename="TSK_NAME" columnName="destination_title" required="yes"/>
<AttributeName attributename="TSK_LOCATION" columnName="destination_address" required="yes"/>
<AttributeName attributename="TSK_GEO_LATITUDE_START" columnName="source_latitude" required="yes"/>
<AttributeName attributename="TSK_GEO_LONGITUDE_START" columnName="source_longitude" required="yes"/>
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName>
</FileName>
-->
</aLeap_Files_To_Process> </aLeap_Files_To_Process>

View File

@ -50,9 +50,9 @@
<FileName filename="App Snapshots.tsv" description="App Snapshots (screenshots)"> <FileName filename="App Snapshots.tsv" description="App Snapshots (screenshots)">
<ArtifactName artifactname="TSK_SCREEN_SHOTS" comment="null"> <ArtifactName artifactname="TSK_SCREEN_SHOTS" comment="null">
<AttributeName attributename="TSK_PROG_NAME" columnName="App Name" required="yes" /> <AttributeName attributename="TSK_PROG_NAME" columnName="App Name" required="yes" />
<AttributeName attributename="TSK_PATH" columnName="SOurce Path" required="yes" /> <AttributeName attributename="TSK_PATH" columnName="Source Path" required="yes" />
<AttributeName attributename="TSK_DATETIME" columnName="Date Modified" required="yes" /> <AttributeName attributename="TSK_DATETIME" columnName="Date Modified" required="yes" />
<AttributeName attributename="null" columnName="Source File Located" required="no" /> <AttributeName attributename="null" columnName="Png Path" required="no" />
</ArtifactName> </ArtifactName>
</FileName> </FileName>
@ -101,6 +101,7 @@
<AttributeName attributename="null" columnName="ISO County Code" required="no" /> <AttributeName attributename="null" columnName="ISO County Code" required="no" />
<AttributeName attributename="null" columnName="Location" required="no" /> <AttributeName attributename="null" columnName="Location" required="no" />
<AttributeName attributename="null" columnName="Service Provider" required="no" /> <AttributeName attributename="null" columnName="Service Provider" required="no" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName> </ArtifactName>
</FileName> </FileName>
@ -743,16 +744,14 @@
</ArtifactName> </ArtifactName>
</FileName> </FileName>
<!-- This section is commented out as the iLeapp program needs to be changed in order to properly process the mail. It appears that the
TSK_TEXT can contain carriage/line returns and this messes reading the tsv file line by line
<FileName filename="SMS - iMessage.tsv" description="SMS - iMessage"> <FileName filename="SMS - iMessage.tsv" description="SMS - iMessage">
<ArtifactName artifactname="TSK_MESSAGE" comment="null"> <ArtifactName artifactname="TSK_MESSAGE" comment="SMS - iMessage">
<AttributeName attributename="TSK_DATETIME" columnName="Message Date" required="yes" /> <AttributeName attributename="TSK_DATETIME" columnName="Message Date" required="yes" />
<AttributeName attributename="TSK_DATETIME_RCVD" columnName="Date Delivered" required="yes" /> <AttributeName attributename="null" columnName="Date Delivered" required="no" />
<AttributeName attributename="TSK_DATETIME_ACCESSED" columnName="Date Read" required="yes" /> <AttributeName attributename="null" columnName="Date Read" required="no" />
<AttributeName attributename="TSK_TEXT" columnName="Message" required="yes" /> <AttributeName attributename="TSK_TEXT" columnName="Message" required="yes" />
<AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="Contact ID" required="yes" /> <AttributeName attributename="TSK_PHONE_NUMBER_FROM" columnName="Contact ID" required="yes" />
<AttributeName attributename="TSK_MESSAGE_TYPE" columnName="Service" required="yes" /> <AttributeName attributename="null" columnName="Service" required="no" />
<AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="Account" required="yes" /> <AttributeName attributename="TSK_PHONE_NUMBER_TO" columnName="Account" required="yes" />
<AttributeName attributename="null" columnName="Is Delivered" required="no" /> <AttributeName attributename="null" columnName="Is Delivered" required="no" />
<AttributeName attributename="null" columnName="Is from Me" required="no" /> <AttributeName attributename="null" columnName="Is from Me" required="no" />
@ -760,9 +759,9 @@
<AttributeName attributename="null" columnName="MIME Type" required="no" /> <AttributeName attributename="null" columnName="MIME Type" required="no" />
<AttributeName attributename="null" columnName="Transfer Type" required="no" /> <AttributeName attributename="null" columnName="Transfer Type" required="no" />
<AttributeName attributename="null" columnName="Total Bytes" required="no" /> <AttributeName attributename="null" columnName="Total Bytes" required="no" />
<AttributeName attributename="TSK_TEXT_FILE" columnName="source file" required="yes"/>
</ArtifactName> </ArtifactName>
</FileName> </FileName>
-->
<FileName filename="Wifi.tsv" description="Wifi"> <FileName filename="Wifi.tsv" description="Wifi">
<ArtifactName artifactname="TSK_WIFI_NETWORK" comment="Wifi"> <ArtifactName artifactname="TSK_WIFI_NETWORK" comment="Wifi">

View File

@ -1085,7 +1085,7 @@ public class PortableCaseReportModule implements ReportModule {
Host newHost = null; Host newHost = null;
if (content instanceof DataSource) { if (content instanceof DataSource) {
Host oldHost = ((DataSource)content).getHost(); Host oldHost = ((DataSource)content).getHost();
newHost = portableSkCase.getHostManager().createHost(oldHost.getName()); newHost = portableSkCase.getHostManager().newHost(oldHost.getName());
} }
CaseDbTransaction trans = portableSkCase.beginTransaction(); CaseDbTransaction trans = portableSkCase.beginTransaction();

View File

@ -70,12 +70,13 @@ import org.sleuthkit.datamodel.ReadContentInputStream;
import org.xml.sax.ContentHandler; import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import org.apache.tika.parser.pdf.PDFParserConfig.OCR_STRATEGY; import org.apache.tika.parser.pdf.PDFParserConfig.OCR_STRATEGY;
import org.sleuthkit.autopsy.coreutils.ExecUtil.HybridTerminator; import org.sleuthkit.autopsy.coreutils.ExecUtil.HybridTerminator;
import org.sleuthkit.datamodel.TskData;
/** /**
* Extracts text from Tika supported content. Protects against Tika parser hangs * Extracts text from Tika supported content. Protects against Tika parser hangs
@ -133,7 +134,7 @@ final class TikaTextExtractor implements TextExtractor {
// Used to log to the tika file that is why it uses the java.util.logging.logger class instead of the Autopsy one // Used to log to the tika file that is why it uses the java.util.logging.logger class instead of the Autopsy one
private static final java.util.logging.Logger TIKA_LOGGER = java.util.logging.Logger.getLogger("Tika"); //NON-NLS private static final java.util.logging.Logger TIKA_LOGGER = java.util.logging.Logger.getLogger("Tika"); //NON-NLS
private static final Logger AUTOPSY_LOGGER = Logger.getLogger(TikaTextExtractor.class.getName()); private static final Logger AUTOPSY_LOGGER = Logger.getLogger(TikaTextExtractor.class.getName());
private static final int LIMITED_OCR_SIZE_MIN = 100 * 1024;
private final ThreadFactory tikaThreadFactory private final ThreadFactory tikaThreadFactory
= new ThreadFactoryBuilder().setNameFormat("tika-reader-%d").build(); = new ThreadFactoryBuilder().setNameFormat("tika-reader-%d").build();
private final ExecutorService executorService = Executors.newSingleThreadExecutor(tikaThreadFactory); private final ExecutorService executorService = Executors.newSingleThreadExecutor(tikaThreadFactory);
@ -143,6 +144,7 @@ final class TikaTextExtractor implements TextExtractor {
private final Content content; private final Content content;
private boolean tesseractOCREnabled; private boolean tesseractOCREnabled;
private boolean limitedOCREnabled;
private static final String TESSERACT_DIR_NAME = "Tesseract-OCR"; //NON-NLS private static final String TESSERACT_DIR_NAME = "Tesseract-OCR"; //NON-NLS
private static final String TESSERACT_EXECUTABLE = "tesseract.exe"; //NON-NLS private static final String TESSERACT_EXECUTABLE = "tesseract.exe"; //NON-NLS
private static final File TESSERACT_PATH = locateTesseractExecutable(); private static final File TESSERACT_PATH = locateTesseractExecutable();
@ -158,7 +160,7 @@ final class TikaTextExtractor implements TextExtractor {
.map(mt -> mt.getType() + "/" + mt.getSubtype()) .map(mt -> mt.getType() + "/" + mt.getSubtype())
.collect(Collectors.toList()); .collect(Collectors.toList());
public TikaTextExtractor(Content content) { TikaTextExtractor(Content content) {
this.content = content; this.content = content;
} }
@ -198,7 +200,7 @@ final class TikaTextExtractor implements TextExtractor {
// Handle images seperately so the OCR task can be cancelled. // Handle images seperately so the OCR task can be cancelled.
// See JIRA-4519 for the need to have cancellation in the UI and ingest. // See JIRA-4519 for the need to have cancellation in the UI and ingest.
if (ocrEnabled() && mimeType.toLowerCase().startsWith("image/")) { if (ocrEnabled() && mimeType.toLowerCase().startsWith("image/") && useOcrOnFile(file)) {
InputStream imageOcrStream = performOCR(file); InputStream imageOcrStream = performOCR(file);
return new InputStreamReader(imageOcrStream, Charset.forName("UTF-8")); return new InputStreamReader(imageOcrStream, Charset.forName("UTF-8"));
} }
@ -219,7 +221,7 @@ final class TikaTextExtractor implements TextExtractor {
officeParserConfig.setUseSAXDocxExtractor(true); officeParserConfig.setUseSAXDocxExtractor(true);
parseContext.set(OfficeParserConfig.class, officeParserConfig); parseContext.set(OfficeParserConfig.class, officeParserConfig);
if (ocrEnabled()) { if (ocrEnabled() && useOcrOnFile(file)) {
// Configure OCR for Tika if it chooses to run OCR // Configure OCR for Tika if it chooses to run OCR
// during extraction // during extraction
TesseractOCRConfig ocrConfig = new TesseractOCRConfig(); TesseractOCRConfig ocrConfig = new TesseractOCRConfig();
@ -256,7 +258,7 @@ final class TikaTextExtractor implements TextExtractor {
+ "Tika returned empty reader for " + content); + "Tika returned empty reader for " + content);
} }
pushbackReader.unread(read); pushbackReader.unread(read);
//Save the metadata if it has not been fetched already. //Save the metadata if it has not been fetched already.
if (metadataMap == null) { if (metadataMap == null) {
metadataMap = new HashMap<>(); metadataMap = new HashMap<>();
@ -264,7 +266,7 @@ final class TikaTextExtractor implements TextExtractor {
metadataMap.put(mtdtKey, metadata.get(mtdtKey)); metadataMap.put(mtdtKey, metadata.get(mtdtKey));
} }
} }
return new ReaderCharSource(pushbackReader).openStream(); return new ReaderCharSource(pushbackReader).openStream();
} catch (TimeoutException te) { } catch (TimeoutException te) {
final String msg = NbBundle.getMessage(this.getClass(), final String msg = NbBundle.getMessage(this.getClass(),
@ -345,6 +347,22 @@ final class TikaTextExtractor implements TextExtractor {
} }
} }
/**
* Method to indicate if OCR should be performed on this image file. Checks
* to see if the limited OCR setting is enabled. If it is it will also check
* that one of the limiting factors is true.
*
* @param file The AbstractFile which OCR might be performed on.
* @param boolean The configuration setting which indicates if limited OCR
* is enabled in Keyword Search.
*
* @return True if limited OCR is not enabled or the image is greater than
* 100KB in size or the image is a derived file.
*/
private boolean useOcrOnFile(AbstractFile file) {
return !limitedOCREnabled || file.getSize() > LIMITED_OCR_SIZE_MIN || file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED;
}
/** /**
* Wraps the creation of a TikaReader into a Future so that it can be * Wraps the creation of a TikaReader into a Future so that it can be
* cancelled. * cancelled.
@ -356,7 +374,7 @@ final class TikaTextExtractor implements TextExtractor {
private final Metadata metadata; private final Metadata metadata;
private final ParseContext parseContext; private final ParseContext parseContext;
public GetTikaReader(AutoDetectParser parser, InputStream stream, GetTikaReader(AutoDetectParser parser, InputStream stream,
Metadata metadata, ParseContext parseContext) { Metadata metadata, ParseContext parseContext) {
this.parser = parser; this.parser = parser;
this.stream = stream; this.stream = stream;
@ -386,7 +404,7 @@ final class TikaTextExtractor implements TextExtractor {
* *
* @throws FileNotFoundException * @throws FileNotFoundException
*/ */
public CleanUpStream(File file) throws FileNotFoundException { CleanUpStream(File file) throws FileNotFoundException {
super(file); super(file);
this.file = file; this.file = file;
} }
@ -442,7 +460,7 @@ final class TikaTextExtractor implements TextExtractor {
if (metadataMap != null) { if (metadataMap != null) {
return ImmutableMap.copyOf(metadataMap); return ImmutableMap.copyOf(metadataMap);
} }
try { try {
metadataMap = new HashMap<>(); metadataMap = new HashMap<>();
InputStream stream = new ReadContentInputStream(content); InputStream stream = new ReadContentInputStream(content);
@ -528,7 +546,7 @@ final class TikaTextExtractor implements TextExtractor {
* @param context Instance containing config classes * @param context Instance containing config classes
*/ */
@Override @Override
public void setExtractionSettings(Lookup context) { public void setExtractionSettings(Lookup context) {
if (context != null) { if (context != null) {
List<ProcessTerminator> terminators = new ArrayList<>(); List<ProcessTerminator> terminators = new ArrayList<>();
ImageConfig configInstance = context.lookup(ImageConfig.class); ImageConfig configInstance = context.lookup(ImageConfig.class);
@ -536,11 +554,13 @@ final class TikaTextExtractor implements TextExtractor {
if (Objects.nonNull(configInstance.getOCREnabled())) { if (Objects.nonNull(configInstance.getOCREnabled())) {
this.tesseractOCREnabled = configInstance.getOCREnabled(); this.tesseractOCREnabled = configInstance.getOCREnabled();
} }
if (Objects.nonNull(configInstance.getLimitedOCREnabled())) {
this.limitedOCREnabled = configInstance.getLimitedOCREnabled();
}
if (Objects.nonNull(configInstance.getOCRLanguages())) { if (Objects.nonNull(configInstance.getOCRLanguages())) {
this.languagePacks = formatLanguagePacks(configInstance.getOCRLanguages()); this.languagePacks = formatLanguagePacks(configInstance.getOCRLanguages());
} }
terminators.add(configInstance.getOCRTimeoutTerminator()); terminators.add(configInstance.getOCRTimeoutTerminator());
} }
@ -548,8 +568,8 @@ final class TikaTextExtractor implements TextExtractor {
if (terminatorInstance != null) { if (terminatorInstance != null) {
terminators.add(terminatorInstance); terminators.add(terminatorInstance);
} }
if(!terminators.isEmpty()) { if (!terminators.isEmpty()) {
this.processTerminator = new HybridTerminator(terminators); this.processTerminator = new HybridTerminator(terminators);
} }
} }
@ -572,4 +592,4 @@ final class TikaTextExtractor implements TextExtractor {
return reader; return reader;
} }
} }
} }

View File

@ -29,10 +29,11 @@ import org.sleuthkit.autopsy.coreutils.ExecUtil.TimedProcessTerminator;
* @see org.openide.util.Lookup * @see org.openide.util.Lookup
*/ */
public class ImageConfig { public class ImageConfig {
private static final int OCR_TIMEOUT_SECONDS = 30 * 60; private static final int OCR_TIMEOUT_SECONDS = 30 * 60;
private Boolean OCREnabled; private Boolean OCREnabled;
private Boolean limitedOCREnabled;
private List<String> ocrLanguages; private List<String> ocrLanguages;
private final TimedProcessTerminator ocrTimedTerminator = new TimedProcessTerminator(OCR_TIMEOUT_SECONDS); private final TimedProcessTerminator ocrTimedTerminator = new TimedProcessTerminator(OCR_TIMEOUT_SECONDS);
@ -46,6 +47,16 @@ public class ImageConfig {
this.OCREnabled = enabled; this.OCREnabled = enabled;
} }
/**
* Enables the limiting OCR to be run on larger images and images which were
* extracted from documents.
*
* @param enabled Flag indicating if OCR is enabled.
*/
public void setLimitedOCREnabled(boolean enabled) {
this.limitedOCREnabled = enabled;
}
/** /**
* Gets the OCR flag that has been set. By default this flag is turned off. * Gets the OCR flag that has been set. By default this flag is turned off.
* *
@ -57,9 +68,9 @@ public class ImageConfig {
/** /**
* Sets languages for OCR. * Sets languages for OCR.
* *
* See PlatformUtil for list of installed language packs. * See PlatformUtil for list of installed language packs.
* *
* @param languages List of languages to use * @param languages List of languages to use
*/ */
public void setOCRLanguages(List<String> languages) { public void setOCRLanguages(List<String> languages) {
@ -68,19 +79,30 @@ public class ImageConfig {
/** /**
* Gets the list of languages OCR should perform. * Gets the list of languages OCR should perform.
* *
* @return Collection of OCR languages * @return Collection of OCR languages
*/ */
public List<String> getOCRLanguages() { public List<String> getOCRLanguages() {
return this.ocrLanguages; return this.ocrLanguages;
} }
/** /**
* Returns a ProcessTerminator for timing out the OCR process. * Returns a ProcessTerminator for timing out the OCR process.
* *
* @return ProcessTerminator instance. * @return ProcessTerminator instance.
*/ */
public ProcessTerminator getOCRTimeoutTerminator() { public ProcessTerminator getOCRTimeoutTerminator() {
return ocrTimedTerminator; return ocrTimedTerminator;
} }
/**
* Gets the limited OCR flag to indicate if OCR should be limited to larger
* images and images which were extracted from documents.
*
* @return Flag indicating if limited OCR is enabled. True if OCR should be
* limited, false otherwise..
*/
public boolean getLimitedOCREnabled() {
return limitedOCREnabled;
}
} }

View File

@ -30,6 +30,7 @@ import java.io.IOException;
import javax.swing.JPanel; import javax.swing.JPanel;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.texttranslation.TextTranslator; import org.sleuthkit.autopsy.texttranslation.TextTranslator;
import org.sleuthkit.autopsy.texttranslation.TranslationConfigException; import org.sleuthkit.autopsy.texttranslation.TranslationConfigException;
import org.sleuthkit.autopsy.texttranslation.TranslationException; import org.sleuthkit.autopsy.texttranslation.TranslationException;
@ -46,7 +47,7 @@ public class BingTranslator implements TextTranslator {
//https://docs.microsoft.com/en-us/azure/cognitive-services/translator/language-support //https://docs.microsoft.com/en-us/azure/cognitive-services/translator/language-support
private static final String BASE_URL = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to="; private static final String BASE_URL = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=";
private static final int MAX_STRING_LENGTH = 5000; private static final int MAX_STRING_LENGTH = 5000;
private final BingTranslatorSettingsPanel settingsPanel; private BingTranslatorSettingsPanel settingsPanel;
private final BingTranslatorSettings settings = new BingTranslatorSettings(); private final BingTranslatorSettings settings = new BingTranslatorSettings();
// This sends messages to Microsoft. // This sends messages to Microsoft.
private final OkHttpClient CLIENT = new OkHttpClient(); private final OkHttpClient CLIENT = new OkHttpClient();
@ -55,11 +56,11 @@ public class BingTranslator implements TextTranslator {
* Create a Bing Translator * Create a Bing Translator
*/ */
public BingTranslator() { public BingTranslator() {
settingsPanel = new BingTranslatorSettingsPanel(settings.getAuthenticationKey(), settings.getTargetLanguageCode());
} }
/** /**
* Get the tranlationurl for the specified language code * Get the tranlation url for the specified language code
* *
* *
* *
@ -133,7 +134,11 @@ public class BingTranslator implements TextTranslator {
} }
@Override @Override
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
public JPanel getSettingsPanel() { public JPanel getSettingsPanel() {
if(settingsPanel == null) {
settingsPanel = new BingTranslatorSettingsPanel(settings.getAuthenticationKey(), settings.getTargetLanguageCode());
}
return settingsPanel; return settingsPanel;
} }

View File

@ -36,6 +36,7 @@ import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.EscapeUtil; import org.sleuthkit.autopsy.coreutils.EscapeUtil;
import org.sleuthkit.autopsy.coreutils.ThreadConfined;
import org.sleuthkit.autopsy.texttranslation.TextTranslator; import org.sleuthkit.autopsy.texttranslation.TextTranslator;
import org.sleuthkit.autopsy.texttranslation.TranslationConfigException; import org.sleuthkit.autopsy.texttranslation.TranslationConfigException;
import org.sleuthkit.autopsy.texttranslation.TranslationException; import org.sleuthkit.autopsy.texttranslation.TranslationException;
@ -50,7 +51,7 @@ public final class GoogleTranslator implements TextTranslator {
private static final Logger logger = Logger.getLogger(GoogleTranslator.class.getName()); private static final Logger logger = Logger.getLogger(GoogleTranslator.class.getName());
//See translate method for justification of this limit. //See translate method for justification of this limit.
private static final int MAX_PAYLOAD_SIZE = 5000; private static final int MAX_PAYLOAD_SIZE = 5000;
private final GoogleTranslatorSettingsPanel settingsPanel; private GoogleTranslatorSettingsPanel settingsPanel;
private final GoogleTranslatorSettings settings = new GoogleTranslatorSettings(); private final GoogleTranslatorSettings settings = new GoogleTranslatorSettings();
private Translate googleTranslate; private Translate googleTranslate;
@ -59,7 +60,6 @@ public final class GoogleTranslator implements TextTranslator {
*/ */
public GoogleTranslator() { public GoogleTranslator() {
// Instantiates a client // Instantiates a client
settingsPanel = new GoogleTranslatorSettingsPanel(settings.getCredentialPath(), settings.getTargetLanguageCode());
loadTranslator(); loadTranslator();
} }
@ -134,7 +134,11 @@ public final class GoogleTranslator implements TextTranslator {
} }
@Override @Override
@ThreadConfined(type = ThreadConfined.ThreadType.AWT)
public JPanel getSettingsPanel() { public JPanel getSettingsPanel() {
if(settingsPanel == null) {
settingsPanel = new GoogleTranslatorSettingsPanel(settings.getCredentialPath(), settings.getTargetLanguageCode());
}
return settingsPanel; return settingsPanel;
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2020 Basis Technology Corp. * Copyright 2020-2021 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");
@ -163,7 +163,7 @@ public class TaskRetryUtil {
* each attempt and an optional timeout for each attempt. If an attempt * each attempt and an optional timeout for each attempt. If an attempt
* times out, that particular attempt task will be cancelled. * times out, that particular attempt task will be cancelled.
* *
* @tparam T The return type of the task. * @tparam T The return type of the task.
* @param task The task. * @param task The task.
* @param attempts The defining details for each attempt of the task. * @param attempts The defining details for each attempt of the task.
* @param executor The scheduled task executor to be used to attempt the * @param executor The scheduled task executor to be used to attempt the
@ -181,6 +181,9 @@ public class TaskRetryUtil {
* @throws InterruptedException * @throws InterruptedException
*/ */
public static <T> T attemptTask(Callable<T> task, List<TaskAttempt> attempts, ScheduledThreadPoolExecutor executor, Terminator terminator, Logger logger, String taskDesc) throws InterruptedException { public static <T> T attemptTask(Callable<T> task, List<TaskAttempt> attempts, ScheduledThreadPoolExecutor executor, Terminator terminator, Logger logger, String taskDesc) throws InterruptedException {
/*
* Attempt the task.
*/
T result = null; T result = null;
String taskDescForLog = taskDesc != null ? taskDesc : "Task"; String taskDescForLog = taskDesc != null ? taskDesc : "Task";
int attemptCounter = 0; int attemptCounter = 0;
@ -195,9 +198,6 @@ public class TaskRetryUtil {
break; break;
} }
TaskAttempt attempt = attempts.get(attemptCounter); TaskAttempt attempt = attempts.get(attemptCounter);
if (logger != null) {
logger.log(Level.INFO, String.format("SCHEDULING '%s' (attempt = %d, delay = %d %s, timeout = %d %s)", taskDescForLog, attemptCounter + 1, attempt.getDelay(), attempt.getTimeUnit(), attempt.getTimeout(), attempt.getTimeUnit()));
}
if (attemptCounter > 0) { if (attemptCounter > 0) {
totalTaskRetries.incrementAndGet(); totalTaskRetries.incrementAndGet();
} }
@ -222,11 +222,27 @@ public class TaskRetryUtil {
} }
++attemptCounter; ++attemptCounter;
} }
/*
* If the task required more than one attempt, log it.
*/
if (logger != null && attemptCounter > 1) {
if (result != null) {
logger.log(Level.WARNING, String.format("'%s' succeeded after %d attempts", taskDescForLog, attemptCounter));
} else {
logger.log(Level.SEVERE, String.format("'%s' failed after %d attempts", taskDescForLog, attemptCounter));
}
}
/*
* If the task failed, count it as a failed task.
*/
if (result == null) { if (result == null) {
if (terminator == null || !terminator.stopTaskAttempts()) { if (terminator == null || !terminator.stopTaskAttempts()) {
totalFailedTasks.incrementAndGet(); totalFailedTasks.incrementAndGet();
} }
} }
return result; return result;
} }

View File

@ -45,7 +45,6 @@ import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.openide.modules.InstalledFileLocator; import org.openide.modules.InstalledFileLocator;
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
import org.sleuthkit.autopsy.url.analytics.DomainCategory; import org.sleuthkit.autopsy.url.analytics.DomainCategory;
/** /**
@ -396,7 +395,7 @@ class WebCategoriesDataModel implements AutoCloseable {
* @return The list of domain suffixes and their categories. * @return The list of domain suffixes and their categories.
* @throws SQLException * @throws SQLException
*/ */
List<DomainCategory> getRecords() throws SQLException { synchronized List<DomainCategory> getRecords() throws SQLException {
if (!isInitialized()) { if (!isInitialized()) {
initialize(); initialize();
} }
@ -428,7 +427,7 @@ class WebCategoriesDataModel implements AutoCloseable {
* @return The found entry or null. * @return The found entry or null.
* @throws SQLException * @throws SQLException
*/ */
DomainCategory getRecordBySuffix(String domainSuffix) throws SQLException { synchronized DomainCategory getRecordBySuffix(String domainSuffix) throws SQLException {
if (!isInitialized()) { if (!isInitialized()) {
initialize(); initialize();
} }
@ -529,7 +528,9 @@ class WebCategoriesDataModel implements AutoCloseable {
@Override @Override
public synchronized void close() throws SQLException { public synchronized void close() throws SQLException {
dbConn.close(); if (dbConn != null) {
dbConn = null; dbConn.close();
dbConn = null;
}
} }
} }

View File

@ -973,7 +973,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
* job to be shut down in an orderly fashion. * job to be shut down in an orderly fashion.
*/ */
void cancelCurrentJob() { void cancelCurrentJob() {
if (State.RUNNING != state) { if ((State.RUNNING != state) && (State.SHUTTING_DOWN != state)) {
return; return;
} }
synchronized (jobsLock) { synchronized (jobsLock) {
@ -2564,6 +2564,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
synchronized (ingestLock) { synchronized (ingestLock) {
// Try each DSP in decreasing order of confidence // Try each DSP in decreasing order of confidence
for (AutoIngestDataSourceProcessor selectedProcessor : validDataSourceProcessors) { for (AutoIngestDataSourceProcessor selectedProcessor : validDataSourceProcessors) {
currentJob.setDataSourceProcessor(selectedProcessor);
UUID taskId = UUID.randomUUID(); UUID taskId = UUID.randomUUID();
caseForJob.notifyAddingDataSource(taskId); caseForJob.notifyAddingDataSource(taskId);
DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId, ingestLock); DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId, ingestLock);

View File

@ -205,9 +205,7 @@ DeleteCaseTask.progress.parsingManifest=Parsing manifest file {0}...
DeleteCaseTask.progress.releasingManifestLock=Releasing lock on the manifest file {0}... DeleteCaseTask.progress.releasingManifestLock=Releasing lock on the manifest file {0}...
DeleteCaseTask.progress.startMessage=Starting deletion... DeleteCaseTask.progress.startMessage=Starting deletion...
DeleteOrphanCaseNodesAction.progressDisplayName=Cleanup Case Znodes DeleteOrphanCaseNodesAction.progressDisplayName=Cleanup Case Znodes
# {0} - item count
DeleteOrphanCaseNodesDialog.additionalInit.lblNodeCount.text=Znodes found: {0} DeleteOrphanCaseNodesDialog.additionalInit.lblNodeCount.text=Znodes found: {0}
# {0} - item count
DeleteOrphanCaseNodesDialog.additionalInit.znodesTextArea.countMessage=ZNODES FOUND: {0} DeleteOrphanCaseNodesDialog.additionalInit.znodesTextArea.countMessage=ZNODES FOUND: {0}
DeleteOrphanCaseNodesTask.progress.connectingToCoordSvc=Connecting to the coordination service DeleteOrphanCaseNodesTask.progress.connectingToCoordSvc=Connecting to the coordination service
# {0} - node path # {0} - node path

View File

@ -320,3 +320,4 @@ ExtractedContentPanel.pageOfLabel.text=of
ExtractedContentPanel.pageCurLabel.text=- ExtractedContentPanel.pageCurLabel.text=-
ExtractedContentPanel.pagesLabel.text=Page: ExtractedContentPanel.pagesLabel.text=Page:
KeywordSearchGlobalSearchSettingsPanel.ocrCheckBox.text=Enable Optical Character Recognition (OCR) KeywordSearchGlobalSearchSettingsPanel.ocrCheckBox.text=Enable Optical Character Recognition (OCR)
KeywordSearchGlobalSearchSettingsPanel.limitedOcrCheckbox.text=Only process images which are over 100KB in size or extracted from a document (Beta)

View File

@ -23,6 +23,7 @@ ExtractAllTermsReport.search.noFilesInIdxMsg2=No files are in index yet. Try aga
ExtractAllTermsReport.search.searchIngestInProgressTitle=Keyword Search Ingest in Progress ExtractAllTermsReport.search.searchIngestInProgressTitle=Keyword Search Ingest in Progress
ExtractAllTermsReport.startExport=Starting Unique Word Extraction ExtractAllTermsReport.startExport=Starting Unique Word Extraction
ExtractedContentPanel.setMarkup.panelTxt=<span style='font-style:italic'>Loading text... Please wait</span> ExtractedContentPanel.setMarkup.panelTxt=<span style='font-style:italic'>Loading text... Please wait</span>
# {0} - Content name
ExtractedContentPanel.SetMarkup.progress.loading=Loading text for {0} ExtractedContentPanel.SetMarkup.progress.loading=Loading text for {0}
GlobalEditListPanel.editKeyword.title=Edit Keyword GlobalEditListPanel.editKeyword.title=Edit Keyword
GlobalEditListPanel.warning.text=Boundary characters ^ and $ do not match word boundaries. Consider\nreplacing with an explicit list of boundary characters, such as [ \\.,] GlobalEditListPanel.warning.text=Boundary characters ^ and $ do not match word boundaries. Consider\nreplacing with an explicit list of boundary characters, such as [ \\.,]
@ -30,6 +31,7 @@ GlobalEditListPanel.warning.title=Warning
IndexedText.errorMessage.errorGettingText=<span style='font-style:italic'>Error retrieving indexed text.</span> IndexedText.errorMessage.errorGettingText=<span style='font-style:italic'>Error retrieving indexed text.</span>
IndexedText.warningMessage.knownFile=<span style='font-style:italic'>This file is a known file (based on MD5 hash) and does not have indexed text.</span> IndexedText.warningMessage.knownFile=<span style='font-style:italic'>This file is a known file (based on MD5 hash) and does not have indexed text.</span>
IndexedText.warningMessage.noTextAvailable=<span style='font-style:italic'>No indexed text for this file.</span> IndexedText.warningMessage.noTextAvailable=<span style='font-style:italic'>No indexed text for this file.</span>
KeywordSearchGlobalSearchSettingsPanel.customizeComponents.windowsLimitedOCR=Only process images which are over 100KB in size or extracted from a document. (Beta) (Requires Windows 64-bit)
KeywordSearchGlobalSearchSettingsPanel.customizeComponents.windowsOCR=Enable Optical Character Recognition (OCR) (Requires Windows 64-bit) KeywordSearchGlobalSearchSettingsPanel.customizeComponents.windowsOCR=Enable Optical Character Recognition (OCR) (Requires Windows 64-bit)
KeywordSearchGlobalSettingsPanel.Title=Global Keyword Search Settings KeywordSearchGlobalSettingsPanel.Title=Global Keyword Search Settings
KeywordSearchIngestModule.init.badInitMsg=Keyword search server was not properly initialized, cannot run keyword search ingest. KeywordSearchIngestModule.init.badInitMsg=Keyword search server was not properly initialized, cannot run keyword search ingest.
@ -49,7 +51,7 @@ KeywordSearchResultFactory.createNodeForKey.noResultsFound.text=No results found
KeywordSearchResultFactory.query.exception.msg=Could not perform the query KeywordSearchResultFactory.query.exception.msg=Could not perform the query
OpenIDE-Module-Display-Category=Ingest Module OpenIDE-Module-Display-Category=Ingest Module
OpenIDE-Module-Long-Description=Keyword Search ingest module.\n\nThe module indexes files found in the disk image at ingest time.\nIt then periodically runs the search on the indexed files using one or more keyword lists (containing pure words and/or regular expressions) and posts results.\n\nThe module also contains additional tools integrated in the main GUI, such as keyword list configuration, keyword search bar in the top-right corner, extracted text viewer and search results viewer showing highlighted keywords found. OpenIDE-Module-Long-Description=Keyword Search ingest module.\n\nThe module indexes files found in the disk image at ingest time.\nIt then periodically runs the search on the indexed files using one or more keyword lists (containing pure words and/or regular expressions) and posts results.\n\n\The module also contains additional tools integrated in the main GUI, such as keyword list configuration, keyword search bar in the top-right corner, extracted text viewer and search results viewer showing highlighted keywords found.
OpenIDE-Module-Name=KeywordSearch OpenIDE-Module-Name=KeywordSearch
OptionsCategory_Name_KeywordSearchOptions=Keyword Search OptionsCategory_Name_KeywordSearchOptions=Keyword Search
OptionsCategory_Keywords_KeywordSearchOptions=Keyword Search OptionsCategory_Keywords_KeywordSearchOptions=Keyword Search
@ -400,6 +402,7 @@ ExtractedContentPanel.pageOfLabel.text=of
ExtractedContentPanel.pageCurLabel.text=- ExtractedContentPanel.pageCurLabel.text=-
ExtractedContentPanel.pagesLabel.text=Page: ExtractedContentPanel.pagesLabel.text=Page:
KeywordSearchGlobalSearchSettingsPanel.ocrCheckBox.text=Enable Optical Character Recognition (OCR) KeywordSearchGlobalSearchSettingsPanel.ocrCheckBox.text=Enable Optical Character Recognition (OCR)
KeywordSearchGlobalSearchSettingsPanel.limitedOcrCheckbox.text=Only process images which are over 100KB in size or extracted from a document (Beta)
TextZoomPanel.zoomInButton.text= TextZoomPanel.zoomInButton.text=
TextZoomPanel.zoomOutButton.text= TextZoomPanel.zoomOutButton.text=
TextZoomPanel.zoomResetButton.text=Reset TextZoomPanel.zoomResetButton.text=Reset

View File

@ -31,22 +31,17 @@
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="settingsSeparator" min="-2" pref="326" max="-2" attributes="0"/> <Component id="settingsSeparator" min="-2" pref="326" max="-2" attributes="0"/>
</Group> </Group>
<Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="skipNSRLCheckBox" min="-2" max="-2" attributes="0"/>
<Component id="showSnippetsCB" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="ocrCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Component id="informationLabel" min="-2" max="-2" attributes="0"/> <Component id="informationLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="informationSeparator" min="-2" pref="309" max="-2" attributes="0"/> <Component id="informationSeparator" min="-2" pref="309" max="-2" attributes="0"/>
</Group> </Group>
<Group type="102" alignment="0" attributes="0"> <Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/> <EmptySpace min="-2" pref="16" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="skipNSRLCheckBox" min="-2" max="-2" attributes="0"/>
<Component id="showSnippetsCB" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="ocrCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Component id="filesIndexedLabel" linkSize="1" min="-2" max="-2" attributes="0"/> <Component id="filesIndexedLabel" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/> <EmptySpace type="separate" max="-2" attributes="0"/>
@ -54,7 +49,7 @@
</Group> </Group>
<Component id="frequencyLabel" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="frequencyLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/> <EmptySpace min="-2" pref="16" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="timeRadioButton2" min="-2" max="-2" attributes="0"/> <Component id="timeRadioButton2" min="-2" max="-2" attributes="0"/>
<Component id="timeRadioButton1" min="-2" max="-2" attributes="0"/> <Component id="timeRadioButton1" min="-2" max="-2" attributes="0"/>
@ -68,6 +63,10 @@
<EmptySpace type="separate" max="-2" attributes="0"/> <EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="chunksValLabel" min="-2" max="-2" attributes="0"/> <Component id="chunksValLabel" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="16" max="-2" attributes="0"/>
<Component id="limitedOcrCheckbox" min="-2" max="-2" attributes="0"/>
</Group>
</Group> </Group>
</Group> </Group>
</Group> </Group>
@ -92,6 +91,8 @@
<Component id="showSnippetsCB" min="-2" max="-2" attributes="0"/> <Component id="showSnippetsCB" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="ocrCheckBox" min="-2" max="-2" attributes="0"/> <Component id="ocrCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="limitedOcrCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="frequencyLabel" min="-2" max="-2" attributes="0"/> <Component id="frequencyLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
@ -121,7 +122,7 @@
</Group> </Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/> <EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="ingestWarningLabel" min="-2" max="-2" attributes="0"/> <Component id="ingestWarningLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="43" max="32767" attributes="0"/> <EmptySpace max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -288,5 +289,15 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ocrCheckBoxActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ocrCheckBoxActionPerformed"/>
</Events> </Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="limitedOcrCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/keywordsearch/Bundle.properties" key="KeywordSearchGlobalSearchSettingsPanel.limitedOcrCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="limitedOcrCheckboxActionPerformed"/>
</Events>
</Component>
</SubComponents> </SubComponents>
</Form> </Form>

View File

@ -35,7 +35,8 @@ import org.sleuthkit.autopsy.keywordsearch.KeywordSearchIngestModule.UpdateFrequ
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implements OptionsPanel { class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implements OptionsPanel {
private static final long serialVersionUID = 1L;
private final Logger logger = Logger.getLogger(KeywordSearchGlobalSearchSettingsPanel.class.getName()); private final Logger logger = Logger.getLogger(KeywordSearchGlobalSearchSettingsPanel.class.getName());
/** /**
@ -45,17 +46,19 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
initComponents(); initComponents();
customizeComponents(); customizeComponents();
} }
private void activateWidgets() { private void activateWidgets() {
skipNSRLCheckBox.setSelected(KeywordSearchSettings.getSkipKnown()); skipNSRLCheckBox.setSelected(KeywordSearchSettings.getSkipKnown());
showSnippetsCB.setSelected(KeywordSearchSettings.getShowSnippets()); showSnippetsCB.setSelected(KeywordSearchSettings.getShowSnippets());
ocrCheckBox.setSelected(KeywordSearchSettings.getOcrOption()); ocrCheckBox.setSelected(KeywordSearchSettings.getOcrOption());
limitedOcrCheckbox.setSelected(KeywordSearchSettings.getLimitedOcrOption());
boolean ingestRunning = IngestManager.getInstance().isIngestRunning(); boolean ingestRunning = IngestManager.getInstance().isIngestRunning();
ingestWarningLabel.setVisible(ingestRunning); ingestWarningLabel.setVisible(ingestRunning);
skipNSRLCheckBox.setEnabled(!ingestRunning); skipNSRLCheckBox.setEnabled(!ingestRunning);
ocrCheckBox.setEnabled(!ingestRunning); ocrCheckBox.setEnabled(!ingestRunning);
limitedOcrCheckbox.setEnabled(ocrCheckBox.isSelected() && !ingestRunning);
setTimeSettingEnabled(!ingestRunning); setTimeSettingEnabled(!ingestRunning);
final UpdateFrequency curFreq = KeywordSearchSettings.getUpdateFrequency(); final UpdateFrequency curFreq = KeywordSearchSettings.getUpdateFrequency();
switch (curFreq) { switch (curFreq) {
case FAST: case FAST:
@ -109,6 +112,7 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
timeRadioButton5 = new javax.swing.JRadioButton(); timeRadioButton5 = new javax.swing.JRadioButton();
ingestWarningLabel = new javax.swing.JLabel(); ingestWarningLabel = new javax.swing.JLabel();
ocrCheckBox = new javax.swing.JCheckBox(); ocrCheckBox = new javax.swing.JCheckBox();
limitedOcrCheckbox = new javax.swing.JCheckBox();
skipNSRLCheckBox.setText(org.openide.util.NbBundle.getMessage(KeywordSearchGlobalSearchSettingsPanel.class, "KeywordSearchGlobalSearchSettingsPanel.skipNSRLCheckBox.text")); // NOI18N skipNSRLCheckBox.setText(org.openide.util.NbBundle.getMessage(KeywordSearchGlobalSearchSettingsPanel.class, "KeywordSearchGlobalSearchSettingsPanel.skipNSRLCheckBox.text")); // NOI18N
skipNSRLCheckBox.setToolTipText(org.openide.util.NbBundle.getMessage(KeywordSearchGlobalSearchSettingsPanel.class, "KeywordSearchGlobalSearchSettingsPanel.skipNSRLCheckBox.toolTipText")); // NOI18N skipNSRLCheckBox.setToolTipText(org.openide.util.NbBundle.getMessage(KeywordSearchGlobalSearchSettingsPanel.class, "KeywordSearchGlobalSearchSettingsPanel.skipNSRLCheckBox.toolTipText")); // NOI18N
@ -189,6 +193,13 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
} }
}); });
limitedOcrCheckbox.setText(org.openide.util.NbBundle.getMessage(KeywordSearchGlobalSearchSettingsPanel.class, "KeywordSearchGlobalSearchSettingsPanel.limitedOcrCheckbox.text")); // NOI18N
limitedOcrCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
limitedOcrCheckboxActionPerformed(evt);
}
});
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(
@ -203,26 +214,23 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
.addComponent(settingsLabel) .addComponent(settingsLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(settingsSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 326, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(settingsSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 326, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(skipNSRLCheckBox)
.addComponent(showSnippetsCB)
.addComponent(ocrCheckBox)))
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addComponent(informationLabel) .addComponent(informationLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(informationSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 309, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(informationSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 309, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10) .addGap(16, 16, 16)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(skipNSRLCheckBox)
.addComponent(showSnippetsCB)
.addComponent(ocrCheckBox)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addComponent(filesIndexedLabel) .addComponent(filesIndexedLabel)
.addGap(18, 18, 18) .addGap(18, 18, 18)
.addComponent(filesIndexedValue)) .addComponent(filesIndexedValue))
.addComponent(frequencyLabel) .addComponent(frequencyLabel)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10) .addGap(16, 16, 16)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(timeRadioButton2) .addComponent(timeRadioButton2)
.addComponent(timeRadioButton1) .addComponent(timeRadioButton1)
@ -232,7 +240,10 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addComponent(chunksLabel) .addComponent(chunksLabel)
.addGap(18, 18, 18) .addGap(18, 18, 18)
.addComponent(chunksValLabel))))) .addComponent(chunksValLabel))
.addGroup(layout.createSequentialGroup()
.addGap(16, 16, 16)
.addComponent(limitedOcrCheckbox)))))
.addGap(0, 0, Short.MAX_VALUE))) .addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap()) .addContainerGap())
); );
@ -252,6 +263,8 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
.addComponent(showSnippetsCB) .addComponent(showSnippetsCB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(ocrCheckBox) .addComponent(ocrCheckBox)
.addGap(0, 0, 0)
.addComponent(limitedOcrCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(frequencyLabel) .addComponent(frequencyLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -278,7 +291,7 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
.addComponent(chunksValLabel)) .addComponent(chunksValLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(ingestWarningLabel) .addComponent(ingestWarningLabel)
.addContainerGap(43, Short.MAX_VALUE)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
); );
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
@ -311,9 +324,14 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
}//GEN-LAST:event_timeRadioButton4ActionPerformed }//GEN-LAST:event_timeRadioButton4ActionPerformed
private void ocrCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ocrCheckBoxActionPerformed private void ocrCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ocrCheckBoxActionPerformed
limitedOcrCheckbox.setEnabled(ocrCheckBox.isSelected());
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_ocrCheckBoxActionPerformed }//GEN-LAST:event_ocrCheckBoxActionPerformed
private void limitedOcrCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_limitedOcrCheckboxActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_limitedOcrCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel chunksLabel; private javax.swing.JLabel chunksLabel;
private javax.swing.JLabel chunksValLabel; private javax.swing.JLabel chunksValLabel;
@ -323,6 +341,7 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
private javax.swing.JLabel informationLabel; private javax.swing.JLabel informationLabel;
private javax.swing.JSeparator informationSeparator; private javax.swing.JSeparator informationSeparator;
private javax.swing.JLabel ingestWarningLabel; private javax.swing.JLabel ingestWarningLabel;
private javax.swing.JCheckBox limitedOcrCheckbox;
private javax.swing.JCheckBox ocrCheckBox; private javax.swing.JCheckBox ocrCheckBox;
private javax.swing.JLabel settingsLabel; private javax.swing.JLabel settingsLabel;
private javax.swing.JSeparator settingsSeparator; private javax.swing.JSeparator settingsSeparator;
@ -342,13 +361,14 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
KeywordSearchSettings.setUpdateFrequency(getSelectedTimeValue()); KeywordSearchSettings.setUpdateFrequency(getSelectedTimeValue());
KeywordSearchSettings.setShowSnippets(showSnippetsCB.isSelected()); KeywordSearchSettings.setShowSnippets(showSnippetsCB.isSelected());
KeywordSearchSettings.setOcrOption(ocrCheckBox.isSelected()); KeywordSearchSettings.setOcrOption(ocrCheckBox.isSelected());
KeywordSearchSettings.setLimitedOcrOption(limitedOcrCheckbox.isSelected());
} }
@Override @Override
public void load() { public void load() {
activateWidgets(); activateWidgets();
} }
private void setTimeSettingEnabled(boolean enabled) { private void setTimeSettingEnabled(boolean enabled) {
timeRadioButton1.setEnabled(enabled); timeRadioButton1.setEnabled(enabled);
timeRadioButton2.setEnabled(enabled); timeRadioButton2.setEnabled(enabled);
@ -357,7 +377,7 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
timeRadioButton5.setEnabled(enabled); timeRadioButton5.setEnabled(enabled);
frequencyLabel.setEnabled(enabled); frequencyLabel.setEnabled(enabled);
} }
private UpdateFrequency getSelectedTimeValue() { private UpdateFrequency getSelectedTimeValue() {
if (timeRadioButton1.isSelected()) { if (timeRadioButton1.isSelected()) {
return UpdateFrequency.FAST; return UpdateFrequency.FAST;
@ -372,18 +392,19 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
} }
return UpdateFrequency.DEFAULT; return UpdateFrequency.DEFAULT;
} }
@NbBundle.Messages({"KeywordSearchGlobalSearchSettingsPanel.customizeComponents.windowsOCR=Enable Optical Character Recognition (OCR) (Requires Windows 64-bit)"}) @NbBundle.Messages({"KeywordSearchGlobalSearchSettingsPanel.customizeComponents.windowsOCR=Enable Optical Character Recognition (OCR) (Requires Windows 64-bit)",
"KeywordSearchGlobalSearchSettingsPanel.customizeComponents.windowsLimitedOCR=Only process images which are over 100KB in size or extracted from a document. (Beta) (Requires Windows 64-bit)"})
private void customizeComponents() { private void customizeComponents() {
timeGroup.add(timeRadioButton1); timeGroup.add(timeRadioButton1);
timeGroup.add(timeRadioButton2); timeGroup.add(timeRadioButton2);
timeGroup.add(timeRadioButton3); timeGroup.add(timeRadioButton3);
timeGroup.add(timeRadioButton4); timeGroup.add(timeRadioButton4);
timeGroup.add(timeRadioButton5); timeGroup.add(timeRadioButton5);
this.skipNSRLCheckBox.setSelected(KeywordSearchSettings.getSkipKnown()); this.skipNSRLCheckBox.setSelected(KeywordSearchSettings.getSkipKnown());
try { try {
filesIndexedValue.setText(Integer.toString(KeywordSearch.getServer().queryNumIndexedFiles())); filesIndexedValue.setText(Integer.toString(KeywordSearch.getServer().queryNumIndexedFiles()));
chunksValLabel.setText(Integer.toString(KeywordSearch.getServer().queryNumIndexedChunks())); chunksValLabel.setText(Integer.toString(KeywordSearch.getServer().queryNumIndexedChunks()));
@ -395,15 +416,18 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
ocrCheckBox.setText(Bundle.KeywordSearchGlobalSearchSettingsPanel_customizeComponents_windowsOCR()); ocrCheckBox.setText(Bundle.KeywordSearchGlobalSearchSettingsPanel_customizeComponents_windowsOCR());
ocrCheckBox.setSelected(false); ocrCheckBox.setSelected(false);
ocrCheckBox.setEnabled(false); ocrCheckBox.setEnabled(false);
} limitedOcrCheckbox.setSelected(false);
limitedOcrCheckbox.setEnabled(false);
limitedOcrCheckbox.setText(Bundle.KeywordSearchGlobalSearchSettingsPanel_customizeComponents_windowsLimitedOCR());
}
KeywordSearch.addNumIndexedFilesChangeListener( KeywordSearch.addNumIndexedFilesChangeListener(
new PropertyChangeListener() { new PropertyChangeListener() {
@Override @Override
public void propertyChange(PropertyChangeEvent evt) { public void propertyChange(PropertyChangeEvent evt) {
String changed = evt.getPropertyName(); String changed = evt.getPropertyName();
Object newValue = evt.getNewValue(); Object newValue = evt.getNewValue();
if (changed.equals(KeywordSearch.NUM_FILES_CHANGE_EVT)) { if (changed.equals(KeywordSearch.NUM_FILES_CHANGE_EVT)) {
int newFilesIndexed = ((Integer) newValue); int newFilesIndexed = ((Integer) newValue);
filesIndexedValue.setText(Integer.toString(newFilesIndexed)); filesIndexedValue.setText(Integer.toString(newFilesIndexed));
@ -416,7 +440,7 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
} }
} }
}); });
//allow panel to toggle its enabled status while it is open based on ingest events //allow panel to toggle its enabled status while it is open based on ingest events
IngestManager.getInstance().addIngestJobEventListener(new PropertyChangeListener() { IngestManager.getInstance().addIngestJobEventListener(new PropertyChangeListener() {
@Override @Override

View File

@ -513,6 +513,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
private boolean extractTextAndIndex(AbstractFile aFile, Map<String, String> extractedMetadata) throws IngesterException { private boolean extractTextAndIndex(AbstractFile aFile, Map<String, String> extractedMetadata) throws IngesterException {
ImageConfig imageConfig = new ImageConfig(); ImageConfig imageConfig = new ImageConfig();
imageConfig.setOCREnabled(KeywordSearchSettings.getOcrOption()); imageConfig.setOCREnabled(KeywordSearchSettings.getOcrOption());
imageConfig.setLimitedOCREnabled(KeywordSearchSettings.getLimitedOcrOption());
ProcessTerminator terminator = () -> context.fileIngestIsCancelled(); ProcessTerminator terminator = () -> context.fileIngestIsCancelled();
Lookup extractionContext = Lookups.fixed(imageConfig, terminator); Lookup extractionContext = Lookups.fixed(imageConfig, terminator);

View File

@ -39,9 +39,11 @@ class KeywordSearchSettings {
static final String PROPERTIES_NSRL = NbBundle.getMessage(KeywordSearchSettings.class, "KeywordSearchSettings.propertiesNSRL.text", MODULE_NAME); static final String PROPERTIES_NSRL = NbBundle.getMessage(KeywordSearchSettings.class, "KeywordSearchSettings.propertiesNSRL.text", MODULE_NAME);
static final String PROPERTIES_SCRIPTS = NbBundle.getMessage(KeywordSearchSettings.class, "KeywordSearchSettings.propertiesScripts.text", MODULE_NAME); static final String PROPERTIES_SCRIPTS = NbBundle.getMessage(KeywordSearchSettings.class, "KeywordSearchSettings.propertiesScripts.text", MODULE_NAME);
static final String SHOW_SNIPPETS = "showSnippets"; //NON-NLS static final String SHOW_SNIPPETS = "showSnippets"; //NON-NLS
static final boolean DEFAULT_SHOW_SNIPPETS = true; static final boolean DEFAULT_SHOW_SNIPPETS = true;
static final String OCR_ENABLED = "ocrEnabled"; //NON-NLS static final String OCR_ENABLED = "ocrEnabled"; //NON-NLS
static final String LIMITED_OCR_ENABLED = "limitedOcrEnabled"; //NON-NLS
static final boolean OCR_ENABLED_DEFAULT = false; // NON-NLS static final boolean OCR_ENABLED_DEFAULT = false; // NON-NLS
static final boolean LIMITED_OCR_ENABLED_DEFAULT = false;
private static boolean skipKnown = true; private static boolean skipKnown = true;
private static final Logger logger = Logger.getLogger(KeywordSearchSettings.class.getName()); private static final Logger logger = Logger.getLogger(KeywordSearchSettings.class.getName());
private static UpdateFrequency UpdateFreq = UpdateFrequency.DEFAULT; private static UpdateFrequency UpdateFreq = UpdateFrequency.DEFAULT;
@ -130,19 +132,19 @@ class KeywordSearchSettings {
stringExtractOptions.put(key, val); stringExtractOptions.put(key, val);
ModuleSettings.setConfigSetting(PROPERTIES_OPTIONS, key, val); ModuleSettings.setConfigSetting(PROPERTIES_OPTIONS, key, val);
} }
/** /**
* Save OCR setting to permanent storage * Save OCR setting to permanent storage
* *
* @param enabled Is OCR enabled? * @param enabled Is OCR enabled?
*/ */
static void setOcrOption(boolean enabled) { static void setOcrOption(boolean enabled) {
ModuleSettings.setConfigSetting(PROPERTIES_OPTIONS, OCR_ENABLED, (enabled ? "true" : "false")); //NON-NLS ModuleSettings.setConfigSetting(PROPERTIES_OPTIONS, OCR_ENABLED, (enabled ? "true" : "false")); //NON-NLS
} }
/** /**
* Get OCR setting from permanent storage * Get OCR setting from permanent storage
* *
* @return Is OCR enabled? * @return Is OCR enabled?
*/ */
static boolean getOcrOption() { static boolean getOcrOption() {
@ -152,7 +154,7 @@ class KeywordSearchSettings {
return OCR_ENABLED_DEFAULT; return OCR_ENABLED_DEFAULT;
} }
} }
static void setShowSnippets(boolean showSnippets) { static void setShowSnippets(boolean showSnippets) {
ModuleSettings.setConfigSetting(PROPERTIES_OPTIONS, SHOW_SNIPPETS, (showSnippets ? "true" : "false")); //NON-NLS ModuleSettings.setConfigSetting(PROPERTIES_OPTIONS, SHOW_SNIPPETS, (showSnippets ? "true" : "false")); //NON-NLS
} }
@ -248,11 +250,41 @@ class KeywordSearchSettings {
if (!ModuleSettings.settingExists(KeywordSearchSettings.PROPERTIES_OPTIONS, OCR_ENABLED)) { if (!ModuleSettings.settingExists(KeywordSearchSettings.PROPERTIES_OPTIONS, OCR_ENABLED)) {
logger.log(Level.INFO, "No configuration for OCR found, generating defaults..."); //NON-NLS logger.log(Level.INFO, "No configuration for OCR found, generating defaults..."); //NON-NLS
KeywordSearchSettings.setOcrOption(OCR_ENABLED_DEFAULT); KeywordSearchSettings.setOcrOption(OCR_ENABLED_DEFAULT);
} }
//setting OCR default (disabled by default)
if (!ModuleSettings.settingExists(KeywordSearchSettings.PROPERTIES_OPTIONS, LIMITED_OCR_ENABLED)) {
logger.log(Level.INFO, "No configuration for OCR found, generating defaults..."); //NON-NLS
KeywordSearchSettings.setLimitedOcrOption(LIMITED_OCR_ENABLED_DEFAULT);
}
//setting default Latin-1 Script //setting default Latin-1 Script
if (!ModuleSettings.settingExists(KeywordSearchSettings.PROPERTIES_SCRIPTS, SCRIPT.LATIN_1.name())) { if (!ModuleSettings.settingExists(KeywordSearchSettings.PROPERTIES_SCRIPTS, SCRIPT.LATIN_1.name())) {
logger.log(Level.INFO, "No configuration for Scripts found, generating defaults..."); //NON-NLS logger.log(Level.INFO, "No configuration for Scripts found, generating defaults..."); //NON-NLS
ModuleSettings.setConfigSetting(KeywordSearchSettings.PROPERTIES_SCRIPTS, SCRIPT.LATIN_1.name(), Boolean.toString(true)); ModuleSettings.setConfigSetting(KeywordSearchSettings.PROPERTIES_SCRIPTS, SCRIPT.LATIN_1.name(), Boolean.toString(true));
} }
} }
/**
* Enables the limiting OCR to be run on larger images and images which were
* extracted from documents.
*
* @param enabled Flag indicating if OCR is enabled.
*/
static void setLimitedOcrOption(boolean enabled) {
ModuleSettings.setConfigSetting(PROPERTIES_OPTIONS, LIMITED_OCR_ENABLED, (enabled ? "true" : "false")); //NON-NLS
}
/**
* Gets the limited OCR flag to indicate if OCR should be limited to larger
* images and images which were extracted from documents.
*
* @return Flag indicating if limited OCR is enabled. True if OCR should be
* limited, false otherwise..
*/
static boolean getLimitedOcrOption() {
if (ModuleSettings.settingExists(PROPERTIES_OPTIONS, LIMITED_OCR_ENABLED)) {
return ModuleSettings.getConfigSetting(PROPERTIES_OPTIONS, LIMITED_OCR_ENABLED).equals("true"); //NON-NLS
} else {
return LIMITED_OCR_ENABLED_DEFAULT;
}
}
} }

View File

@ -1,3 +1,38 @@
---------------- VERSION 4.19.0 --------------
Data Source Management:
- To make managing big cases easier, all data sources are now associated with a host that can be specified in the “Add Data Source” wizard.
- Hosts can be grouped by “person”, which is simply a name of the owner.
- The main tree viewer can be configured to group by person and host.
OS Accounts:
- Operating System (OS) accounts and realms are their own data types and not generic artifacts.
- OS Accounts are created for Windows accounts found in the registry. Domain-scoped realms are not fully detected yet.
- NTFS files are associated with OS Accounts by SID.
- The Recent Activity module associates artifacts with OS Accounts based on SID or path of database. Other modules still need to be updated.
- OS accounts appear in a dedicated sub-tree of the main tree view and their properties can be viewed in the results view.
- A new content viewer in the lower right area of the main window was built to display OS account data for the item selected in the result view.
Discovery UI:
- Domain categorization and account types are displayed in Domain Discovery results.
- The Domain Discovery results view more explicitly shows when a downloaded file no longer exists.
- Check boxes are now used to select search options instead of shift-based multi-select.
Ingest Modules:
- File metadata updates are batched up before being saved to the case database for better performance.
- Parsing of iLEAPP and aLEAPP output was expanded to create communication relationships which can be displayed in the Communications UI.
- EML email parsing handles EML messages that are attachments (and have their own attachments).
- Domain categorization within Recent Activity can be customized by user-defined rules that can be imported and exported.
Miscellaneous:
- A “Reset Windows” feature was created to help redock windows.
- A case-insensitive wordlist of all words in the keyword search index can be exported as a text document.
- Information from the Data Source Summary panels can be exported as an Excel spreadsheet.
- More artifacts are added to the timeline and artifacts with multiple time-based attributes are mapped to multiple timeline events.
- The Auto Ingest Dashboard is resizable.
- Added option to only perform optical character recognition on certain file types.
- Heap dumps can be saved to a custom location.
- Assorted bug fixes are included.
---------------- VERSION 4.18.0 -------------- ---------------- VERSION 4.18.0 --------------
Keyword Search: Keyword Search:
- A major upgrade from Solr 4 to Solr 8.6.3. Single user cases continue to use the embedded server. - A major upgrade from Solr 4 to Solr 8.6.3. Single user cases continue to use the embedded server.

View File

@ -13,7 +13,6 @@ ChromeCacheExtractor.progressMsg={0}: Extracting cache entry {1} of {2} entries
DataSourceUsage_AndroidMedia=Android Media Card DataSourceUsage_AndroidMedia=Android Media Card
DataSourceUsage_DJU_Drone_DAT=DJI Internal SD Card DataSourceUsage_DJU_Drone_DAT=DJI Internal SD Card
DataSourceUsage_FlashDrive=Flash Drive DataSourceUsage_FlashDrive=Flash Drive
# {0} - OS name
DataSourceUsageAnalyzer.customVolume.label=OS Drive ({0}) DataSourceUsageAnalyzer.customVolume.label=OS Drive ({0})
DataSourceUsageAnalyzer.parentModuleName=Recent Activity DataSourceUsageAnalyzer.parentModuleName=Recent Activity
DomainCategoryRunner_moduleName_text=DomainCategoryRunner DomainCategoryRunner_moduleName_text=DomainCategoryRunner

View File

@ -143,11 +143,27 @@ abstract class Extract {
* @return The newly created artifact. * @return The newly created artifact.
*/ */
BlackboardArtifact createArtifactWithAttributes(BlackboardArtifact.ARTIFACT_TYPE type, Content content, Collection<BlackboardAttribute> attributes) throws TskCoreException { BlackboardArtifact createArtifactWithAttributes(BlackboardArtifact.ARTIFACT_TYPE type, Content content, Collection<BlackboardAttribute> attributes) throws TskCoreException {
Optional<OsAccount> optional = getOsAccount(content); return createArtifactWithAttributes(new BlackboardArtifact.Type(type), content, attributes);
if (optional.isPresent() && type.getCategory() == BlackboardArtifact.Category.DATA_ARTIFACT) { }
return content.newDataArtifact(new BlackboardArtifact.Type(type), attributes, optional.get());
/**
* Generic method for creating artifacts.
*
* @param type The type of artifact.
* @param content The file the artifact originated from.
* @param attributes A list of the attributes to associate with the
* artifact.
*
* @return The newly created artifact.
*
* @throws TskCoreException
*/
BlackboardArtifact createArtifactWithAttributes(BlackboardArtifact.Type type, Content content, Collection<BlackboardAttribute> attributes) throws TskCoreException {
Optional<OsAccount> optional = getOsAccount(content);
if (optional.isPresent() && type.getCategory() == BlackboardArtifact.Category.DATA_ARTIFACT) {
return content.newDataArtifact(type, attributes, optional.get());
} else { } else {
BlackboardArtifact bbart = content.newArtifact(type); BlackboardArtifact bbart = content.newArtifact(type.getTypeID());
bbart.addAttributes(attributes); bbart.addAttributes(attributes);
return bbart; return bbart;
} }

View File

@ -441,7 +441,7 @@ final class ExtractRecycleBin extends Extract {
attributes.add(new BlackboardAttribute(TSK_PATH, getName(), fileName)); attributes.add(new BlackboardAttribute(TSK_PATH, getName(), fileName));
attributes.add(new BlackboardAttribute(TSK_DATETIME_DELETED, getName(), dateTime)); attributes.add(new BlackboardAttribute(TSK_DATETIME_DELETED, getName(), dateTime));
attributes.add(new BlackboardAttribute(TSK_USER_NAME, getName(), userName == null || userName.isEmpty() ? "" : userName)); attributes.add(new BlackboardAttribute(TSK_USER_NAME, getName(), userName == null || userName.isEmpty() ? "" : userName));
return createArtifactWithAttributes(BlackboardArtifact.ARTIFACT_TYPE.fromID(type.getTypeID()), rFile, attributes); return createArtifactWithAttributes(type, rFile, attributes);
} }
/** /**

View File

@ -93,10 +93,11 @@ import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.Host; import org.sleuthkit.datamodel.Host;
import org.sleuthkit.datamodel.HostManager; import org.sleuthkit.datamodel.HostManager;
import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.OsAccount;
import org.sleuthkit.datamodel.OsAccountAttribute; import org.sleuthkit.datamodel.OsAccount.OsAccountAttribute;
import org.sleuthkit.datamodel.OsAccountInstance; import org.sleuthkit.datamodel.OsAccountInstance;
import org.sleuthkit.datamodel.OsAccountManager; import org.sleuthkit.datamodel.OsAccountManager;
import org.sleuthkit.datamodel.OsAccountManager.NotUserSIDException; import org.sleuthkit.datamodel.OsAccountManager.NotUserSIDException;
import org.sleuthkit.datamodel.OsAccountManager.OsAccountUpdateResult;
import org.sleuthkit.datamodel.OsAccountRealm; import org.sleuthkit.datamodel.OsAccountRealm;
import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException; import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException;
import org.sleuthkit.datamodel.Report; import org.sleuthkit.datamodel.Report;
@ -1079,7 +1080,7 @@ class ExtractRegistry extends Extract {
// New OsAccount Code // New OsAccount Code
OsAccountManager accountMgr = tskCase.getOsAccountManager(); OsAccountManager accountMgr = tskCase.getOsAccountManager();
HostManager hostMrg = tskCase.getHostManager(); HostManager hostMrg = tskCase.getHostManager();
Host host = hostMrg.getHost((DataSource)dataSource); Host host = hostMrg.getHostByDataSource((DataSource)dataSource);
List<OsAccount> existingAccounts = accountMgr.getOsAccounts(host); List<OsAccount> existingAccounts = accountMgr.getOsAccounts(host);
for(OsAccount osAccount: existingAccounts) { for(OsAccount osAccount: existingAccounts) {
@ -1097,8 +1098,8 @@ class ExtractRegistry extends Extract {
//add remaining userinfos as accounts; //add remaining userinfos as accounts;
for (Map<String, String> userInfo : userInfoMap.values()) { for (Map<String, String> userInfo : userInfoMap.values()) {
OsAccount osAccount = accountMgr.createWindowsOsAccount(userInfo.get(SID_KEY), null, null, host, OsAccountRealm.RealmScope.UNKNOWN); OsAccount osAccount = accountMgr.newWindowsOsAccount(userInfo.get(SID_KEY), null, null, host, OsAccountRealm.RealmScope.UNKNOWN);
accountMgr.createOsAccountInstance(osAccount, (DataSource)dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED); accountMgr.newOsAccountInstance(osAccount, (DataSource)dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED);
updateOsAccount(osAccount, userInfo, groupMap.get(userInfo.get(SID_KEY)), regAbstractFile); updateOsAccount(osAccount, userInfo, groupMap.get(userInfo.get(SID_KEY)), regAbstractFile);
} }
@ -1751,7 +1752,6 @@ class ExtractRegistry extends Extract {
try { try {
for (ShellBag bag : shellbags) { for (ShellBag bag : shellbags) {
Collection<BlackboardAttribute> attributes = new ArrayList<>(); Collection<BlackboardAttribute> attributes = new ArrayList<>();
BlackboardArtifact artifact = regFile.newArtifact(getShellBagArtifact().getTypeID());
attributes.add(new BlackboardAttribute(TSK_PATH, getName(), bag.getResource())); attributes.add(new BlackboardAttribute(TSK_PATH, getName(), bag.getResource()));
attributes.add(new BlackboardAttribute(getKeyAttribute(), getName(), bag.getKey())); attributes.add(new BlackboardAttribute(getKeyAttribute(), getName(), bag.getKey()));
@ -1776,9 +1776,7 @@ class ExtractRegistry extends Extract {
attributes.add(new BlackboardAttribute(TSK_DATETIME_ACCESSED, getName(), time)); attributes.add(new BlackboardAttribute(TSK_DATETIME_ACCESSED, getName(), time));
} }
artifact.addAttributes(attributes); artifacts.add(createArtifactWithAttributes(getShellBagArtifact(), regFile, attributes));
artifacts.add(artifact);
} }
} finally { } finally {
if(!context.dataSourceIngestIsCancelled()) { if(!context.dataSourceIngestIsCancelled()) {
@ -1967,17 +1965,18 @@ class ExtractRegistry extends Extract {
private void createOrUpdateOsAccount(AbstractFile file, String sid, String userName, String homeDir) throws TskCoreException, TskDataException, NotUserSIDException { private void createOrUpdateOsAccount(AbstractFile file, String sid, String userName, String homeDir) throws TskCoreException, TskDataException, NotUserSIDException {
OsAccountManager accountMgr = tskCase.getOsAccountManager(); OsAccountManager accountMgr = tskCase.getOsAccountManager();
HostManager hostMrg = tskCase.getHostManager(); HostManager hostMrg = tskCase.getHostManager();
Host host = hostMrg.getHost((DataSource)dataSource); Host host = hostMrg.getHostByDataSource((DataSource)dataSource);
Optional<OsAccount> optional = accountMgr.getWindowsOsAccount(sid, null, null, host); Optional<OsAccount> optional = accountMgr.getWindowsOsAccount(sid, null, null, host);
OsAccount osAccount; OsAccount osAccount;
if (!optional.isPresent()) { if (!optional.isPresent()) {
osAccount = accountMgr.createWindowsOsAccount(sid, userName != null && userName.isEmpty() ? null : userName, null, host, OsAccountRealm.RealmScope.UNKNOWN); osAccount = accountMgr.newWindowsOsAccount(sid, userName != null && userName.isEmpty() ? null : userName, null, host, OsAccountRealm.RealmScope.UNKNOWN);
accountMgr.createOsAccountInstance(osAccount, (DataSource)dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED); accountMgr.newOsAccountInstance(osAccount, (DataSource)dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED);
} else { } else {
osAccount = optional.get(); osAccount = optional.get();
if (userName != null && !userName.isEmpty()) { if (userName != null && !userName.isEmpty()) {
osAccount.setLoginName(userName); OsAccountUpdateResult updateResult= accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, userName, null, host);
osAccount = updateResult.getUpdatedAccount().orElse(osAccount);
} }
} }
@ -1986,10 +1985,9 @@ class ExtractRegistry extends Extract {
String dir = homeDir.replaceFirst("^(%\\w*%)", ""); String dir = homeDir.replaceFirst("^(%\\w*%)", "");
dir = dir.replace("\\", "/"); dir = dir.replace("\\", "/");
attributes.add(createOsAccountAttribute(TSK_HOME_DIR, dir, osAccount, host, file)); attributes.add(createOsAccountAttribute(TSK_HOME_DIR, dir, osAccount, host, file));
accountMgr.addOsAccountAttributes(osAccount, attributes); accountMgr.addExtendedOsAccountAttributes(osAccount, attributes);
} }
accountMgr.updateOsAccount(osAccount);
} }
/** /**
@ -2040,7 +2038,7 @@ class ExtractRegistry extends Extract {
* @throws TskDataException * @throws TskDataException
* @throws TskCoreException * @throws TskCoreException
*/ */
private void updateOsAccount(OsAccount osAccount, Map<String, String> userInfo, List<String> groupList, AbstractFile regFile) throws TskDataException, TskCoreException { private void updateOsAccount(OsAccount osAccount, Map<String, String> userInfo, List<String> groupList, AbstractFile regFile) throws TskDataException, TskCoreException, NotUserSIDException {
Host host = ((DataSource)dataSource).getHost(); Host host = ((DataSource)dataSource).getHost();
SimpleDateFormat regRipperTimeFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy 'Z'", US); SimpleDateFormat regRipperTimeFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy 'Z'", US);
@ -2048,12 +2046,11 @@ class ExtractRegistry extends Extract {
List<OsAccountAttribute> attributes = new ArrayList<>(); List<OsAccountAttribute> attributes = new ArrayList<>();
Long creationTime = null;
String value = userInfo.get(ACCOUNT_CREATED_KEY); String value = userInfo.get(ACCOUNT_CREATED_KEY);
if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) { if (value != null && !value.isEmpty() && !value.equals(NEVER_DATE)) {
Long time = parseRegRipTime(value); creationTime = parseRegRipTime(value);
if (time != null) {
osAccount.setCreationTime(time);
}
} }
value = userInfo.get(LAST_LOGIN_KEY); value = userInfo.get(LAST_LOGIN_KEY);
@ -2066,9 +2063,10 @@ class ExtractRegistry extends Extract {
} }
} }
String loginName = null;
value = userInfo.get(USERNAME_KEY); value = userInfo.get(USERNAME_KEY);
if (value != null && !value.isEmpty()) { if (value != null && !value.isEmpty()) {
osAccount.setLoginName(value); loginName = value;
} }
value = userInfo.get(LOGIN_COUNT_KEY); value = userInfo.get(LOGIN_COUNT_KEY);
@ -2102,13 +2100,14 @@ class ExtractRegistry extends Extract {
} }
// FULL_NAME_KEY and NAME_KEY appear to be the same value. // FULL_NAME_KEY and NAME_KEY appear to be the same value.
String fullName = null;
value = userInfo.get(FULL_NAME_KEY); value = userInfo.get(FULL_NAME_KEY);
if (value != null && !value.isEmpty()) { if (value != null && !value.isEmpty()) {
osAccount.setFullName(value); fullName = value;
} else { } else {
value = userInfo.get(NAME_KEY); value = userInfo.get(NAME_KEY);
if (value != null && !value.isEmpty()) { if (value != null && !value.isEmpty()) {
osAccount.setFullName(value); fullName = value;
} }
} }
@ -2163,9 +2162,17 @@ class ExtractRegistry extends Extract {
groups, osAccount, host, regFile)); groups, osAccount, host, regFile));
} }
// add the attributes to account.
OsAccountManager accountMgr = tskCase.getOsAccountManager(); OsAccountManager accountMgr = tskCase.getOsAccountManager();
accountMgr.addOsAccountAttributes(osAccount, attributes); accountMgr.addExtendedOsAccountAttributes(osAccount, attributes);
accountMgr.updateOsAccount(osAccount);
// update the loginname
accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, loginName, null, host);
// update other standard attributes - fullname, creationdate
accountMgr.updateStandardOsAccountAttributes(osAccount, fullName, null, null, creationTime);
} }
/** /**
@ -2205,7 +2212,7 @@ class ExtractRegistry extends Extract {
* @return Newly created OsACcountAttribute * @return Newly created OsACcountAttribute
*/ */
private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, String value, OsAccount osAccount, Host host, AbstractFile file) { private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, String value, OsAccount osAccount, Host host, AbstractFile file) {
return new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file); return osAccount.new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file);
} }
/** /**
@ -2220,7 +2227,7 @@ class ExtractRegistry extends Extract {
* @return Newly created OsACcountAttribute * @return Newly created OsACcountAttribute
*/ */
private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, Long value, OsAccount osAccount, Host host, AbstractFile file) { private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, Long value, OsAccount osAccount, Host host, AbstractFile file) {
return new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file); return osAccount.new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file);
} }
/** /**
@ -2235,6 +2242,6 @@ class ExtractRegistry extends Extract {
* @return Newly created OsACcountAttribute * @return Newly created OsACcountAttribute
*/ */
private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, Integer value, OsAccount osAccount, Host host, AbstractFile file) { private OsAccountAttribute createOsAccountAttribute(BlackboardAttribute.ATTRIBUTE_TYPE type, Integer value, OsAccount osAccount, Host host, AbstractFile file) {
return new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file); return osAccount.new OsAccountAttribute(new BlackboardAttribute.Type(type), value, osAccount, host, file);
} }
} }

View File

@ -29,7 +29,7 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Host; import org.sleuthkit.datamodel.Host;
import org.sleuthkit.datamodel.OsAccount; import org.sleuthkit.datamodel.OsAccount;
import org.sleuthkit.datamodel.OsAccountAttribute; import org.sleuthkit.datamodel.OsAccount.OsAccountAttribute;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
@ -117,7 +117,7 @@ final class RAOsAccountCache {
List<OsAccount> accounts = tskCase.getOsAccountManager().getOsAccounts(host); List<OsAccount> accounts = tskCase.getOsAccountManager().getOsAccounts(host);
for (OsAccount account : accounts) { for (OsAccount account : accounts) {
List<OsAccountAttribute> attributeList = account.getOsAccountAttributes(); List<OsAccountAttribute> attributeList = account.getExtendedOsAccountAttributes();
for (OsAccountAttribute attribute : attributeList) { for (OsAccountAttribute attribute : attributeList) {
if (attribute.getHostId().isPresent() if (attribute.getHostId().isPresent()

Binary file not shown.

Binary file not shown.