diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 501203babc..282a77c246 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -31,6 +31,7 @@ import org.sleuthkit.autopsy.centralrepository.application.OtherOccurrences; import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepository; +import org.sleuthkit.datamodel.OsAccount; /** * View correlation results from other cases @@ -92,9 +93,10 @@ public final class DataContentViewerOtherCases extends JPanel implements DataCon // Is supported if one of the following is true: // - The central repo is enabled and the node is not null // - The central repo is disabled and the backing file has a valid MD5 hash + // And the node has information which could be correlated on. if (CentralRepository.isEnabled() && node != null) { - return true; - } else if (node != null){ + return OtherOccurrences.getAbstractFileFromNode(node) != null || OtherOccurrences.getBlackboardArtifactFromNode(node) != null || node.getLookup().lookup(OsAccount.class) != null; + } else if (node != null) { AbstractFile file = OtherOccurrences.getAbstractFileFromNode(node); return file != null && file.getSize() > 0 diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java index 112ea3523c..1bc0c5edd5 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java @@ -136,7 +136,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { } private void startTable(StringBuilder sb) { - sb.append(MessageFormat.format("", + sb.append(MessageFormat.format("
", ContentViewerHtmlStyles.getIndentedClassName())); //NON-NLS } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java index f365e8392e..d19cf80b5c 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/analysisresults/AnalysisResultsContentPanel.java @@ -184,7 +184,10 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { Optional.ofNullable(getAnchor(attrs.getAnalysisResult()))); // create a table - Element table = sectionDiv.appendElement("table"); + Element table = sectionDiv.appendElement("table") + .attr("valign", "top") + .attr("align", "left"); + table.attr("class", ContentViewerHtmlStyles.getIndentedClassName()); Element tableBody = table.appendElement("tbody"); @@ -194,11 +197,11 @@ public class AnalysisResultsContentPanel extends javax.swing.JPanel { Element row = tableBody.appendElement("tr"); String keyString = keyVal.getKey() == null ? "" : keyVal.getKey() + ":"; Element keyTd = row.appendElement("td") - .attr("class", ContentViewerHtmlStyles.getTextClassName()); + .attr("class", ContentViewerHtmlStyles.getKeyColumnClassName()); keyTd.appendElement("span") .text(keyString) - .attr("class", ContentViewerHtmlStyles.getKeyColumnClassName()); + .attr("class", ContentViewerHtmlStyles.getTextClassName()); String valueString = keyVal.getValue() == null ? "" : keyVal.getValue(); row.appendElement("td") diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/application/Annotations.java b/Core/src/org/sleuthkit/autopsy/contentviewers/application/Annotations.java index 9651ddc518..67124d1502 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/application/Annotations.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/application/Annotations.java @@ -207,11 +207,10 @@ public class Annotations { Element sourceFileSection = appendSection(parent, Bundle.Annotations_sourceFile_title()); sourceFileSection.attr("class", ContentViewerHtmlStyles.getSpacedSectionClassName()); - + Element sourceFileContainer = sourceFileSection.appendElement("div"); sourceFileContainer.attr("class", ContentViewerHtmlStyles.getIndentedClassName()); - - + boolean sourceFileRendered = renderContent(sourceFileContainer, sourceContent, true); if (!sourceFileRendered) { @@ -239,7 +238,7 @@ public class Annotations { if (CentralRepository.isEnabled()) { List centralRepoComments = getCentralRepositoryData(sourceFile); - boolean crRendered = appendEntries(parent, CR_COMMENTS_CONFIG, centralRepoComments, isSubheader, + boolean crRendered = appendEntries(parent, CR_COMMENTS_CONFIG, centralRepoComments, isSubheader, !contentRendered); contentRendered = contentRendered || crRendered; } @@ -475,13 +474,13 @@ public class Annotations { if (!isFirstSection) { sectionDiv.attr("class", ContentViewerHtmlStyles.getSpacedSectionClassName()); } - + Element sectionContainer = sectionDiv.appendElement("div"); - + if (!isSubsection) { - sectionContainer.attr("class", ContentViewerHtmlStyles.getIndentedClassName()); + sectionContainer.attr("class", ContentViewerHtmlStyles.getIndentedClassName()); } - + appendVerticalEntryTables(sectionContainer, items, config.getAttributes()); return true; } @@ -532,7 +531,10 @@ public class Annotations { * @return The created table. */ private static Element appendTable(Element parent, int columnNumber, List> content, List columnHeaders) { - Element table = parent.appendElement("table"); + Element table = parent.appendElement("table") + .attr("valign", "top") + .attr("align", "left"); + if (columnHeaders != null && !columnHeaders.isEmpty()) { Element header = table.appendElement("thead"); appendRow(header, columnHeaders, columnNumber, true); @@ -559,9 +561,15 @@ public class Annotations { Element row = rowParent.appendElement("tr"); for (int i = 0; i < columnNumber; i++) { Element cell = row.appendElement(cellType); - cell.attr("class", ContentViewerHtmlStyles.getTextClassName()); + + if (i == 0) { + cell.attr("class", ContentViewerHtmlStyles.getKeyColumnClassName()); + } + if (data != null && i < data.size()) { - cell.text(StringUtils.isEmpty(data.get(i)) ? "" : data.get(i)); + cell.appendElement("span") + .attr("class", ContentViewerHtmlStyles.getTextClassName()) + .text(StringUtils.isEmpty(data.get(i)) ? "" : data.get(i)); } } return row; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java index 2b583ff000..e1181f80cd 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/artifactviewers/ContactArtifactViewer.java @@ -65,6 +65,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.CommunicationsManager; import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.InvalidAccountIDException; import org.sleuthkit.datamodel.TskCoreException; /** @@ -624,48 +625,52 @@ public class ContactArtifactViewer extends javax.swing.JPanel implements Artifac protected Map> doInBackground() throws Exception { Map> uniquePersonas = new HashMap<>(); - CommunicationsManager commManager = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager(); List contactAccountsList = commManager.getAccountsRelatedToArtifact(artifact); for (Account account : contactAccountsList) { - if (isCancelled()) { - return new HashMap<>(); - } + try { + if (isCancelled()) { + return new HashMap<>(); + } - // make a list of all unique accounts for this contact - if (!account.getAccountType().equals(Account.Type.DEVICE)) { - Optional optCrAccountType = CentralRepository.getInstance().getAccountTypeByName(account.getAccountType().getTypeName()); - if (optCrAccountType.isPresent()) { - CentralRepoAccount crAccount = CentralRepository.getInstance().getAccount(optCrAccountType.get(), account.getTypeSpecificID()); + // make a list of all unique accounts for this contact + if (!account.getAccountType().equals(Account.Type.DEVICE)) { + Optional optCrAccountType = CentralRepository.getInstance().getAccountTypeByName(account.getAccountType().getTypeName()); + if (optCrAccountType.isPresent()) { + CentralRepoAccount crAccount = CentralRepository.getInstance().getAccount(optCrAccountType.get(), account.getTypeSpecificID()); - if (crAccount != null && uniqueAccountsList.contains(crAccount) == false) { - uniqueAccountsList.add(crAccount); + if (crAccount != null && uniqueAccountsList.contains(crAccount) == false) { + uniqueAccountsList.add(crAccount); + } } } - } - Collection personaAccounts = PersonaAccount.getPersonaAccountsForAccount(account); - if (personaAccounts != null && !personaAccounts.isEmpty()) { - // get personas for the account - Collection personas - = personaAccounts - .stream() - .map(PersonaAccount::getPersona) - .collect(Collectors.toList()); + Collection personaAccounts = PersonaAccount.getPersonaAccountsForAccount(account); + if (personaAccounts != null && !personaAccounts.isEmpty()) { + // get personas for the account + Collection personas + = personaAccounts + .stream() + .map(PersonaAccount::getPersona) + .collect(Collectors.toList()); - // make a list of unique personas, along with all their accounts - for (Persona persona : personas) { - if (uniquePersonas.containsKey(persona) == false) { - Collection accounts = persona.getPersonaAccounts() - .stream() - .map(PersonaAccount::getAccount) - .collect(Collectors.toList()); + // make a list of unique personas, along with all their accounts + for (Persona persona : personas) { + if (uniquePersonas.containsKey(persona) == false) { + Collection accounts = persona.getPersonaAccounts() + .stream() + .map(PersonaAccount::getAccount) + .collect(Collectors.toList()); - ArrayList personaAccountsList = new ArrayList<>(accounts); - uniquePersonas.put(persona, personaAccountsList); + ArrayList personaAccountsList = new ArrayList<>(accounts); + uniquePersonas.put(persona, personaAccountsList); + } } } + } catch (InvalidAccountIDException ex) { + // Do nothing, the account has an identifier that not an + // acceptable format for the cr. } } diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java index 17632dc802..6321f5c78c 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/layout/ContentViewerHtmlStyles.java @@ -65,7 +65,7 @@ public class ContentViewerHtmlStyles { INDENTED_CLASSNAME, pxToPt(ContentViewerDefaults.getSectionIndent())) + String.format(" .%s { padding-top: %dpt } ", SPACED_SECTION_CLASSNAME, pxToPt(ContentViewerDefaults.getSectionSpacing())) - + String.format(" .%s { padding-right: %dpt } ", + + String.format(" .%s { padding-right: %dpt; white-space: nowrap; } ", KEY_COLUMN_TD_CLASSNAME, pxToPt(ContentViewerDefaults.getColumnSpacing())); private static final StyleSheet STYLE_SHEET = new StyleSheet(); diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java index 3d4a55447a..62ca12e217 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java @@ -1258,7 +1258,7 @@ public class CentralRepoDatamodelTest extends TestCase { // We expect 11 total - 10 default and the custom one made earlier // Note: this test will need to be updated based on the current default items defined in the correlation_types table - assertTrue("getDefinedCorrelationTypes returned " + types.size() + " entries - expected 28", types.size() == 28); + assertTrue("getDefinedCorrelationTypes returned " + types.size() + " entries - expected 30", types.size() == 30); } catch (CentralRepoException ex) { Exceptions.printStackTrace(ex); Assert.fail(ex.getMessage()); diff --git a/docs/doxygen-user/auto_ingest_setup.dox b/docs/doxygen-user/auto_ingest_setup.dox index 3e09b11c80..31f0423560 100644 --- a/docs/doxygen-user/auto_ingest_setup.dox +++ b/docs/doxygen-user/auto_ingest_setup.dox @@ -44,6 +44,8 @@ The "Advanced Settings" button will bring up the automated ingest job settings. \image html AutoIngest/advanced_settings.png +The Automated Ingest Pause Setting section lets you configure a weekly time period during which ingest will not run. This is useful if any of your network services has regularly scheduled downtime. Note that ingest isn't immediately stopped at the given "Start Time" - it will run until the current file is processed or the current ingest module is complete. For this reason, we suggest using a lead time of two hours before your system will go down. For example, if the network is not accessible from 4:00 PM to 5:00 PM every Sunday, you should set the start time to 14:00 and the duration to 3 hours (to cover the lead time and the down time). + The Automated Ingest Job Settings section contains the following options:
System synchronization wait time
diff --git a/docs/doxygen-user/images/AutoIngest/advanced_settings.png b/docs/doxygen-user/images/AutoIngest/advanced_settings.png index 8dd88696d3..f93ca9bd00 100644 Binary files a/docs/doxygen-user/images/AutoIngest/advanced_settings.png and b/docs/doxygen-user/images/AutoIngest/advanced_settings.png differ