diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.java index 4ab37d01b5..07eaf84104 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardSelectHostVisual.java @@ -166,7 +166,7 @@ class AddImageWizardSelectHostVisual extends javax.swing.JPanel { if (specifyNewHostRadio.isSelected() && StringUtils.isNotEmpty(specifyNewHostTextField.getText())) { String newHostName = specifyNewHostTextField.getText(); try { - return Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().createHost(newHostName); + return Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().newHost(newHostName); } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.WARNING, String.format("Unable to create host '%s'.", newHostName), ex); return null; @@ -186,7 +186,7 @@ class AddImageWizardSelectHostVisual extends javax.swing.JPanel { */ private void loadHostData() { try { - Collection hosts = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHosts(); + Collection hosts = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getAllHosts(); sanitizedHostSet = HostNameValidator.getSanitizedHostNames(hosts); Vector hostListItems = hosts.stream() diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/events/HostsEvent.java b/Core/src/org/sleuthkit/autopsy/casemodule/events/HostsEvent.java index f37a159125..efa60c8b47 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/events/HostsEvent.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/events/HostsEvent.java @@ -76,7 +76,7 @@ public class HostsEvent extends TskDataModelChangeEvent { continue; } - Optional thisHostOpt = hostManager.getHost(id); + Optional thisHostOpt = hostManager.getHostById(id); thisHostOpt.ifPresent((h) -> toRet.add(h)); } } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/osaccount/OsAccountDataPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/osaccount/OsAccountDataPanel.java index 539f98d896..9c5ae67fa1 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/osaccount/OsAccountDataPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/osaccount/OsAccountDataPanel.java @@ -45,7 +45,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.Host; 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.OsAccountManager; import org.sleuthkit.datamodel.OsAccountRealm; @@ -392,10 +392,10 @@ public class OsAccountDataPanel extends JPanel { account = osAccountManager.getOsAccountByObjectId(accountId); } - OsAccountRealm realm = skCase.getOsAccountRealmManager().getRealmById(account.getRealmId()); + OsAccountRealm realm = skCase.getOsAccountRealmManager().getRealmByRealmId(account.getRealmId()); List hosts = osAccountManager.getHosts(account); - List attributeList = account.getOsAccountAttributes(); + List attributeList = account.getExtendedOsAccountAttributes(); if (attributeList != null) { if (hosts != null) { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java index 5bcd68a03b..93378c6e19 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java @@ -24,6 +24,7 @@ import java.util.Map; import java.util.TreeMap; import java.util.logging.Level; import javax.swing.BorderFactory; +import javax.swing.ImageIcon; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UIManager.LookAndFeelInfo; @@ -75,6 +76,16 @@ public class Installer extends ModuleInstall { } 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 setUnixLookAndFeel(); setModuleSettings("false"); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java index c909ddaad3..22b340d5f1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyTreeChildFactory.java @@ -115,7 +115,7 @@ public final class AutopsyTreeChildFactory extends ChildFactory.Detachable toPopulate) { try { - Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHosts().stream() + Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getAllHosts().stream() .map(HostDataSources::new) .sorted() .forEach(toPopulate::add); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index 674568dd3e..58becb183c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -32,6 +32,7 @@ import java.util.Observable; import java.util.Observer; import java.util.Set; import java.util.logging.Level; +import org.apache.commons.lang3.tuple.Pair; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; @@ -77,7 +78,7 @@ public class EmailExtracted implements AutopsyVisitableItem { */ public static final Map parsePath(String path) { Map 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) { parsed.put(MAIL_ACCOUNT, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultAcct.text")); parsed.put(MAIL_FOLDER, NbBundle.getMessage(EmailExtracted.class, "EmailExtracted.defaultFolder.text")); @@ -146,55 +147,59 @@ public class EmailExtracted implements AutopsyVisitableItem { } @SuppressWarnings("deprecation") - public void update() { - synchronized (accounts) { - accounts.clear(); - } + public void update() { + // clear cache if no case if (skCase == null) { + synchronized (accounts) { + accounts.clear(); + } 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(); - String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " //NON-NLS - + "FROM blackboard_attributes,blackboard_artifacts WHERE " //NON-NLS - + "attribute_type_id=" + pathAttrId //NON-NLS - + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" //NON-NLS - + " AND blackboard_artifacts.artifact_type_id=" + artId; //NON-NLS - if (filteringDSObjId > 0) { - query += " AND blackboard_artifacts.data_source_obj_id = " + filteringDSObjId; - } - + + String query = "SELECT \n" + + " art.artifact_id AS artifact_id,\n" + + " (SELECT value_text FROM blackboard_attributes attr\n" + + " WHERE attr.artifact_id = art.artifact_id AND attr.attribute_type_id = " + pathAttrId + "\n" + + " LIMIT 1) AS value_text\n" + + "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>> newMapping = new HashMap<>(); + try (CaseDbQuery dbQuery = skCase.executeQuery(query)) { ResultSet resultSet = dbQuery.getResultSet(); - synchronized (accounts) { - while (resultSet.next()) { - final String path = resultSet.getString("value_text"); //NON-NLS - final long artifactId = resultSet.getLong("artifact_id"); //NON-NLS - final Map parsedPath = parsePath(path); - final String account = parsedPath.get(MAIL_ACCOUNT); - final String folder = parsedPath.get(MAIL_FOLDER); - - Map> folders = accounts.get(account); - if (folders == null) { - folders = new LinkedHashMap<>(); - accounts.put(account, folders); - } - List messages = folders.get(folder); - if (messages == null) { - messages = new ArrayList<>(); - folders.put(folder, messages); - } - messages.add(artifactId); - } + while (resultSet.next()) { + Long artifactId = resultSet.getLong("artifact_id"); + Map accountFolderMap = parsePath(resultSet.getString("value_text")); + String account = accountFolderMap.get(MAIL_ACCOUNT); + String folder = accountFolderMap.get(MAIL_FOLDER); + + Map> folders = newMapping.computeIfAbsent(account, (str) -> new LinkedHashMap<>()); + List messages = folders.computeIfAbsent(folder, (str) -> new ArrayList<>()); + messages.add(artifactId); } } catch (TskCoreException | SQLException ex) { logger.log(Level.WARNING, "Cannot initialize email extraction: ", ex); //NON-NLS } + + + synchronized (accounts) { + accounts.clear(); + accounts.putAll(newMapping); + } + setChanged(); notifyObservers(); } } + /** * Mail root node grouping all mail accounts, supports account-> folder diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java index 556b247164..4b2588c6bb 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/OsAccounts.java @@ -146,7 +146,7 @@ public final class OsAccounts implements AutopsyVisitableItem { if (filteringDSObjId == 0) { list.addAll(skCase.getOsAccountManager().getOsAccounts()); } else { - Host host = skCase.getHostManager().getHost(skCase.getDataSource(filteringDSObjId)); + Host host = skCase.getHostManager().getHostByDataSource(skCase.getDataSource(filteringDSObjId)); list.addAll(skCase.getOsAccountManager().getOsAccounts(host)); } } catch (TskCoreException | TskDataException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AssociateNewPersonAction.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AssociateNewPersonAction.java index bea7f7b372..2cb89995c6 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AssociateNewPersonAction.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/AssociateNewPersonAction.java @@ -65,7 +65,7 @@ public class AssociateNewPersonAction extends AbstractAction { try { newPersonName = getAddDialogName(); 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); } } catch (NoCurrentCaseException | TskCoreException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java index 7d4d521b51..6cb4220a7a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/ManageHostsDialog.java @@ -166,7 +166,7 @@ public class ManageHostsDialog extends javax.swing.JDialog { if (newHostName != null) { Long selectedId = null; try { - Host newHost = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().createHost(newHostName); + Host newHost = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().newHost(newHostName); selectedId = newHost == null ? null : newHost.getHostId(); } catch (NoCurrentCaseException | TskCoreException 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) { String newHostName = getAddEditDialogName(selectedHost); if (newHostName != null) { - selectedHost.setName(newHostName); try { - Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().updateHost(selectedHost); + Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().updateHostName(selectedHost, newHostName); } 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); } @@ -322,7 +321,7 @@ public class ManageHostsDialog extends javax.swing.JDialog { Map> hostMapping = new HashMap<>(); try { SleuthkitCase curCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - List hosts = curCase.getHostManager().getHosts(); + List hosts = curCase.getHostManager().getAllHosts(); List dataSources = curCase.getDataSources(); if (dataSources != null) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/MergeHostMenuAction.java b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/MergeHostMenuAction.java index 8b8ddc3f23..5517687434 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/hosts/MergeHostMenuAction.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/hosts/MergeHostMenuAction.java @@ -67,7 +67,7 @@ public class MergeHostMenuAction extends AbstractAction implements Presenter.Pop // Get a list of all other hosts List otherHosts = Collections.emptyList(); try { - otherHosts = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getHosts(); + otherHosts = Case.getCurrentCaseThrows().getSleuthkitCase().getHostManager().getAllHosts(); otherHosts.remove(sourceHost); } catch (NoCurrentCaseException | TskCoreException ex) { logger.log(Level.WARNING, "Error getting hosts for case.", ex); diff --git a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java index f2a5f688a9..683b2e6c95 100644 --- a/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java +++ b/Core/src/org/sleuthkit/autopsy/discovery/ui/DomainFilterPanel.java @@ -18,9 +18,6 @@ */ 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.discovery.search.DiscoveryAttributes; import org.sleuthkit.autopsy.discovery.search.ResultsSorter; @@ -46,14 +43,7 @@ public class DomainFilterPanel extends AbstractFiltersPanel { addFilter(new KnownAccountTypeFilterPanel(), false, null, 1); addFilter(new ArtifactTypeFilterPanel(), false, null, 1); addFilter(new DateFilterPanel(), false, null, 1); - List defaultFrequencies = null; - 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); + addFilter(new PastOccurrencesFilterPanel(TYPE), false, null, 0); addPanelsToScrollPane(domainFiltersSplitPane); setLastGroupingAttributeType(DiscoveryAttributes.GroupingAttributeType.LAST_ACTIVITY_DATE); setLastSortingMethod(ResultsSorter.SortingMethod.BY_DOMAIN_NAME); diff --git a/Core/src/org/sleuthkit/autopsy/images/error_32.png b/Core/src/org/sleuthkit/autopsy/images/error_32.png new file mode 100755 index 0000000000..50c92f43bf Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/images/error_32.png differ diff --git a/Core/src/org/sleuthkit/autopsy/images/information_32.png b/Core/src/org/sleuthkit/autopsy/images/information_32.png new file mode 100755 index 0000000000..c00c1e7dc2 Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/images/information_32.png differ diff --git a/Core/src/org/sleuthkit/autopsy/images/question_32.png b/Core/src/org/sleuthkit/autopsy/images/question_32.png new file mode 100755 index 0000000000..8e0094a8ac Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/images/question_32.png differ diff --git a/Core/src/org/sleuthkit/autopsy/images/warning_32.png b/Core/src/org/sleuthkit/autopsy/images/warning_32.png new file mode 100755 index 0000000000..251c2eb88e Binary files /dev/null and b/Core/src/org/sleuthkit/autopsy/images/warning_32.png differ diff --git a/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/LeappFileProcessor.java b/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/LeappFileProcessor.java index ca2da24cdf..58d2cece31 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/LeappFileProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/LeappFileProcessor.java @@ -77,6 +77,11 @@ import org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper; import org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper.CallMediaType; import org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper.CommunicationDirection; 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.FileAttachment; import org.w3c.dom.Document; @@ -149,23 +154,41 @@ public final class LeappFileProcessor { .build(); private static final Map ACCOUNT_RELATIONSHIPS = ImmutableMap.builder() - .put("Zapya.tsv", "message") + .put("zapya.tsv", "message") .put("sms messages.tsv", "message") .put("mms messages.tsv", "message") - .put("Viber - Messages.tsv", "message") - .put("Viber - Contacts.tsv", "contact") - .put("Viber - Call Logs.tsv", "calllog") - .put("Xender file transfer - Messages.tsv", "message") - .put("Whatsapp - Contacts.tsv", "contact") - .put("Whatsapp - Group Call Logs.tsv", "calllog") - .put("Whatsapp - Single Call Logs.tsv", "calllog") - .put("Whatsapp - Messages Logs.tsv", "message") - .put("Shareit file transfer.tsv", "message") + .put("viber - messages.tsv", "message") + .put("viber - contacts.tsv", "contact") + .put("viber - call logs.tsv", "calllog") + .put("xender file transfer - messages.tsv", "message") + .put("xender file transfer - contacts.tsv", "contact") + .put("whatsapp - contacts.tsv", "contact") + .put("whatsapp - group call logs.tsv", "calllog") + .put("whatsapp - single call logs.tsv", "calllog") + .put("whatsapp - messages logs.tsv", "message") + .put("shareit file transfer.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("IMO - AccountId.tsv", "contact") - .put("IMO - messages.tsv", "message") - + .put("sms - imessage.tsv", "message") + .put("call history.tsv", "calllog") .build(); Blackboard blkBoard; @@ -318,6 +341,10 @@ public final class LeappFileProcessor { List bbartifacts, Content dataSource) throws FileNotFoundException, IOException, IngestModuleException, TskCoreException { + String trackpointSegmentName = null; + GeoTrackPoints pointList = new GeoTrackPoints(); + AbstractFile geoAbstractFile = 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() : "")); return; @@ -348,7 +375,7 @@ public final class LeappFileProcessor { Collection bbattributes = processReadLine(columnItems, columnIndexes, attrList, fileName, lineNum); if (!bbattributes.isEmpty()) { - switch (ACCOUNT_RELATIONSHIPS.getOrDefault(fileName, "norelationship").toLowerCase()) { + switch (ACCOUNT_RELATIONSHIPS.getOrDefault(fileName.toLowerCase(), "norelationship").toLowerCase()) { case "message": createMessageRelationship(bbattributes, dataSource, fileName); break; @@ -358,6 +385,12 @@ public final class LeappFileProcessor { case "calllog": createCalllogRelationship(bbattributes, dataSource, fileName); 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 BlackboardArtifact bbartifact = createArtifactWithAttributes(artifactType.getTypeID(), dataSource, bbattributes); 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 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 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 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 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({ "LeappFileProcessor.cannot.create.message.relationship=Cannot create TSK_MESSAGE Relationship.", }) @@ -380,6 +563,7 @@ public final class LeappFileProcessor { private void createMessageRelationship(Collection bbattributes, Content dataSource, String fileName) throws IngestModuleException { String messageType = null; + String alternateId = null; CommunicationDirection communicationDirection = CommunicationDirection.UNKNOWN; String senderId = null; String receipentId = null; @@ -394,6 +578,7 @@ public final class LeappFileProcessor { String sourceFile = null; MessageAttachments messageAttachments = null; + /******* DISABLE TEMPORARILY************* try { for (BlackboardAttribute bba : bbattributes) { switch (bba.getAttributeType().getTypeName()) { @@ -441,17 +626,28 @@ public final class LeappFileProcessor { case "TSK_SUBJECT": subject = bba.getValueString(); break; + case "TSK_ID": + alternateId = bba.getValueString(); + otherAttributes.add(bba); + break; default: otherAttributes.add(bba); break; } } AbstractFile absFile = findAbstractFile(dataSource, sourceFile); - Account.Type accountType = getAccountType(fileName); + if (absFile == null) { + absFile = (AbstractFile) dataSource; + } + Account.Type accountType = getAccountType(fileName); if ((absFile != null) || (accountType != null)) { CommunicationArtifactsHelper accountArtifact = new CommunicationArtifactsHelper(Case.getCurrentCaseThrows().getSleuthkitCase(), moduleName, absFile, accountType); - BlackboardArtifact messageArtifact = accountArtifact.addMessage(messageType, communicationDirection, senderId, + } else { + accountArtifact = new CommunicationArtifactsHelper(Case.getCurrentCaseThrows().getSleuthkitCase(), + moduleName, absFile, accountType, accountType, alternateId); + } + BlackboardArtifact messageArtifact = accountArtifact.addMessage(messageType, communicationDirection, senderId, receipentId, dateTime, messageStatus, subject, messageText, threadId, otherAttributes); if (!fileAttachments.isEmpty()) { @@ -461,10 +657,13 @@ public final class LeappFileProcessor { } } catch (NoCurrentCaseException | TskCoreException | BlackboardException ex) { throw new IngestModuleException(Bundle.LeappFileProcessor_cannot_create_message_relationship() + ex.getLocalizedMessage(), ex); //NON-NLS - } + }*/ } + @NbBundle.Messages({ + "LeappFileProcessor.cannot.create.contact.relationship=Cannot create TSK_CONTACT Relationship.", + }) private void createContactRelationship(Collection bbattributes, Content dataSource, String fileName) throws IngestModuleException { String alternateId = null; @@ -503,6 +702,7 @@ public final class LeappFileProcessor { break; case "TSK_ID": alternateId = bba.getValueString(); + otherAttributes.add(bba); break; default: otherAttributes.add(bba); @@ -510,8 +710,11 @@ public final class LeappFileProcessor { } } AbstractFile absFile = findAbstractFile(dataSource, sourceFile); + if (absFile == null) { + absFile = (AbstractFile) dataSource; + } Account.Type accountType = getAccountType(fileName); - if ((absFile != null) || (accountType != null)) { + if (accountType != null) { CommunicationArtifactsHelper accountArtifact; if (alternateId == null) { @@ -524,14 +727,18 @@ public final class LeappFileProcessor { BlackboardArtifact messageArtifact = accountArtifact.addContact(contactName, phoneNumber, homePhoneNumber, mobilePhoneNumber, emailAddr, otherAttributes); } } 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 bbattributes, Content dataSource, String fileName) throws IngestModuleException { String callerId = null; + String alternateId = null; List calleeId = Arrays.asList(); CommunicationDirection communicationDirection = CommunicationDirection.UNKNOWN; Long startDateTime = Long.valueOf(0); @@ -570,6 +777,10 @@ public final class LeappFileProcessor { calleeId = Arrays.asList(calleeTempList); } break; + case "TSK_ID": + alternateId = bba.getValueString(); + otherAttributes.add(bba); + break; default: otherAttributes.add(bba); break; @@ -582,14 +793,21 @@ public final class LeappFileProcessor { callerId = null; } AbstractFile absFile = findAbstractFile(dataSource, sourceFile); - Account.Type accountType = getAccountType(fileName); - if ((absFile != null) || (accountType != null)) { - CommunicationArtifactsHelper accountArtifact = new CommunicationArtifactsHelper(Case.getCurrentCaseThrows().getSleuthkitCase(), - moduleName, absFile, accountType); - BlackboardArtifact callLogArtifact = accountArtifact.addCalllog(communicationDirection, callerId, calleeId, startDateTime, endDateTime, mediaType, otherAttributes); + if (absFile == null) { + absFile = (AbstractFile) dataSource; } + 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) { - 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 +824,10 @@ public final class LeappFileProcessor { return Account.Type.IMO; case "imo - messages.tsv": return Account.Type.IMO; + case "textnow - contacts.tsv": + return Account.Type.TEXTNOW; + case "textnow - messages.tsv": + return Account.Type.TEXTNOW; case "mms messages.tsv": return Account.Type.PHONE; case "viber - call logs.tsv": @@ -616,6 +838,8 @@ public final class LeappFileProcessor { return Account.Type.VIBER; case "xender file transfer - messages.tsv": return Account.Type.XENDER; + case "xender file transfer - contacts.tsv": + return Account.Type.XENDER; case "whatsapp - single call logs.tsv": return Account.Type.WHATSAPP; case "whatsapp - messages logs.tsv": @@ -627,9 +851,33 @@ public final class LeappFileProcessor { case "tangomessages messages.tsv": return Account.Type.TANGO; 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: - return null; + return Account.Type.PHONE; } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/aleap-artifact-attribute-reference.xml b/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/aleap-artifact-attribute-reference.xml index 27d3bc7263..3ef61b0025 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/aleap-artifact-attribute-reference.xml +++ b/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/aleap-artifact-attribute-reference.xml @@ -355,15 +355,6 @@ - - @@ -379,8 +370,9 @@ - - + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/ileap-artifact-attribute-reference.xml b/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/ileap-artifact-attribute-reference.xml index 16409f42c7..70725fd0c6 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/ileap-artifact-attribute-reference.xml +++ b/Core/src/org/sleuthkit/autopsy/modules/leappanalyzers/ileap-artifact-attribute-reference.xml @@ -50,9 +50,9 @@ - + - + @@ -101,6 +101,7 @@ + @@ -743,16 +744,14 @@ - diff --git a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java index 56bb8e9133..f8dbebe224 100644 --- a/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/modules/portablecase/PortableCaseReportModule.java @@ -1085,7 +1085,7 @@ public class PortableCaseReportModule implements ReportModule { Host newHost = null; if (content instanceof DataSource) { Host oldHost = ((DataSource)content).getHost(); - newHost = portableSkCase.getHostManager().createHost(oldHost.getName()); + newHost = portableSkCase.getHostManager().newHost(oldHost.getName()); } CaseDbTransaction trans = portableSkCase.beginTransaction(); diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java index 948aae9217..6524c1835d 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/BingTranslator.java @@ -30,6 +30,7 @@ import java.io.IOException; import javax.swing.JPanel; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.texttranslation.TextTranslator; import org.sleuthkit.autopsy.texttranslation.TranslationConfigException; 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 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 final BingTranslatorSettingsPanel settingsPanel; + private BingTranslatorSettingsPanel settingsPanel; private final BingTranslatorSettings settings = new BingTranslatorSettings(); // This sends messages to Microsoft. private final OkHttpClient CLIENT = new OkHttpClient(); @@ -55,11 +56,11 @@ public class BingTranslator implements TextTranslator { * Create a Bing Translator */ 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 + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) public JPanel getSettingsPanel() { + if(settingsPanel == null) { + settingsPanel = new BingTranslatorSettingsPanel(settings.getAuthenticationKey(), settings.getTargetLanguageCode()); + } return settingsPanel; } diff --git a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java index ec74190229..c0820b688c 100644 --- a/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java +++ b/Core/src/org/sleuthkit/autopsy/texttranslation/translators/GoogleTranslator.java @@ -36,6 +36,7 @@ import org.apache.commons.lang3.StringUtils; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.coreutils.EscapeUtil; +import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.texttranslation.TextTranslator; import org.sleuthkit.autopsy.texttranslation.TranslationConfigException; 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()); //See translate method for justification of this limit. private static final int MAX_PAYLOAD_SIZE = 5000; - private final GoogleTranslatorSettingsPanel settingsPanel; + private GoogleTranslatorSettingsPanel settingsPanel; private final GoogleTranslatorSettings settings = new GoogleTranslatorSettings(); private Translate googleTranslate; @@ -59,7 +60,6 @@ public final class GoogleTranslator implements TextTranslator { */ public GoogleTranslator() { // Instantiates a client - settingsPanel = new GoogleTranslatorSettingsPanel(settings.getCredentialPath(), settings.getTargetLanguageCode()); loadTranslator(); } @@ -134,7 +134,11 @@ public final class GoogleTranslator implements TextTranslator { } @Override + @ThreadConfined(type = ThreadConfined.ThreadType.AWT) public JPanel getSettingsPanel() { + if(settingsPanel == null) { + settingsPanel = new GoogleTranslatorSettingsPanel(settings.getCredentialPath(), settings.getTargetLanguageCode()); + } return settingsPanel; } diff --git a/Core/src/org/sleuthkit/autopsy/threadutils/TaskRetryUtil.java b/Core/src/org/sleuthkit/autopsy/threadutils/TaskRetryUtil.java index e00cedab83..79484dddb1 100755 --- a/Core/src/org/sleuthkit/autopsy/threadutils/TaskRetryUtil.java +++ b/Core/src/org/sleuthkit/autopsy/threadutils/TaskRetryUtil.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2020 Basis Technology Corp. + * Copyright 2020-2021 Basis Technology Corp. * Contact: carrier sleuthkit org * * 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 * 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 attempts The defining details for each attempt of the task. * @param executor The scheduled task executor to be used to attempt the @@ -181,6 +181,9 @@ public class TaskRetryUtil { * @throws InterruptedException */ public static T attemptTask(Callable task, List attempts, ScheduledThreadPoolExecutor executor, Terminator terminator, Logger logger, String taskDesc) throws InterruptedException { + /* + * Attempt the task. + */ T result = null; String taskDescForLog = taskDesc != null ? taskDesc : "Task"; int attemptCounter = 0; @@ -195,9 +198,6 @@ public class TaskRetryUtil { break; } 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) { totalTaskRetries.incrementAndGet(); } @@ -222,11 +222,27 @@ public class TaskRetryUtil { } ++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 (terminator == null || !terminator.stopTaskAttempts()) { totalFailedTasks.incrementAndGet(); } } + return result; } diff --git a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesDataModel.java b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesDataModel.java index 067a5fceea..5b2932b718 100644 --- a/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesDataModel.java +++ b/Core/src/org/sleuthkit/autopsy/url/analytics/domaincategorization/WebCategoriesDataModel.java @@ -45,7 +45,6 @@ import java.util.stream.Stream; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.openide.modules.InstalledFileLocator; -import org.sleuthkit.autopsy.coreutils.NetworkUtils; import org.sleuthkit.autopsy.url.analytics.DomainCategory; /** @@ -396,7 +395,7 @@ class WebCategoriesDataModel implements AutoCloseable { * @return The list of domain suffixes and their categories. * @throws SQLException */ - List getRecords() throws SQLException { + synchronized List getRecords() throws SQLException { if (!isInitialized()) { initialize(); } @@ -428,7 +427,7 @@ class WebCategoriesDataModel implements AutoCloseable { * @return The found entry or null. * @throws SQLException */ - DomainCategory getRecordBySuffix(String domainSuffix) throws SQLException { + synchronized DomainCategory getRecordBySuffix(String domainSuffix) throws SQLException { if (!isInitialized()) { initialize(); } @@ -529,7 +528,9 @@ class WebCategoriesDataModel implements AutoCloseable { @Override public synchronized void close() throws SQLException { - dbConn.close(); - dbConn = null; + if (dbConn != null) { + dbConn.close(); + dbConn = null; + } } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index b3a25be677..a15fb3b50b 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -973,7 +973,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen * job to be shut down in an orderly fashion. */ void cancelCurrentJob() { - if (State.RUNNING != state) { + if ((State.RUNNING != state) && (State.SHUTTING_DOWN != state)) { return; } synchronized (jobsLock) { @@ -2564,6 +2564,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen synchronized (ingestLock) { // Try each DSP in decreasing order of confidence for (AutoIngestDataSourceProcessor selectedProcessor : validDataSourceProcessors) { + currentJob.setDataSourceProcessor(selectedProcessor); UUID taskId = UUID.randomUUID(); caseForJob.notifyAddingDataSource(taskId); DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId, ingestLock); diff --git a/NEWS.txt b/NEWS.txt index 532aae69fa..d9e2f99b90 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -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 -------------- Keyword Search: - A major upgrade from Solr 4 to Solr 8.6.3. Single user cases continue to use the embedded server. diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED index 547b90ca6a..26181755d0 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED @@ -13,7 +13,6 @@ ChromeCacheExtractor.progressMsg={0}: Extracting cache entry {1} of {2} entries DataSourceUsage_AndroidMedia=Android Media Card DataSourceUsage_DJU_Drone_DAT=DJI Internal SD Card DataSourceUsage_FlashDrive=Flash Drive -# {0} - OS name DataSourceUsageAnalyzer.customVolume.label=OS Drive ({0}) DataSourceUsageAnalyzer.parentModuleName=Recent Activity DomainCategoryRunner_moduleName_text=DomainCategoryRunner diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java index e152a146fa..c2abe0223d 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Extract.java @@ -143,11 +143,27 @@ abstract class Extract { * @return The newly created artifact. */ BlackboardArtifact createArtifactWithAttributes(BlackboardArtifact.ARTIFACT_TYPE type, Content content, Collection attributes) throws TskCoreException { - Optional optional = getOsAccount(content); - if (optional.isPresent() && type.getCategory() == BlackboardArtifact.Category.DATA_ARTIFACT) { - return content.newDataArtifact(new BlackboardArtifact.Type(type), attributes, optional.get()); + return createArtifactWithAttributes(new BlackboardArtifact.Type(type), content, attributes); + } + + /** + * 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 attributes) throws TskCoreException { + Optional optional = getOsAccount(content); + if (optional.isPresent() && type.getCategory() == BlackboardArtifact.Category.DATA_ARTIFACT) { + return content.newDataArtifact(type, attributes, optional.get()); } else { - BlackboardArtifact bbart = content.newArtifact(type); + BlackboardArtifact bbart = content.newArtifact(type.getTypeID()); bbart.addAttributes(attributes); return bbart; } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java index 4478f49278..1ced615661 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRecycleBin.java @@ -441,7 +441,7 @@ final class ExtractRecycleBin extends Extract { attributes.add(new BlackboardAttribute(TSK_PATH, getName(), fileName)); attributes.add(new BlackboardAttribute(TSK_DATETIME_DELETED, getName(), dateTime)); 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); } /** diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index e5e0eefbe8..ad5c1e9ed4 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -93,11 +93,11 @@ import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.Host; import org.sleuthkit.datamodel.HostManager; 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.OsAccountManager; -import org.sleuthkit.datamodel.OsAccountManager.AccountUpdateStatus; import org.sleuthkit.datamodel.OsAccountManager.NotUserSIDException; +import org.sleuthkit.datamodel.OsAccountManager.OsAccountUpdateResult; import org.sleuthkit.datamodel.OsAccountRealm; import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamException; import org.sleuthkit.datamodel.Report; @@ -1080,7 +1080,7 @@ class ExtractRegistry extends Extract { // New OsAccount Code OsAccountManager accountMgr = tskCase.getOsAccountManager(); HostManager hostMrg = tskCase.getHostManager(); - Host host = hostMrg.getHost((DataSource)dataSource); + Host host = hostMrg.getHostByDataSource((DataSource)dataSource); List existingAccounts = accountMgr.getOsAccounts(host); for(OsAccount osAccount: existingAccounts) { @@ -1098,8 +1098,8 @@ class ExtractRegistry extends Extract { //add remaining userinfos as accounts; for (Map userInfo : userInfoMap.values()) { - OsAccount osAccount = accountMgr.createWindowsOsAccount(userInfo.get(SID_KEY), null, null, host, OsAccountRealm.RealmScope.UNKNOWN); - accountMgr.createOsAccountInstance(osAccount, (DataSource)dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED); + OsAccount osAccount = accountMgr.newWindowsOsAccount(userInfo.get(SID_KEY), null, null, host, OsAccountRealm.RealmScope.UNKNOWN); + accountMgr.newOsAccountInstance(osAccount, (DataSource)dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED); updateOsAccount(osAccount, userInfo, groupMap.get(userInfo.get(SID_KEY)), regAbstractFile); } @@ -1752,7 +1752,6 @@ class ExtractRegistry extends Extract { try { for (ShellBag bag : shellbags) { Collection attributes = new ArrayList<>(); - BlackboardArtifact artifact = regFile.newArtifact(getShellBagArtifact().getTypeID()); attributes.add(new BlackboardAttribute(TSK_PATH, getName(), bag.getResource())); attributes.add(new BlackboardAttribute(getKeyAttribute(), getName(), bag.getKey())); @@ -1777,9 +1776,7 @@ class ExtractRegistry extends Extract { attributes.add(new BlackboardAttribute(TSK_DATETIME_ACCESSED, getName(), time)); } - artifact.addAttributes(attributes); - - artifacts.add(artifact); + artifacts.add(createArtifactWithAttributes(getShellBagArtifact(), regFile, attributes)); } } finally { if(!context.dataSourceIngestIsCancelled()) { @@ -1968,18 +1965,18 @@ class ExtractRegistry extends Extract { private void createOrUpdateOsAccount(AbstractFile file, String sid, String userName, String homeDir) throws TskCoreException, TskDataException, NotUserSIDException { OsAccountManager accountMgr = tskCase.getOsAccountManager(); HostManager hostMrg = tskCase.getHostManager(); - Host host = hostMrg.getHost((DataSource)dataSource); + Host host = hostMrg.getHostByDataSource((DataSource)dataSource); Optional optional = accountMgr.getWindowsOsAccount(sid, null, null, host); OsAccount osAccount; if (!optional.isPresent()) { - osAccount = accountMgr.createWindowsOsAccount(sid, userName != null && userName.isEmpty() ? null : userName, null, host, OsAccountRealm.RealmScope.UNKNOWN); - accountMgr.createOsAccountInstance(osAccount, (DataSource)dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED); + osAccount = accountMgr.newWindowsOsAccount(sid, userName != null && userName.isEmpty() ? null : userName, null, host, OsAccountRealm.RealmScope.UNKNOWN); + accountMgr.newOsAccountInstance(osAccount, (DataSource)dataSource, OsAccountInstance.OsAccountInstanceType.LAUNCHED); } else { osAccount = optional.get(); if (userName != null && !userName.isEmpty()) { - AccountUpdateStatus updateStatus = accountMgr.updateWindowsOsAccountCore(osAccount, null, userName, null, host); - osAccount = updateStatus.getUpdatedAccount().orElse(osAccount); + OsAccountUpdateResult updateResult= accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, userName, null, host); + osAccount = updateResult.getUpdatedAccount().orElse(osAccount); } } @@ -1988,7 +1985,7 @@ class ExtractRegistry extends Extract { String dir = homeDir.replaceFirst("^(%\\w*%)", ""); dir = dir.replace("\\", "/"); attributes.add(createOsAccountAttribute(TSK_HOME_DIR, dir, osAccount, host, file)); - accountMgr.addOsAccountAttributes(osAccount, attributes); + accountMgr.addExtendedOsAccountAttributes(osAccount, attributes); } } @@ -2167,13 +2164,13 @@ class ExtractRegistry extends Extract { // add the attributes to account. OsAccountManager accountMgr = tskCase.getOsAccountManager(); - accountMgr.addOsAccountAttributes(osAccount, attributes); + accountMgr.addExtendedOsAccountAttributes(osAccount, attributes); // update the loginname - accountMgr.updateWindowsOsAccountCore(osAccount, null, loginName, null, host); + accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, loginName, null, host); - // update other properties - fullname, creationdate - accountMgr.updateOsAccountProperties(osAccount, fullName, null, null, creationTime); + // update other standard attributes - fullname, creationdate + accountMgr.updateStandardOsAccountAttributes(osAccount, fullName, null, null, creationTime); } @@ -2215,7 +2212,7 @@ class ExtractRegistry extends Extract { * @return Newly created OsACcountAttribute */ 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); } /** @@ -2230,7 +2227,7 @@ class ExtractRegistry extends Extract { * @return Newly created OsACcountAttribute */ 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); } /** @@ -2245,6 +2242,6 @@ class ExtractRegistry extends Extract { * @return Newly created OsACcountAttribute */ 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); } } diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAOsAccountCache.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAOsAccountCache.java index 788f219371..c1206c82f6 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAOsAccountCache.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAOsAccountCache.java @@ -29,7 +29,7 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Host; 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.TskCoreException; @@ -117,7 +117,7 @@ final class RAOsAccountCache { List accounts = tskCase.getOsAccountManager().getOsAccounts(host); for (OsAccount account : accounts) { - List attributeList = account.getOsAccountAttributes(); + List attributeList = account.getExtendedOsAccountAttributes(); for (OsAccountAttribute attribute : attributeList) { if (attribute.getHostId().isPresent() diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index 6e51b879e3..c2df473fe0 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Thu, 01 Apr 2021 23:53:50 -0400 +#Mon, 25 Jan 2021 12:41:22 -0500 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 229347ff54..d519362703 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -#Thu, 01 Apr 2021 23:53:50 -0400 +#Mon, 25 Jan 2021 12:41:22 -0500 CTL_MainWindow_Title=Autopsy 4.18.0 CTL_MainWindow_Title_No_Project=Autopsy 4.18.0 diff --git a/thirdparty/aLeapp/aleapp.exe b/thirdparty/aLeapp/aleapp.exe index 71106090c0..3f47725616 100644 Binary files a/thirdparty/aLeapp/aleapp.exe and b/thirdparty/aLeapp/aleapp.exe differ diff --git a/thirdparty/iLeapp/ileapp.exe b/thirdparty/iLeapp/ileapp.exe index 0456c3c726..f1d395e930 100644 Binary files a/thirdparty/iLeapp/ileapp.exe and b/thirdparty/iLeapp/ileapp.exe differ