From 0f6527fcb434561fc25e8789bc2e7125c8883168 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 24 Sep 2019 13:40:37 -0400 Subject: [PATCH 01/17] Added bulk postArtifact calls --- .../recentactivity/ExtractRegistry.java | 123 +++++++++--------- 1 file changed, 61 insertions(+), 62 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index 628b84ea08..707bd9c337 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -431,6 +431,7 @@ class ExtractRegistry extends Extract { */ private boolean parseAutopsyPluginOutput(String regFilePath, AbstractFile regFile) { FileInputStream fstream = null; + List newArtifacts = new ArrayList<>(); try { // Read the file in and create a Document and elements File regfile = new File(regFilePath); @@ -447,7 +448,7 @@ class ExtractRegistry extends Extract { String stringdoc = startdoc + result + enddoc; DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = builder.parse(new InputSource(new StringReader(stringdoc))); - + // cycle through the elements in the doc Element oroot = doc.getDocumentElement(); NodeList children = oroot.getChildNodes(); @@ -538,7 +539,7 @@ class ExtractRegistry extends Extract { String Tempdate = installtime.toString(); installtime = Long.valueOf(Tempdate) / MS_IN_SEC; } catch (ParseException e) { - logger.log(Level.SEVERE, "RegRipper::Conversion on DateTime -> ", e); //NON-NLS + logger.log(Level.WARNING, "RegRipper::Conversion on DateTime -> ", e); //NON-NLS } } break; @@ -564,8 +565,7 @@ class ExtractRegistry extends Extract { BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_OS_INFO); bbart.addAttributes(bbattributes); - // index the artifact for keyword search - postArtifact(bbart); + newArtifacts.add(bbart); } else { results.get(0).addAttributes(bbattributes); } @@ -615,8 +615,7 @@ class ExtractRegistry extends Extract { BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_OS_INFO); bbart.addAttributes(bbattributes); - // index the artifact for keyword search - postArtifact(bbart); + newArtifacts.add(bbart); } else { results.get(0).addAttributes(bbattributes); } @@ -654,13 +653,12 @@ class ExtractRegistry extends Extract { BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_OS_INFO); bbart.addAttributes(bbattributes); - // index the artifact for keyword search - postArtifact(bbart); + newArtifacts.add(bbart); } else { results.get(0).addAttributes(bbattributes); } } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error adding os info artifact to blackboard."); //NON-NLS + logger.log(Level.WARNING, "Error adding os info artifact to blackboard.", ex); //NON-NLS } break; default: @@ -706,8 +704,7 @@ class ExtractRegistry extends Extract { bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_ID, parentModuleName, value)); bbart.addAttributes(bbattributes); - // index the artifact for keyword search - postArtifact(bbart); + newArtifacts.add(bbart); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding device attached artifact to blackboard.", ex); //NON-NLS } @@ -730,10 +727,9 @@ class ExtractRegistry extends Extract { BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_INSTALLED_PROG); bbart.addAttributes(bbattributes); - // index the artifact for keyword search - postArtifact(bbart); + newArtifacts.add(bbart); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error adding installed program artifact to blackboard.", ex); //NON-NLS + logger.log(Level.WARNING, "Error adding installed program artifact to blackboard.", ex); //NON-NLS } break; case "office": //NON-NLS @@ -750,10 +746,9 @@ class ExtractRegistry extends Extract { bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME, parentModuleName, artnode.getNodeName())); bbart.addAttributes(bbattributes); - // index the artifact for keyword search - postArtifact(bbart); + newArtifacts.add(bbart); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error adding recent object artifact to blackboard.", ex); //NON-NLS + logger.log(Level.WARNING, "Error adding recent object artifact to blackboard.", ex); //NON-NLS } break; @@ -817,10 +812,9 @@ class ExtractRegistry extends Extract { } } bbart.addAttributes(bbattributes); - // index the artifact for keyword search - postArtifact(bbart); + newArtifacts.add(bbart); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error adding account artifact to blackboard.", ex); //NON-NLS + logger.log(Level.WARNING, "Error adding account artifact to blackboard.", ex); //NON-NLS } break; @@ -834,10 +828,9 @@ class ExtractRegistry extends Extract { bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REMOTE_PATH, parentModuleName, remoteName)); bbart.addAttributes(bbattributes); - // index the artifact for keyword search - postArtifact(bbart); + newArtifacts.add(bbart); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error adding network artifact to blackboard.", ex); //NON-NLS + logger.log(Level.WARNING, "Error adding network artifact to blackboard.", ex); //NON-NLS } break; case "SSID": // NON-NLS @@ -850,10 +843,9 @@ class ExtractRegistry extends Extract { bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DEVICE_ID, parentModuleName, adapter)); BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_WIFI_NETWORK); bbart.addAttributes(bbattributes); - // index the artifact for keyword search - postArtifact(bbart); + newArtifacts.add(bbart); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error adding SSID artifact to blackboard.", ex); //NON-NLS + logger.log(Level.WARNING, "Error adding SSID artifact to blackboard.", ex); //NON-NLS } break; case "shellfolders": // NON-NLS @@ -887,6 +879,8 @@ class ExtractRegistry extends Extract { } } catch (IOException ex) { } + + postArtifacts(newArtifacts); } return false; } @@ -902,6 +896,7 @@ class ExtractRegistry extends Extract { */ private boolean parseSamPluginOutput(String regFilePath, AbstractFile regAbstractFile) { File regfile = new File(regFilePath); + List newArtifacts = new ArrayList<>(); try (BufferedReader bufferedReader = new BufferedReader(new FileReader(regfile))) { // Read the file in and create a Document and elements String userInfoSection = "User Information"; @@ -942,23 +937,25 @@ class ExtractRegistry extends Extract { } } } + //add remaining userinfos as accounts; for (Map userInfo : userInfoMap.values()) { BlackboardArtifact bbart = regAbstractFile.newArtifact(ARTIFACT_TYPE.TSK_OS_ACCOUNT); bbart.addAttributes(getAttributesForAccount(userInfo, groupMap.get(userInfo.get(SID_KEY)), false)); // index the artifact for keyword search - postArtifact(bbart); + newArtifacts.add(bbart); } - //store set of attributes to make artifact for later in collection of artifact like objects return true; } catch (FileNotFoundException ex) { - logger.log(Level.SEVERE, "Error finding the registry file.", ex); //NON-NLS + logger.log(Level.WARNING, "Error finding the registry file.", ex); //NON-NLS } catch (IOException ex) { - logger.log(Level.SEVERE, "Error building the document parser: {0}", ex); //NON-NLS + logger.log(Level.WARNING, "Error building the document parser: {0}", ex); //NON-NLS } catch (ParseException ex) { - logger.log(Level.SEVERE, "Error parsing the the date from the registry file", ex); //NON-NLS + logger.log(Level.WARNING, "Error parsing the the date from the registry file", ex); //NON-NLS } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error updating TSK_OS_ACCOUNT artifacts to include newly parsed data.", ex); //NON-NLS + logger.log(Level.WARNING, "Error updating TSK_OS_ACCOUNT artifacts to include newly parsed data.", ex); //NON-NLS + } finally { + postArtifacts(newArtifacts); } return false; } @@ -1163,39 +1160,41 @@ class ExtractRegistry extends Extract { */ void createShellBagArtifacts(AbstractFile regFile, List shellbags) throws TskCoreException { List artifacts = new ArrayList<>(); - 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())); + 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())); - long time; - time = bag.getLastWrite(); - if (time != 0) { - attributes.add(new BlackboardAttribute(getLastWriteAttribute(), getName(), time)); + long time; + time = bag.getLastWrite(); + if (time != 0) { + attributes.add(new BlackboardAttribute(getLastWriteAttribute(), getName(), time)); + } + + time = bag.getModified(); + if (time != 0) { + attributes.add(new BlackboardAttribute(TSK_DATETIME_MODIFIED, getName(), time)); + } + + time = bag.getCreated(); + if (time != 0) { + attributes.add(new BlackboardAttribute(TSK_DATETIME_CREATED, getName(), time)); + } + + time = bag.getAccessed(); + if (time != 0) { + attributes.add(new BlackboardAttribute(TSK_DATETIME_ACCESSED, getName(), time)); + } + + artifact.addAttributes(attributes); + + artifacts.add(artifact); } - - time = bag.getModified(); - if (time != 0) { - attributes.add(new BlackboardAttribute(TSK_DATETIME_MODIFIED, getName(), time)); - } - - time = bag.getCreated(); - if (time != 0) { - attributes.add(new BlackboardAttribute(TSK_DATETIME_CREATED, getName(), time)); - } - - time = bag.getAccessed(); - if (time != 0) { - attributes.add(new BlackboardAttribute(TSK_DATETIME_ACCESSED, getName(), time)); - } - - artifact.addAttributes(attributes); - - artifacts.add(artifact); + } finally { + postArtifacts(artifacts); } - - postArtifacts(artifacts); } /** From 38fe2ed78383de577dd55b23a9348065905a098d Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Tue, 24 Sep 2019 13:51:49 -0400 Subject: [PATCH 02/17] Changed log levels back to SEVERE --- .../recentactivity/ExtractRegistry.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index 707bd9c337..b7d168147c 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -658,7 +658,7 @@ class ExtractRegistry extends Extract { results.get(0).addAttributes(bbattributes); } } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error adding os info artifact to blackboard.", ex); //NON-NLS + logger.log(Level.SEVERE, "Error adding os info artifact to blackboard.", ex); //NON-NLS } break; default: @@ -718,7 +718,7 @@ class ExtractRegistry extends Extract { itemMtime /= MS_IN_SEC; } } catch (ParseException ex) { - logger.log(Level.WARNING, "Failed to parse epoch time for installed program artifact.", ex); //NON-NLS + logger.log(Level.SEVERE, "Failed to parse epoch time for installed program artifact.", ex); //NON-NLS } try { @@ -729,7 +729,7 @@ class ExtractRegistry extends Extract { newArtifacts.add(bbart); } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error adding installed program artifact to blackboard.", ex); //NON-NLS + logger.log(Level.SEVERE, "Error adding installed program artifact to blackboard.", ex); //NON-NLS } break; case "office": //NON-NLS @@ -748,7 +748,7 @@ class ExtractRegistry extends Extract { newArtifacts.add(bbart); } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error adding recent object artifact to blackboard.", ex); //NON-NLS + logger.log(Level.SEVERE, "Error adding recent object artifact to blackboard.", ex); //NON-NLS } break; @@ -786,7 +786,7 @@ class ExtractRegistry extends Extract { } } } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error getting existing os account artifact", ex); + logger.log(Level.SEVERE, "Error getting existing os account artifact", ex); } if (bbart == null) { //create new artifact @@ -814,7 +814,7 @@ class ExtractRegistry extends Extract { bbart.addAttributes(bbattributes); newArtifacts.add(bbart); } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error adding account artifact to blackboard.", ex); //NON-NLS + logger.log(Level.SEVERE, "Error adding account artifact to blackboard.", ex); //NON-NLS } break; @@ -830,7 +830,7 @@ class ExtractRegistry extends Extract { bbart.addAttributes(bbattributes); newArtifacts.add(bbart); } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error adding network artifact to blackboard.", ex); //NON-NLS + logger.log(Level.SEVERE, "Error adding network artifact to blackboard.", ex); //NON-NLS } break; case "SSID": // NON-NLS @@ -845,7 +845,7 @@ class ExtractRegistry extends Extract { bbart.addAttributes(bbattributes); newArtifacts.add(bbart); } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error adding SSID artifact to blackboard.", ex); //NON-NLS + logger.log(Level.SEVERE, "Error adding SSID artifact to blackboard.", ex); //NON-NLS } break; case "shellfolders": // NON-NLS @@ -855,7 +855,7 @@ class ExtractRegistry extends Extract { break; default: - logger.log(Level.WARNING, "Unrecognized node name: {0}", dataType); //NON-NLS + logger.log(Level.SEVERE, "Unrecognized node name: {0}", dataType); //NON-NLS break; } } @@ -865,13 +865,13 @@ class ExtractRegistry extends Extract { } // for return true; } catch (FileNotFoundException ex) { - logger.log(Level.WARNING, String.format("Error finding the registry file: %s", regFilePath), ex); //NON-NLS + logger.log(Level.SEVERE, String.format("Error finding the registry file: %s", regFilePath), ex); //NON-NLS } catch (SAXException ex) { - logger.log(Level.WARNING, String.format("Error parsing the registry XML: %s", regFilePath), ex); //NON-NLS + logger.log(Level.SEVERE, String.format("Error parsing the registry XML: %s", regFilePath), ex); //NON-NLS } catch (IOException ex) { - logger.log(Level.WARNING, String.format("Error building the document parser: %s", regFilePath), ex); //NON-NLS + logger.log(Level.SEVERE, String.format("Error building the document parser: %s", regFilePath), ex); //NON-NLS } catch (ParserConfigurationException ex) { - logger.log(Level.WARNING, String.format("Error configuring the registry parser: %s", regFilePath), ex); //NON-NLS + logger.log(Level.SEVERE, String.format("Error configuring the registry parser: %s", regFilePath), ex); //NON-NLS } finally { try { if (fstream != null) { @@ -947,13 +947,13 @@ class ExtractRegistry extends Extract { } return true; } catch (FileNotFoundException ex) { - logger.log(Level.WARNING, "Error finding the registry file.", ex); //NON-NLS + logger.log(Level.SEVERE, "Error finding the registry file.", ex); //NON-NLS } catch (IOException ex) { - logger.log(Level.WARNING, "Error building the document parser: {0}", ex); //NON-NLS + logger.log(Level.SEVERE, "Error building the document parser: {0}", ex); //NON-NLS } catch (ParseException ex) { - logger.log(Level.WARNING, "Error parsing the the date from the registry file", ex); //NON-NLS + logger.log(Level.SEVERE, "Error parsing the the date from the registry file", ex); //NON-NLS } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error updating TSK_OS_ACCOUNT artifacts to include newly parsed data.", ex); //NON-NLS + logger.log(Level.SEVERE, "Error updating TSK_OS_ACCOUNT artifacts to include newly parsed data.", ex); //NON-NLS } finally { postArtifacts(newArtifacts); } From fd937a7fd3756e704a7f519c2d508ad67162ca93 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 25 Sep 2019 08:15:46 -0400 Subject: [PATCH 03/17] Added section from Eugene on report setting persistence. Fixed typo. --- docs/doxygen-user/command_line_ingest.dox | 2 +- docs/doxygen/modReport.dox | 45 ++++++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/docs/doxygen-user/command_line_ingest.dox b/docs/doxygen-user/command_line_ingest.dox index dc61708ee4..c5f77def58 100644 --- a/docs/doxygen-user/command_line_ingest.dox +++ b/docs/doxygen-user/command_line_ingest.dox @@ -37,7 +37,7 @@ The table below shows a summary of the command line operations. You can run one Generate Reports
--generateReports
 
--generateReports
-Create List of Data Sources
--listAllDataSources
&nbps;
--listAllDataSources
+Create List of Data Sources
--listAllDataSources
 
--listAllDataSources
diff --git a/docs/doxygen/modReport.dox b/docs/doxygen/modReport.dox index 6199ce7560..5799314acf 100644 --- a/docs/doxygen/modReport.dox +++ b/docs/doxygen/modReport.dox @@ -58,7 +58,7 @@ As when generating table module reports, Autopsy will iterate through a list of \subsection report_create_module_general Creating a General Report Module -If you implement GeneralReportModule, the overriden methods will be: +If you implement GeneralReportModule, the overridden methods will be: - org.sleuthkit.autopsy.report.GeneralReportModule.generateReport(String reportPath, ReportProgressPanel progressPanel) - org.sleuthkit.autopsy.report.GeneralReportModule.getConfigurationPanel() @@ -125,4 +125,47 @@ Report modules developed using Jython are installed in Autopsy by placing them i directory. A window into the python_modules directory can be opened through the Autopsy's Tools -> Python Plugins menu item. Create a folder in this directory and create or place your Python scripts in this folder. + +\subsection report_create_module_persistence Persisting your Report Module Configuration + +Both Java and Python report modules can have their configurations persisted to disk. In order to do so, the report module must do +two things: +
    +
  1. The report module must have a class that defines the configuration for the module (for example, org.sleuthkit.autopsy.report.modules.html.HTMLReportModuleSettings). This class +must implement the ReportModuleSettings interface. Note that the ReportModuleSettings interface extends Serializable, therefore the report +settings class must contain serialVersionUID variable: + +\code +class HTMLReportModuleSettings implements ReportModuleSettings { + + private static final long serialVersionUID = 1L; + + HTMLReportModuleSettings() { + } + + @Override + public long getVersionNumber() { + return serialVersionUID; + } +} +\endcode + +
  2. The report module implementation class (e.g. ReportHTML) must implement the following methods of the ReportModule interface: +- getDefaultConfiguration() +- getConfiguration() +- setConfiguration(ReportModuleSettings settings) +
+ +The use case scenario for this API when the configuration of a report module is occurring is as follows (using HTMLReport as example): +
    +
  1. User clicks "Generate Reports" button in the Autopsy UI. +
  2. Report Configuration UI attempts to load the persisted reporting configuration from disk. +
  3. For each existing report module, if a persisted ReportModuleSettings (i.e. HTMLReportModuleSettings) configuration exists, Configuration UI calls HTMLReport.setConfiguration() with the persisted settings; Otherwise the Configuration UI calls HTMLReport.getDefaultConfiguration(), then HTMLReport.setConfiguration(). +
  4. Configuration UI calls HTMLReport.getConfigurationPanel(). The report module loads the settings into its configuration panel and returns the panel. +
  5. Configuration UI presents the panel to the user. +
  6. User interacts with the panel to modify the current settings of the report module. +
  7. Configuration UI calls HTMLReport.getConfiguration() and obtains the latest report module configuration. +
  8. Configuration UI persists the module settings. +
+ */ From 755f1ade4905b8a7314aa4f7bf4b71560bfc3e5b Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 25 Sep 2019 08:57:59 -0400 Subject: [PATCH 04/17] Added section on mobile parsing helper classes --- docs/doxygen/modMobile.dox | 50 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/docs/doxygen/modMobile.dox b/docs/doxygen/modMobile.dox index ac24ad8fff..255638aa48 100644 --- a/docs/doxygen/modMobile.dox +++ b/docs/doxygen/modMobile.dox @@ -13,6 +13,56 @@ The ingest module has a basic flow of The BlackBoard has standard artifacts for the standard cell phone forensics data types, such as BlackboardArtifact.TSK_CALLLOG. +There are a couple of classes that can help streamline processing mobile databases. The org.sleuthkit.autopsy.coreutils.AppSQLiteDB class has methods for opening and querying SQLite databases. For example, to find and open a database named "transfer20.db" in the "com.dewmobile.kuaiya.play" package, you can simply use the following method (examples in Python): +\verbatim +transferDbs = AppSQLiteDB.findAppDatabases(dataSource, "transfer20.db", True, "com.dewmobile.kuaiya.play") +\endverbatim + +Once you have your databases, you can run easily run queries on them: +\code +queryString = "SELECT device, name, direction, createtime, path, title FROM transfer" +transfersResultSet = transferDb.runQuery(queryString) +\endcode + +You can make Blackboard Artifacts using the org.sleuthkit.datamodel.blackboardutils.CommunicationArtifactsHelper class. This gives you methods to make contacts, messages, and call log entries. The following is sample code in Python to set up the CommunicationArtifactsHelper and then use it to make artifacts. + +\code +transferDbHelper = CommunicationArtifactsHelper(current_case.getSleuthkitCase(), + "Zapya Analyzer", transferDb.getDBFile(), + Account.Type.ZAPYA) +\endcode + +\code +direction = CommunicationDirection.UNKNOWN +fromAddress = None +toAddress = None + +if (transfersResultSet.getInt("direction") == 1): + direction = CommunicationDirection.OUTGOING + toAddress = Account.Address(transfersResultSet.getString("device"), transfersResultSet.getString("name") ) +else: + direction = CommunicationDirection.INCOMING + fromAddress = Account.Address(transfersResultSet.getString("device"), transfersResultSet.getString("name") ) + +msgBody = "" # there is no body. +attachments = [transfersResultSet.getString("path")] +msgBody = general.appendAttachmentList(msgBody, attachments) + +timeStamp = transfersResultSet.getLong("createtime") / 1000 +messageArtifact = transferDbHelper.addMessage( + self._MESSAGE_TYPE, + direction, + fromAddress, + toAddress, + timeStamp, + MessageReadStatus.UNKNOWN, + None, # subject + msgBody, + None ) # thread id +\endcode + +Look in the autopsy\\InternalPythonModules\\android\\ folder for additional examples. + \section mod_mobile_std Android Module Autopsy comes with an Android module, as defined in various classes in the org.sleuthkit.autopsy.modules.android package. You can use those classes as a reference example. From ee03b898cbb321c36e6ab8d5bb5c069f00373b53 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 25 Sep 2019 11:53:55 -0400 Subject: [PATCH 05/17] Revert "5537-file-encryption-handle-asec-files-better" --- .../Bundle.properties-MERGED | 1 - .../EncryptionDetectionFileIngestModule.java | 61 +-- KeywordSearch/ivy.xml | 1 - KeywordSearch/nbproject/project.properties | 1 - KeywordSearch/nbproject/project.xml | 4 - .../AutopsyConfig/conf/lang/stoptags_ja.txt | 420 ------------------ .../AutopsyConfig/conf/lang/stopwords_ja.txt | 127 ------ .../configsets/AutopsyConfig/conf/schema.xml | 20 +- .../keywordsearch/HighlightedText.java | 124 +----- .../autopsy/keywordsearch/IndexFinder.java | 2 +- .../autopsy/keywordsearch/Ingester.java | 24 +- .../autopsy/keywordsearch/Language.java | 46 -- .../keywordsearch/LanguageDetector.java | 60 --- ...LanguageSpecificContentIndexingHelper.java | 85 ---- .../LanguageSpecificContentQueryHelper.java | 248 ----------- .../autopsy/keywordsearch/LuceneQuery.java | 63 +-- .../keywordsearch/MiniChunkHelper.java | 41 -- .../keywordsearch/QueryTermHelper.java | 95 ---- .../autopsy/keywordsearch/Server.java | 26 +- ...anguageSpecificContentQueryHelperTest.java | 59 --- .../keywordsearch/MiniChunkHelperTest.java | 46 -- 21 files changed, 42 insertions(+), 1512 deletions(-) delete mode 100644 KeywordSearch/solr/solr/configsets/AutopsyConfig/conf/lang/stoptags_ja.txt delete mode 100644 KeywordSearch/solr/solr/configsets/AutopsyConfig/conf/lang/stopwords_ja.txt delete mode 100644 KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Language.java delete mode 100644 KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LanguageDetector.java delete mode 100644 KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LanguageSpecificContentIndexingHelper.java delete mode 100644 KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LanguageSpecificContentQueryHelper.java delete mode 100644 KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/MiniChunkHelper.java delete mode 100644 KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryTermHelper.java delete mode 100644 KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/LanguageSpecificContentQueryHelperTest.java delete mode 100644 KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/MiniChunkHelperTest.java diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties-MERGED index 36198317db..905c5b3d84 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties-MERGED @@ -1,7 +1,6 @@ EncryptionDetectionDataSourceIngestModule.artifactComment.bitlocker=Bitlocker encryption detected. EncryptionDetectionDataSourceIngestModule.artifactComment.suspected=Suspected encryption due to high entropy (%f). EncryptionDetectionDataSourceIngestModule.processing.message=Checking image for encryption. -EncryptionDetectionFileIngestModule.artifactComment.location=High entropy and known location/extension. EncryptionDetectionFileIngestModule.artifactComment.password=Password protection detected. EncryptionDetectionFileIngestModule.artifactComment.suspected=Suspected encryption due to high entropy (%f). EncryptionDetectionFileIngestModule.getDesc.text=Looks for files with the specified minimum entropy. diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java index 20252d4eb4..9afafb7831 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java @@ -29,8 +29,6 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.BufferUnderflowException; -import java.util.HashMap; -import java.util.Map; import java.util.logging.Level; import org.apache.tika.exception.EncryptedDocumentException; import org.apache.tika.exception.TikaException; @@ -77,11 +75,6 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter private static final String MIME_TYPE_PDF = "application/pdf"; private static final String[] FILE_IGNORE_LIST = {"hiberfile.sys", "pagefile.sys"}; - - /** - * This maps file locations to file extensions that are known to be encrypted - */ - private static final Map knownEncryptedLocationExtensions = createLocationExtensionMap(); private final IngestServices services = IngestServices.getInstance(); private final Logger logger = services.getLogger(EncryptionDetectionModuleFactory.getModuleName()); @@ -113,7 +106,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter public void startUp(IngestJobContext context) throws IngestModule.IngestModuleException { try { validateSettings(); - this.context = context; + this.context = context; blackboard = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboard(); fileTypeDetector = new FileTypeDetector(); @@ -126,7 +119,6 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter @Messages({ "EncryptionDetectionFileIngestModule.artifactComment.password=Password protection detected.", - "EncryptionDetectionFileIngestModule.artifactComment.location=High entropy and known location/extension.", "EncryptionDetectionFileIngestModule.artifactComment.suspected=Suspected encryption due to high entropy (%f)." }) @Override @@ -138,12 +130,12 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter * verify the file hasn't been deleted. */ if (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) - && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) - && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR) - && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR) - && (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK) || slackFilesAllowed) - && !file.getKnown().equals(TskData.FileKnown.KNOWN) - && !file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)) { + && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) + && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR) + && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR) + && (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK) || slackFilesAllowed) + && !file.getKnown().equals(TskData.FileKnown.KNOWN) + && !file.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)) { /* * Is the file in FILE_IGNORE_LIST? */ @@ -163,9 +155,6 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter */ String mimeType = fileTypeDetector.getMIMEType(file); if (mimeType.equals("application/octet-stream") && isFileEncryptionSuspected(file)) { - if (checkFileLocationExtension(file)) { - return flagFile(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED, Bundle.EncryptionDetectionFileIngestModule_artifactComment_location()); - } return flagFile(file, BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_SUSPECTED, String.format(Bundle.EncryptionDetectionFileIngestModule_artifactComment_suspected(), calculatedEntropy)); } else if (isFilePasswordProtected(file)) { @@ -209,7 +198,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter if (context.fileIngestIsCancelled()) { return IngestModule.ProcessResult.OK; } - + BlackboardArtifact artifact = file.newArtifact(artifactType); artifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, EncryptionDetectionModuleFactory.getModuleName(), comment)); @@ -336,7 +325,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter try { accessDatabase = databaseBuilder.open(); } catch (IOException | BufferUnderflowException | IndexOutOfBoundsException ignored) { - return passwordProtected; + return passwordProtected; } /* * No exception has been thrown at this point, so the file @@ -417,36 +406,4 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter return possiblyEncrypted; } - - /** - * This method checks if the AbstractFile input is in a location that is - * known to hold encrypted files. It must meet the requirements and location - * of known encrypted file(s) - * - * @param file AbstractFile to be checked. - * - * @return True if file extension and location match known values. - * - */ - private boolean checkFileLocationExtension(AbstractFile file) { - String filePath = file.getParentPath().replace("/", ""); - if ((knownEncryptedLocationExtensions.containsKey(filePath)) - && (knownEncryptedLocationExtensions.get(filePath).equals(file.getNameExtension()))) - { - return true; - } - return false; - } - - /* - * This method creates the map of paths and extensions that are known to - * have encrypted files - * - * @return Map of path and extension of files - */ - private static Map createLocationExtensionMap() { - Map locationExtensionMap = new HashMap(); - locationExtensionMap.put(".android_secure", "asec"); - return locationExtensionMap; - } } diff --git a/KeywordSearch/ivy.xml b/KeywordSearch/ivy.xml index 9f39e52d7c..2d7bb8b4a5 100644 --- a/KeywordSearch/ivy.xml +++ b/KeywordSearch/ivy.xml @@ -21,7 +21,6 @@ - diff --git a/KeywordSearch/nbproject/project.properties b/KeywordSearch/nbproject/project.properties index 86b4519538..1041bdd524 100644 --- a/KeywordSearch/nbproject/project.properties +++ b/KeywordSearch/nbproject/project.properties @@ -29,7 +29,6 @@ file.reference.jericho-html-3.3.jar=release/modules/ext/jericho-html-3.3.jar file.reference.joda-time-2.2.jar=release/modules/ext/joda-time-2.2.jar file.reference.json-simple-1.1.1.jar=release/modules/ext/json-simple-1.1.1.jar file.reference.juniversalchardet-1.0.3.jar=release/modules/ext/juniversalchardet-1.0.3.jar -file.reference.language-detector-0.6.jar=release/modules/ext/language-detector-0.6.jar file.reference.libsvm-3.1.jar=release/modules/ext/libsvm-3.1.jar file.reference.log4j-1.2.17.jar=release/modules/ext/log4j-1.2.17.jar file.reference.lucene-core-4.0.0.jar=release/modules/ext/lucene-core-4.0.0.jar diff --git a/KeywordSearch/nbproject/project.xml b/KeywordSearch/nbproject/project.xml index 96bbdef0c5..3f40ab3ace 100644 --- a/KeywordSearch/nbproject/project.xml +++ b/KeywordSearch/nbproject/project.xml @@ -467,10 +467,6 @@ ext/vorbis-java-tika-0.8.jar release/modules/ext/vorbis-java-tika-0.8.jar - - ext/language-detector-0.6.jar - release/modules/ext/language-detector-0.6.jar - diff --git a/KeywordSearch/solr/solr/configsets/AutopsyConfig/conf/lang/stoptags_ja.txt b/KeywordSearch/solr/solr/configsets/AutopsyConfig/conf/lang/stoptags_ja.txt deleted file mode 100644 index 71b750845e..0000000000 --- a/KeywordSearch/solr/solr/configsets/AutopsyConfig/conf/lang/stoptags_ja.txt +++ /dev/null @@ -1,420 +0,0 @@ -# -# This file defines a Japanese stoptag set for JapanesePartOfSpeechStopFilter. -# -# Any token with a part-of-speech tag that exactly matches those defined in this -# file are removed from the token stream. -# -# Set your own stoptags by uncommenting the lines below. Note that comments are -# not allowed on the same line as a stoptag. See LUCENE-3745 for frequency lists, -# etc. that can be useful for building you own stoptag set. -# -# The entire possible tagset is provided below for convenience. -# -##### -# noun: unclassified nouns -#名詞 -# -# noun-common: Common nouns or nouns where the sub-classification is undefined -#名詞-一般 -# -# noun-proper: Proper nouns where the sub-classification is undefined -#名詞-固有名詞 -# -# noun-proper-misc: miscellaneous proper nouns -#名詞-固有名詞-一般 -# -# noun-proper-person: Personal names where the sub-classification is undefined -#名詞-固有名詞-人名 -# -# noun-proper-person-misc: names that cannot be divided into surname and -# given name; foreign names; names where the surname or given name is unknown. -# e.g. お市の方 -#名詞-固有名詞-人名-一般 -# -# noun-proper-person-surname: Mainly Japanese surnames. -# e.g. 山田 -#名詞-固有名詞-人名-姓 -# -# noun-proper-person-given_name: Mainly Japanese given names. -# e.g. 太郎 -#名詞-固有名詞-人名-名 -# -# noun-proper-organization: Names representing organizations. -# e.g. 通産省, NHK -#名詞-固有名詞-組織 -# -# noun-proper-place: Place names where the sub-classification is undefined -#名詞-固有名詞-地域 -# -# noun-proper-place-misc: Place names excluding countries. -# e.g. アジア, バルセロナ, 京都 -#名詞-固有名詞-地域-一般 -# -# noun-proper-place-country: Country names. -# e.g. 日本, オーストラリア -#名詞-固有名詞-地域-国 -# -# noun-pronoun: Pronouns where the sub-classification is undefined -#名詞-代名詞 -# -# noun-pronoun-misc: miscellaneous pronouns: -# e.g. それ, ここ, あいつ, あなた, あちこち, いくつ, どこか, なに, みなさん, みんな, わたくし, われわれ -#名詞-代名詞-一般 -# -# noun-pronoun-contraction: Spoken language contraction made by combining a -# pronoun and the particle 'wa'. -# e.g. ありゃ, こりゃ, こりゃあ, そりゃ, そりゃあ -#名詞-代名詞-縮約 -# -# noun-adverbial: Temporal nouns such as names of days or months that behave -# like adverbs. Nouns that represent amount or ratios and can be used adverbially, -# e.g. 金曜, 一月, 午後, 少量 -#名詞-副詞可能 -# -# noun-verbal: Nouns that take arguments with case and can appear followed by -# 'suru' and related verbs (する, できる, なさる, くださる) -# e.g. インプット, 愛着, 悪化, 悪戦苦闘, 一安心, 下取り -#名詞-サ変接続 -# -# noun-adjective-base: The base form of adjectives, words that appear before な ("na") -# e.g. 健康, 安易, 駄目, だめ -#名詞-形容動詞語幹 -# -# noun-numeric: Arabic numbers, Chinese numerals, and counters like 何 (回), 数. -# e.g. 0, 1, 2, 何, 数, 幾 -#名詞-数 -# -# noun-affix: noun affixes where the sub-classification is undefined -#名詞-非自立 -# -# noun-affix-misc: Of adnominalizers, the case-marker の ("no"), and words that -# attach to the base form of inflectional words, words that cannot be classified -# into any of the other categories below. This category includes indefinite nouns. -# e.g. あかつき, 暁, かい, 甲斐, 気, きらい, 嫌い, くせ, 癖, こと, 事, ごと, 毎, しだい, 次第, -# 順, せい, 所為, ついで, 序で, つもり, 積もり, 点, どころ, の, はず, 筈, はずみ, 弾み, -# 拍子, ふう, ふり, 振り, ほう, 方, 旨, もの, 物, 者, ゆえ, 故, ゆえん, 所以, わけ, 訳, -# わり, 割り, 割, ん-口語/, もん-口語/ -#名詞-非自立-一般 -# -# noun-affix-adverbial: noun affixes that that can behave as adverbs. -# e.g. あいだ, 間, あげく, 挙げ句, あと, 後, 余り, 以外, 以降, 以後, 以上, 以前, 一方, うえ, -# 上, うち, 内, おり, 折り, かぎり, 限り, きり, っきり, 結果, ころ, 頃, さい, 際, 最中, さなか, -# 最中, じたい, 自体, たび, 度, ため, 為, つど, 都度, とおり, 通り, とき, 時, ところ, 所, -# とたん, 途端, なか, 中, のち, 後, ばあい, 場合, 日, ぶん, 分, ほか, 他, まえ, 前, まま, -# 儘, 侭, みぎり, 矢先 -#名詞-非自立-副詞可能 -# -# noun-affix-aux: noun affixes treated as 助動詞 ("auxiliary verb") in school grammars -# with the stem よう(だ) ("you(da)"). -# e.g. よう, やう, 様 (よう) -#名詞-非自立-助動詞語幹 -# -# noun-affix-adjective-base: noun affixes that can connect to the indeclinable -# connection form な (aux "da"). -# e.g. みたい, ふう -#名詞-非自立-形容動詞語幹 -# -# noun-special: special nouns where the sub-classification is undefined. -#名詞-特殊 -# -# noun-special-aux: The そうだ ("souda") stem form that is used for reporting news, is -# treated as 助動詞 ("auxiliary verb") in school grammars, and attach to the base -# form of inflectional words. -# e.g. そう -#名詞-特殊-助動詞語幹 -# -# noun-suffix: noun suffixes where the sub-classification is undefined. -#名詞-接尾 -# -# noun-suffix-misc: Of the nouns or stem forms of other parts of speech that connect -# to ガル or タイ and can combine into compound nouns, words that cannot be classified into -# any of the other categories below. In general, this category is more inclusive than -# 接尾語 ("suffix") and is usually the last element in a compound noun. -# e.g. おき, かた, 方, 甲斐 (がい), がかり, ぎみ, 気味, ぐるみ, (~した) さ, 次第, 済 (ず) み, -# よう, (でき)っこ, 感, 観, 性, 学, 類, 面, 用 -#名詞-接尾-一般 -# -# noun-suffix-person: Suffixes that form nouns and attach to person names more often -# than other nouns. -# e.g. 君, 様, 著 -#名詞-接尾-人名 -# -# noun-suffix-place: Suffixes that form nouns and attach to place names more often -# than other nouns. -# e.g. 町, 市, 県 -#名詞-接尾-地域 -# -# noun-suffix-verbal: Of the suffixes that attach to nouns and form nouns, those that -# can appear before スル ("suru"). -# e.g. 化, 視, 分け, 入り, 落ち, 買い -#名詞-接尾-サ変接続 -# -# noun-suffix-aux: The stem form of そうだ (様態) that is used to indicate conditions, -# is treated as 助動詞 ("auxiliary verb") in school grammars, and attach to the -# conjunctive form of inflectional words. -# e.g. そう -#名詞-接尾-助動詞語幹 -# -# noun-suffix-adjective-base: Suffixes that attach to other nouns or the conjunctive -# form of inflectional words and appear before the copula だ ("da"). -# e.g. 的, げ, がち -#名詞-接尾-形容動詞語幹 -# -# noun-suffix-adverbial: Suffixes that attach to other nouns and can behave as adverbs. -# e.g. 後 (ご), 以後, 以降, 以前, 前後, 中, 末, 上, 時 (じ) -#名詞-接尾-副詞可能 -# -# noun-suffix-classifier: Suffixes that attach to numbers and form nouns. This category -# is more inclusive than 助数詞 ("classifier") and includes common nouns that attach -# to numbers. -# e.g. 個, つ, 本, 冊, パーセント, cm, kg, カ月, か国, 区画, 時間, 時半 -#名詞-接尾-助数詞 -# -# noun-suffix-special: Special suffixes that mainly attach to inflecting words. -# e.g. (楽し) さ, (考え) 方 -#名詞-接尾-特殊 -# -# noun-suffix-conjunctive: Nouns that behave like conjunctions and join two words -# together. -# e.g. (日本) 対 (アメリカ), 対 (アメリカ), (3) 対 (5), (女優) 兼 (主婦) -#名詞-接続詞的 -# -# noun-verbal_aux: Nouns that attach to the conjunctive particle て ("te") and are -# semantically verb-like. -# e.g. ごらん, ご覧, 御覧, 頂戴 -#名詞-動詞非自立的 -# -# noun-quotation: text that cannot be segmented into words, proverbs, Chinese poetry, -# dialects, English, etc. Currently, the only entry for 名詞 引用文字列 ("noun quotation") -# is いわく ("iwaku"). -#名詞-引用文字列 -# -# noun-nai_adjective: Words that appear before the auxiliary verb ない ("nai") and -# behave like an adjective. -# e.g. 申し訳, 仕方, とんでも, 違い -#名詞-ナイ形容詞語幹 -# -##### -# prefix: unclassified prefixes -#接頭詞 -# -# prefix-nominal: Prefixes that attach to nouns (including adjective stem forms) -# excluding numerical expressions. -# e.g. お (水), 某 (氏), 同 (社), 故 (~氏), 高 (品質), お (見事), ご (立派) -#接頭詞-名詞接続 -# -# prefix-verbal: Prefixes that attach to the imperative form of a verb or a verb -# in conjunctive form followed by なる/なさる/くださる. -# e.g. お (読みなさい), お (座り) -#接頭詞-動詞接続 -# -# prefix-adjectival: Prefixes that attach to adjectives. -# e.g. お (寒いですねえ), バカ (でかい) -#接頭詞-形容詞接続 -# -# prefix-numerical: Prefixes that attach to numerical expressions. -# e.g. 約, およそ, 毎時 -#接頭詞-数接続 -# -##### -# verb: unclassified verbs -#動詞 -# -# verb-main: -#動詞-自立 -# -# verb-auxiliary: -#動詞-非自立 -# -# verb-suffix: -#動詞-接尾 -# -##### -# adjective: unclassified adjectives -#形容詞 -# -# adjective-main: -#形容詞-自立 -# -# adjective-auxiliary: -#形容詞-非自立 -# -# adjective-suffix: -#形容詞-接尾 -# -##### -# adverb: unclassified adverbs -#副詞 -# -# adverb-misc: Words that can be segmented into one unit and where adnominal -# modification is not possible. -# e.g. あいかわらず, 多分 -#副詞-一般 -# -# adverb-particle_conjunction: Adverbs that can be followed by の, は, に, -# な, する, だ, etc. -# e.g. こんなに, そんなに, あんなに, なにか, なんでも -#副詞-助詞類接続 -# -##### -# adnominal: Words that only have noun-modifying forms. -# e.g. この, その, あの, どの, いわゆる, なんらかの, 何らかの, いろんな, こういう, そういう, ああいう, -# どういう, こんな, そんな, あんな, どんな, 大きな, 小さな, おかしな, ほんの, たいした, -# 「(, も) さる (ことながら)」, 微々たる, 堂々たる, 単なる, いかなる, 我が」「同じ, 亡き -#連体詞 -# -##### -# conjunction: Conjunctions that can occur independently. -# e.g. が, けれども, そして, じゃあ, それどころか -接続詞 -# -##### -# particle: unclassified particles. -助詞 -# -# particle-case: case particles where the subclassification is undefined. -助詞-格助詞 -# -# particle-case-misc: Case particles. -# e.g. から, が, で, と, に, へ, より, を, の, にて -助詞-格助詞-一般 -# -# particle-case-quote: the "to" that appears after nouns, a person’s speech, -# quotation marks, expressions of decisions from a meeting, reasons, judgements, -# conjectures, etc. -# e.g. ( だ) と (述べた.), ( である) と (して執行猶予...) -助詞-格助詞-引用 -# -# particle-case-compound: Compounds of particles and verbs that mainly behave -# like case particles. -# e.g. という, といった, とかいう, として, とともに, と共に, でもって, にあたって, に当たって, に当って, -# にあたり, に当たり, に当り, に当たる, にあたる, において, に於いて,に於て, における, に於ける, -# にかけ, にかけて, にかんし, に関し, にかんして, に関して, にかんする, に関する, に際し, -# に際して, にしたがい, に従い, に従う, にしたがって, に従って, にたいし, に対し, にたいして, -# に対して, にたいする, に対する, について, につき, につけ, につけて, につれ, につれて, にとって, -# にとり, にまつわる, によって, に依って, に因って, により, に依り, に因り, による, に依る, に因る, -# にわたって, にわたる, をもって, を以って, を通じ, を通じて, を通して, をめぐって, をめぐり, をめぐる, -# って-口語/, ちゅう-関西弁「という」/, (何) ていう (人)-口語/, っていう-口語/, といふ, とかいふ -助詞-格助詞-連語 -# -# particle-conjunctive: -# e.g. から, からには, が, けれど, けれども, けど, し, つつ, て, で, と, ところが, どころか, とも, ども, -# ながら, なり, ので, のに, ば, ものの, や ( した), やいなや, (ころん) じゃ(いけない)-口語/, -# (行っ) ちゃ(いけない)-口語/, (言っ) たって (しかたがない)-口語/, (それがなく)ったって (平気)-口語/ -助詞-接続助詞 -# -# particle-dependency: -# e.g. こそ, さえ, しか, すら, は, も, ぞ -助詞-係助詞 -# -# particle-adverbial: -# e.g. がてら, かも, くらい, 位, ぐらい, しも, (学校) じゃ(これが流行っている)-口語/, -# (それ)じゃあ (よくない)-口語/, ずつ, (私) なぞ, など, (私) なり (に), (先生) なんか (大嫌い)-口語/, -# (私) なんぞ, (先生) なんて (大嫌い)-口語/, のみ, だけ, (私) だって-口語/, だに, -# (彼)ったら-口語/, (お茶) でも (いかが), 等 (とう), (今後) とも, ばかり, ばっか-口語/, ばっかり-口語/, -# ほど, 程, まで, 迄, (誰) も (が)([助詞-格助詞] および [助詞-係助詞] の前に位置する「も」) -助詞-副助詞 -# -# particle-interjective: particles with interjective grammatical roles. -# e.g. (松島) や -助詞-間投助詞 -# -# particle-coordinate: -# e.g. と, たり, だの, だり, とか, なり, や, やら -助詞-並立助詞 -# -# particle-final: -# e.g. かい, かしら, さ, ぜ, (だ)っけ-口語/, (とまってる) で-方言/, な, ナ, なあ-口語/, ぞ, ね, ネ, -# ねぇ-口語/, ねえ-口語/, ねん-方言/, の, のう-口語/, や, よ, ヨ, よぉ-口語/, わ, わい-口語/ -助詞-終助詞 -# -# particle-adverbial/conjunctive/final: The particle "ka" when unknown whether it is -# adverbial, conjunctive, or sentence final. For example: -# (a) 「A か B か」. Ex:「(国内で運用する) か,(海外で運用する) か (.)」 -# (b) Inside an adverb phrase. Ex:「(幸いという) か (, 死者はいなかった.)」 -# 「(祈りが届いたせい) か (, 試験に合格した.)」 -# (c) 「かのように」. Ex:「(何もなかった) か (のように振る舞った.)」 -# e.g. か -助詞-副助詞/並立助詞/終助詞 -# -# particle-adnominalizer: The "no" that attaches to nouns and modifies -# non-inflectional words. -助詞-連体化 -# -# particle-adnominalizer: The "ni" and "to" that appear following nouns and adverbs -# that are giongo, giseigo, or gitaigo. -# e.g. に, と -助詞-副詞化 -# -# particle-special: A particle that does not fit into one of the above classifications. -# This includes particles that are used in Tanka, Haiku, and other poetry. -# e.g. かな, けむ, ( しただろう) に, (あんた) にゃ(わからん), (俺) ん (家) -助詞-特殊 -# -##### -# auxiliary-verb: -助動詞 -# -##### -# interjection: Greetings and other exclamations. -# e.g. おはよう, おはようございます, こんにちは, こんばんは, ありがとう, どうもありがとう, ありがとうございます, -# いただきます, ごちそうさま, さよなら, さようなら, はい, いいえ, ごめん, ごめんなさい -#感動詞 -# -##### -# symbol: unclassified Symbols. -記号 -# -# symbol-misc: A general symbol not in one of the categories below. -# e.g. [○◎@$〒→+] -記号-一般 -# -# symbol-comma: Commas -# e.g. [,、] -記号-読点 -# -# symbol-period: Periods and full stops. -# e.g. [..。] -記号-句点 -# -# symbol-space: Full-width whitespace. -記号-空白 -# -# symbol-open_bracket: -# e.g. [({‘“『【] -記号-括弧開 -# -# symbol-close_bracket: -# e.g. [)}’”』」】] -記号-括弧閉 -# -# symbol-alphabetic: -#記号-アルファベット -# -##### -# other: unclassified other -#その他 -# -# other-interjection: Words that are hard to classify as noun-suffixes or -# sentence-final particles. -# e.g. (だ)ァ -その他-間投 -# -##### -# filler: Aizuchi that occurs during a conversation or sounds inserted as filler. -# e.g. あの, うんと, えと -フィラー -# -##### -# non-verbal: non-verbal sound. -非言語音 -# -##### -# fragment: -#語断片 -# -##### -# unknown: unknown part of speech. -#未知語 -# -##### End of file diff --git a/KeywordSearch/solr/solr/configsets/AutopsyConfig/conf/lang/stopwords_ja.txt b/KeywordSearch/solr/solr/configsets/AutopsyConfig/conf/lang/stopwords_ja.txt deleted file mode 100644 index d4321be6b1..0000000000 --- a/KeywordSearch/solr/solr/configsets/AutopsyConfig/conf/lang/stopwords_ja.txt +++ /dev/null @@ -1,127 +0,0 @@ -# -# This file defines a stopword set for Japanese. -# -# This set is made up of hand-picked frequent terms from segmented Japanese Wikipedia. -# Punctuation characters and frequent kanji have mostly been left out. See LUCENE-3745 -# for frequency lists, etc. that can be useful for making your own set (if desired) -# -# Note that there is an overlap between these stopwords and the terms stopped when used -# in combination with the JapanesePartOfSpeechStopFilter. When editing this file, note -# that comments are not allowed on the same line as stopwords. -# -# Also note that stopping is done in a case-insensitive manner. Change your StopFilter -# configuration if you need case-sensitive stopping. Lastly, note that stopping is done -# using the same character width as the entries in this file. Since this StopFilter is -# normally done after a CJKWidthFilter in your chain, you would usually want your romaji -# entries to be in half-width and your kana entries to be in full-width. -# -の -に -は -を -た -が -で -て -と -し -れ -さ -ある -いる -も -する -から -な -こと -として -い -や -れる -など -なっ -ない -この -ため -その -あっ -よう -また -もの -という -あり -まで -られ -なる -へ -か -だ -これ -によって -により -おり -より -による -ず -なり -られる -において -ば -なかっ -なく -しかし -について -せ -だっ -その後 -できる -それ -う -ので -なお -のみ -でき -き -つ -における -および -いう -さらに -でも -ら -たり -その他 -に関する -たち -ます -ん -なら -に対して -特に -せる -及び -これら -とき -では -にて -ほか -ながら -うち -そして -とともに -ただし -かつて -それぞれ -または -お -ほど -ものの -に対する -ほとんど -と共に -といった -です -とも -ところ -ここ -##### End of file diff --git a/KeywordSearch/solr/solr/configsets/AutopsyConfig/conf/schema.xml b/KeywordSearch/solr/solr/configsets/AutopsyConfig/conf/schema.xml index bbc68fea00..05ea8891a5 100644 --- a/KeywordSearch/solr/solr/configsets/AutopsyConfig/conf/schema.xml +++ b/KeywordSearch/solr/solr/configsets/AutopsyConfig/conf/schema.xml @@ -45,7 +45,7 @@ that avoids logging every request --> - + @@ -244,18 +243,6 @@ - - - - - - - - - - - - - - - - - diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java index 99d4f40820..240c10e431 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/HighlightedText.java @@ -38,7 +38,6 @@ import org.apache.commons.lang3.math.NumberUtils; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrRequest.METHOD; import org.apache.solr.client.solrj.response.QueryResponse; -import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocumentList; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; @@ -347,8 +346,6 @@ class HighlightedText implements IndexedText { String chunkID = ""; String highlightField = ""; try { - double indexSchemaVersion = NumberUtils.toDouble(solrServer.getIndexInfo().getSchemaVersion()); - loadPageInfo(); //inits once SolrQuery q = new SolrQuery(); q.setShowDebugInfo(DEBUG); //debug @@ -362,46 +359,22 @@ class HighlightedText implements IndexedText { highlightField = LuceneQuery.HIGHLIGHT_FIELD; if (isLiteral) { - if (2.2 <= indexSchemaVersion) { - //if the query is literal try to get solr to do the highlighting - final String highlightQuery = keywords.stream().map(s -> - LanguageSpecificContentQueryHelper.expandQueryString(KeywordSearchUtil.quoteQuery(KeywordSearchUtil.escapeLuceneQuery(s)))) - .collect(Collectors.joining(" OR ")); - q.setQuery(highlightQuery); - for (Server.Schema field : LanguageSpecificContentQueryHelper.getQueryFields()) { - q.addField(field.toString()); - q.addHighlightField(field.toString()); - } - q.addField(Server.Schema.LANGUAGE.toString()); - // in case of single term literal query there is only 1 term - LanguageSpecificContentQueryHelper.configureTermfreqQuery(q, keywords.iterator().next()); - q.addFilterQuery(filterQuery); - q.setHighlightFragsize(0); // don't fragment the highlight, works with original highlighter, or needs "single" list builder with FVH - } else { - //if the query is literal try to get solr to do the highlighting - final String highlightQuery = keywords.stream() - .map(HighlightedText::constructEscapedSolrQuery) - .collect(Collectors.joining(" ")); + //if the query is literal try to get solr to do the highlighting + final String highlightQuery = keywords.stream() + .map(HighlightedText::constructEscapedSolrQuery) + .collect(Collectors.joining(" ")); - q.setQuery(highlightQuery); - q.addField(highlightField); - q.addFilterQuery(filterQuery); - q.addHighlightField(highlightField); - q.setHighlightFragsize(0); // don't fragment the highlight, works with original highlighter, or needs "single" list builder with FVH - } + q.setQuery(highlightQuery); + q.addField(highlightField); + q.addFilterQuery(filterQuery); + q.addHighlightField(highlightField); + q.setHighlightFragsize(0); // don't fragment the highlight, works with original highlighter, or needs "single" list builder with FVH //tune the highlighter - if (shouldUseOriginalHighlighter(contentIdStr)) { - // use original highlighter - q.setParam("hl.useFastVectorHighlighter", "off"); - q.setParam("hl.simple.pre", HIGHLIGHT_PRE); - q.setParam("hl.simple.post", HIGHLIGHT_POST); - } else { - q.setParam("hl.useFastVectorHighlighter", "on"); //fast highlighter scales better than standard one NON-NLS - q.setParam("hl.tag.pre", HIGHLIGHT_PRE); //makes sense for FastVectorHighlighter only NON-NLS - q.setParam("hl.tag.post", HIGHLIGHT_POST); //makes sense for FastVectorHighlighter only NON-NLS - q.setParam("hl.fragListBuilder", "single"); //makes sense for FastVectorHighlighter only NON-NLS - } + q.setParam("hl.useFastVectorHighlighter", "on"); //fast highlighter scales better than standard one NON-NLS + q.setParam("hl.tag.pre", HIGHLIGHT_PRE); //makes sense for FastVectorHighlighter only NON-NLS + q.setParam("hl.tag.post", HIGHLIGHT_POST); //makes sense for FastVectorHighlighter only NON-NLS + q.setParam("hl.fragListBuilder", "single"); //makes sense for FastVectorHighlighter only NON-NLS //docs says makes sense for the original Highlighter only, but not really q.setParam("hl.maxAnalyzedChars", Server.HL_ANALYZE_CHARS_UNLIMITED); //NON-NLS @@ -433,40 +406,12 @@ class HighlightedText implements IndexedText { if (responseHighlightID == null) { highlightedContent = attemptManualHighlighting(response.getResults(), highlightField, keywords); } else { - SolrDocument document = response.getResults().get(0); - Object language = document.getFieldValue(Server.Schema.LANGUAGE.toString()); - if (2.2 <= indexSchemaVersion && language != null) { - List contentHighlights = LanguageSpecificContentQueryHelper.getHighlights(responseHighlightID).orElse(null); - if (contentHighlights == null) { - highlightedContent = ""; - } else { - int hitCountInMiniChunk = LanguageSpecificContentQueryHelper.queryChunkTermfreq(keywords, MiniChunkHelper.getChunkIdString(contentIdStr)); - String s = contentHighlights.get(0).trim(); - // If there is a mini-chunk, trim the content not to show highlighted text in it. - if (0 < hitCountInMiniChunk) { - int hitCountInChunk = ((Float) document.getFieldValue(Server.Schema.TERMFREQ.toString())).intValue(); - int idx = LanguageSpecificContentQueryHelper.findNthIndexOf( - s, - HIGHLIGHT_PRE, - // trim after the last hit in chunk - hitCountInChunk - hitCountInMiniChunk); - if (idx != -1) { - highlightedContent = s.substring(0, idx); - } else { - highlightedContent = s; - } - } else { - highlightedContent = s; - } - } + List contentHighlights = responseHighlightID.get(LuceneQuery.HIGHLIGHT_FIELD); + if (contentHighlights == null) { + highlightedContent = attemptManualHighlighting(response.getResults(), highlightField, keywords); } else { - List contentHighlights = responseHighlightID.get(LuceneQuery.HIGHLIGHT_FIELD); - if (contentHighlights == null) { - highlightedContent = attemptManualHighlighting(response.getResults(), highlightField, keywords); - } else { - // extracted content (minus highlight tags) is HTML-escaped - highlightedContent = contentHighlights.get(0).trim(); - } + // extracted content (minus highlight tags) is HTML-escaped + highlightedContent = contentHighlights.get(0).trim(); } } } @@ -606,37 +551,4 @@ class HighlightedText implements IndexedText { return buf.toString(); } - /** - * Return true if we should use original highlighter instead of FastVectorHighlighter. - * - * In the case Japanese text and phrase query, FastVectorHighlighter does not work well. - * - * Note about highlighters: - * If the query is "雨が降る" (phrase query), Solr divides it into 雨 and 降る. が is a stop word here. - * It seems that FastVector highlighter does not produce any snippet when there is a stop word between terms. - * On the other hand, original highlighter produces multiple matches, for example: - * > 雨が降っています - * Unified highlighter (from Solr 6.4) handles the case as expected: - * > 雨が降っています。 - */ - private boolean shouldUseOriginalHighlighter(String contentID) throws NoOpenCoreException, KeywordSearchModuleException { - final SolrQuery q = new SolrQuery(); - q.setQuery("*:*"); - q.addFilterQuery(Server.Schema.ID.toString() + ":" + contentID); - q.setFields(Server.Schema.LANGUAGE.toString()); - - QueryResponse response = solrServer.query(q, METHOD.POST); - SolrDocumentList solrDocuments = response.getResults(); - - if (!solrDocuments.isEmpty()) { - SolrDocument solrDocument = solrDocuments.get(0); - if (solrDocument != null) { - Object languageField = solrDocument.getFieldValue(Server.Schema.LANGUAGE.toString()); - if (languageField != null) { - return languageField.equals("ja"); - } - } - } - return false; - } } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexFinder.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexFinder.java index e2abde6eb0..e46791d270 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexFinder.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/IndexFinder.java @@ -39,7 +39,7 @@ class IndexFinder { private static final String KWS_DATA_FOLDER_NAME = "data"; private static final String INDEX_FOLDER_NAME = "index"; private static final String CURRENT_SOLR_VERSION = "4"; - private static final String CURRENT_SOLR_SCHEMA_VERSION = "2.2"; + private static final String CURRENT_SOLR_SCHEMA_VERSION = "2.1"; static String getCurrentSolrVersion() { return CURRENT_SOLR_VERSION; diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java index be0b93088d..bcdf143697 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java @@ -20,10 +20,8 @@ package org.sleuthkit.autopsy.keywordsearch; import java.io.BufferedReader; import java.io.Reader; -import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Optional; import java.util.logging.Level; import org.apache.commons.lang3.math.NumberUtils; import org.apache.solr.client.solrj.SolrServerException; @@ -61,8 +59,6 @@ class Ingester { private final Server solrServer = KeywordSearch.getServer(); private static final SolrFieldsVisitor SOLR_FIELDS_VISITOR = new SolrFieldsVisitor(); private static Ingester instance; - private final LanguageSpecificContentIndexingHelper languageSpecificContentIndexingHelper - = new LanguageSpecificContentIndexingHelper(); private Ingester() { } @@ -97,7 +93,7 @@ class Ingester { * file, but the Solr server is probably fine. */ void indexMetaDataOnly(AbstractFile file) throws IngesterException { - indexChunk("", file.getName().toLowerCase(), new HashMap<>(getContentFields(file))); + indexChunk("", file.getName().toLowerCase(), getContentFields(file)); } /** @@ -111,7 +107,7 @@ class Ingester { * artifact, but the Solr server is probably fine. */ void indexMetaDataOnly(BlackboardArtifact artifact, String sourceName) throws IngesterException { - indexChunk("", sourceName, new HashMap<>(getContentFields(artifact))); + indexChunk("", sourceName, getContentFields(artifact)); } /** @@ -147,30 +143,21 @@ class Ingester { < T extends SleuthkitVisitableItem> boolean indexText(Reader sourceReader, long sourceID, String sourceName, T source, IngestJobContext context) throws Ingester.IngesterException { int numChunks = 0; //unknown until chunking is done - Map contentFields = Collections.unmodifiableMap(getContentFields(source)); + Map fields = getContentFields(source); //Get a reader for the content of the given source try (BufferedReader reader = new BufferedReader(sourceReader)) { Chunker chunker = new Chunker(reader); - while (chunker.hasNext()) { + for (Chunk chunk : chunker) { if (context != null && context.fileIngestIsCancelled()) { logger.log(Level.INFO, "File ingest cancelled. Cancelling keyword search indexing of {0}", sourceName); return false; } - - Chunk chunk = chunker.next(); - Map fields = new HashMap<>(contentFields); String chunkId = Server.getChunkIdString(sourceID, numChunks + 1); fields.put(Server.Schema.ID.toString(), chunkId); fields.put(Server.Schema.CHUNK_SIZE.toString(), String.valueOf(chunk.getBaseChunkLength())); - Optional language = languageSpecificContentIndexingHelper.detectLanguageIfNeeded(chunk); - language.ifPresent(lang -> languageSpecificContentIndexingHelper.updateLanguageSpecificFields(fields, chunk, lang)); try { //add the chunk text to Solr index indexChunk(chunk.toString(), sourceName, fields); - // add mini chunk when there's a language specific field - if (chunker.hasNext() && language.isPresent()) { - languageSpecificContentIndexingHelper.indexMiniChunk(chunk, sourceName, new HashMap<>(contentFields), chunkId, language.get()); - } numChunks++; } catch (Ingester.IngesterException ingEx) { logger.log(Level.WARNING, "Ingester had a problem with extracted string from file '" //NON-NLS @@ -190,7 +177,6 @@ class Ingester { if (context != null && context.fileIngestIsCancelled()) { return false; } else { - Map fields = new HashMap<>(contentFields); //after all chunks, index just the meta data, including the numChunks, of the parent file fields.put(Server.Schema.NUM_CHUNKS.toString(), Integer.toString(numChunks)); //reset id field to base document id @@ -216,7 +202,7 @@ class Ingester { * * @throws org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException */ - private void indexChunk(String chunk, String sourceName, Map fields) throws IngesterException { + private void indexChunk(String chunk, String sourceName, Map fields) throws IngesterException { if (fields.get(Server.Schema.IMAGE_ID.toString()) == null) { //JMTODO: actually if the we couldn't get the image id it is set to -1, // but does this really mean we don't want to index it? diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Language.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Language.java deleted file mode 100644 index 5fb1f859d3..0000000000 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Language.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2019 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.keywordsearch; - -import java.util.Arrays; -import java.util.Optional; - -/** - * Language. - * - * Contents which are detected to have these languages should be indexed to a corresponding language-specific field - * such as content_ja. - */ -public enum Language { - JAPANESE("ja"); - - private String value; - - String getValue() { - return value; - } - - static Optional fromValue(String value) { - return Arrays.stream(Language.values()).filter(x -> x.value.equals(value)).findFirst(); - } - - Language(String value) { - this.value = value; - } -} diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LanguageDetector.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LanguageDetector.java deleted file mode 100644 index f527a2fc0e..0000000000 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LanguageDetector.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2019 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.keywordsearch; - -import com.optimaize.langdetect.LanguageDetectorBuilder; -import com.optimaize.langdetect.i18n.LdLocale; -import com.optimaize.langdetect.ngram.NgramExtractors; -import com.optimaize.langdetect.profiles.LanguageProfileReader; -import com.optimaize.langdetect.text.CommonTextObjectFactories; -import com.optimaize.langdetect.text.TextObject; -import com.optimaize.langdetect.text.TextObjectFactory; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.util.Optional; - -/** - * Detects the language of the given contents. Only languages which should be indexed to a corresponding - * language-specific field are detected. - */ -class LanguageDetector { - - private com.optimaize.langdetect.LanguageDetector impl; - private TextObjectFactory textObjectFactory; - - LanguageDetector() { - try { - impl = LanguageDetectorBuilder.create(NgramExtractors.standard()) - .withProfiles(new LanguageProfileReader().readAllBuiltIn()) - .build(); - textObjectFactory = CommonTextObjectFactories.forDetectingOnLargeText(); - } catch (IOException e) { - // The IOException here could occur when failing to read the language profiles from the classpath. - // That can be considered to be a severe IO problem. Nothing can be done here. - throw new UncheckedIOException(e); - } - } - - Optional detect(String text) { - TextObject textObject = textObjectFactory.forText(text); - Optional localeOpt = impl.detect(textObject).transform(Optional::of).or(Optional.empty()); - return localeOpt.map(LdLocale::getLanguage).flatMap(Language::fromValue); - } -} diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LanguageSpecificContentIndexingHelper.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LanguageSpecificContentIndexingHelper.java deleted file mode 100644 index d0988c83f3..0000000000 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LanguageSpecificContentIndexingHelper.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2019 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.keywordsearch; - -import org.apache.commons.lang3.math.NumberUtils; -import org.apache.solr.common.SolrInputDocument; -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.healthmonitor.HealthMonitor; -import org.sleuthkit.autopsy.healthmonitor.TimingMetric; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -/** - * A helper class to support indexing language-specific fields. - */ -class LanguageSpecificContentIndexingHelper { - - private final LanguageDetector languageDetector = new LanguageDetector(); - - Optional detectLanguageIfNeeded(Chunker.Chunk chunk) throws NoOpenCoreException { - double indexSchemaVersion = NumberUtils.toDouble(KeywordSearch.getServer().getIndexInfo().getSchemaVersion()); - if (2.2 <= indexSchemaVersion) { - return languageDetector.detect(chunk.toString()); - } else { - return Optional.empty(); - } - } - - void updateLanguageSpecificFields(Map fields, Chunker.Chunk chunk, Language language) { - List values = new ArrayList<>(); - values.add(chunk.toString()); - if (fields.containsKey(Server.Schema.FILE_NAME.toString())) { - values.add(fields.get(Server.Schema.FILE_NAME.toString()).toString()); - } - - // index the chunk to a language specific field - fields.put(Server.Schema.CONTENT_JA.toString(), values); - fields.put(Server.Schema.LANGUAGE.toString(), language.getValue()); - } - - void indexMiniChunk(Chunker.Chunk chunk, String sourceName, Map fields, String baseChunkID, Language language) - throws Ingester.IngesterException { - //Make a SolrInputDocument out of the field map - SolrInputDocument updateDoc = new SolrInputDocument(); - for (String key : fields.keySet()) { - updateDoc.addField(key, fields.get(key)); - } - - try { - updateDoc.setField(Server.Schema.ID.toString(), MiniChunkHelper.getChunkIdString(baseChunkID)); - - // index the chunk to a language specific field - updateDoc.addField(Server.Schema.CONTENT_JA.toString(), chunk.toString().substring(chunk.getBaseChunkLength())); - updateDoc.addField(Server.Schema.LANGUAGE.toString(), language.getValue()); - - TimingMetric metric = HealthMonitor.getTimingMetric("Solr: Index chunk"); - - KeywordSearch.getServer().addDocument(updateDoc); - HealthMonitor.submitTimingMetric(metric); - - } catch (KeywordSearchModuleException | NoOpenCoreException ex) { - throw new Ingester.IngesterException( - NbBundle.getMessage(Ingester.class, "Ingester.ingest.exception.err.msg", sourceName), ex); - } - } -} diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LanguageSpecificContentQueryHelper.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LanguageSpecificContentQueryHelper.java deleted file mode 100644 index a3ed8a7876..0000000000 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LanguageSpecificContentQueryHelper.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2019 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.keywordsearch; - -import org.apache.solr.client.solrj.SolrQuery; -import org.apache.solr.client.solrj.SolrRequest; -import org.apache.solr.client.solrj.response.QueryResponse; -import org.apache.solr.common.SolrDocument; -import org.apache.solr.common.SolrDocumentList; -import org.sleuthkit.autopsy.coreutils.EscapeUtil; -import org.sleuthkit.autopsy.coreutils.Version; -import org.sleuthkit.datamodel.TskException; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * A helper class to support querying documents which have language-specific fields. - */ -final class LanguageSpecificContentQueryHelper { - - private LanguageSpecificContentQueryHelper() {} - - private static final List QUERY_FIELDS = new ArrayList<>(); - private static final List LANGUAGE_SPECIFIC_CONTENT_FIELDS - = Collections.singletonList(Server.Schema.CONTENT_JA); - private static final boolean DEBUG = (Version.getBuildType() == Version.Type.DEVELOPMENT); - - static { - QUERY_FIELDS.add(Server.Schema.TEXT); - QUERY_FIELDS.addAll(LANGUAGE_SPECIFIC_CONTENT_FIELDS); - } - - /** - * Holds query response for later processes related to language-specific fields - */ - static class QueryResults { - List chunks = new ArrayList<>(); - Map miniChunks = new HashMap<>(); - // objectId_chunk -> "text" -> List of previews - Map>> highlighting = new HashMap<>(); - } - - /** - * Make a query string from the given one by applying it to the multiple query fields - * - * @param queryStr escaped query string - * @return query string - */ - static String expandQueryString(final String queryStr) { - List fieldQueries = new ArrayList<>(); - fieldQueries.add(Server.Schema.TEXT.toString() + ":" + queryStr); - fieldQueries.addAll(LANGUAGE_SPECIFIC_CONTENT_FIELDS.stream().map(field -> field.toString() + ":" + queryStr).collect(Collectors.toList())); - return String.join(" OR ", fieldQueries); - } - - static List getQueryFields() { - return QUERY_FIELDS; - } - - static void updateQueryResults(QueryResults results, SolrDocument document) { - String id = (String) document.getFieldValue(Server.Schema.ID.toString()); - if (MiniChunkHelper.isMiniChunkID(id)) { - results.miniChunks.put(MiniChunkHelper.getBaseChunkID(id), document); - } else { - results.chunks.add(document); - } - } - - /** - * Get snippets - * - * @param highlight field ID -> snippets - * @return snippets of appropriate fields. - * Note that this method returns {@code Optional.empty} if the result is empty for convenience to interact with the existing code. - */ - static Optional> getHighlights(Map> highlight) { - for (Server.Schema field : LANGUAGE_SPECIFIC_CONTENT_FIELDS) { - if (highlight.containsKey(field.toString())) { - return Optional.of(highlight.get(field.toString())); - } - } - return Optional.empty(); - } - - /** - * Merge KeywordHits from TEXT field and a language specific field - * - * Replace KeywordHits in the given {@code matches} if its chunk ID is same. - */ - static List mergeKeywordHits(List matches, Keyword originalKeyword, QueryResults queryResults) throws KeywordSearchModuleException { - Map map = findMatches(originalKeyword, queryResults).stream().collect(Collectors.toMap(KeywordHit::getSolrDocumentId, x -> x)); - List merged = new ArrayList<>(); - - // first, replace KeywordHit in matches - for (KeywordHit match : matches) { - String key = match.getSolrDocumentId(); - if (map.containsKey(key)) { - merged.add(map.get(key)); - map.remove(key); - } else { - merged.add(match); - } - } - // second, add rest of KeywordHits from queryResults - merged.addAll(map.values()); - - return merged; - } - - static void configureTermfreqQuery(SolrQuery query, String keyword) throws KeywordSearchModuleException, NoOpenCoreException { - // make a request to Solr to parse query. - QueryTermHelper.Result queryParserResult = QueryTermHelper.parse(keyword, LANGUAGE_SPECIFIC_CONTENT_FIELDS); - query.addField(buildTermfreqQuery(keyword, queryParserResult)); - } - - static String buildTermfreqQuery(String keyword, QueryTermHelper.Result result) { - List termfreqs = new ArrayList<>(); - for (Map.Entry> e : result.fieldTermsMap.entrySet()) { - String field = e.getKey(); - for (String term : e.getValue()) { - termfreqs.add(String.format("termfreq(\"%s\",\"%s\")", field, KeywordSearchUtil.escapeLuceneQuery(term))); - } - } - - // sum of all language specific query fields. - // only one of these fields could be non-zero. - return String.format("termfreq:sum(%s)", String.join(",", termfreqs)); - } - - static int queryChunkTermfreq(Set keywords, String contentID) throws KeywordSearchModuleException, NoOpenCoreException { - SolrQuery q = new SolrQuery(); - q.setShowDebugInfo(DEBUG); - - final String filterQuery = Server.Schema.ID.toString() + ":" + KeywordSearchUtil.escapeLuceneQuery(contentID); - final String highlightQuery = keywords.stream() - .map(s -> LanguageSpecificContentQueryHelper.expandQueryString( - KeywordSearchUtil.quoteQuery(KeywordSearchUtil.escapeLuceneQuery(s)))) - .collect(Collectors.joining(" ")); - - q.addFilterQuery(filterQuery); - q.setQuery(highlightQuery); - LanguageSpecificContentQueryHelper.configureTermfreqQuery(q, keywords.iterator().next()); - - QueryResponse response = KeywordSearch.getServer().query(q, SolrRequest.METHOD.POST); - SolrDocumentList results = response.getResults(); - if (results.isEmpty()) { - return 0; - } - - SolrDocument document = results.get(0); - return ((Float) document.getFieldValue(Server.Schema.TERMFREQ.toString())).intValue(); - } - - static int findNthIndexOf(String s, String pattern, int n) { - int found = 0; - int idx = -1; - int len = s.length(); - while (idx < len && found <= n) { - idx = s.indexOf(pattern, idx + 1); - if (idx == -1) { - break; - } - found++; - } - - return idx; - } - - private static List findMatches(Keyword originalKeyword, QueryResults queryResults) throws KeywordSearchModuleException { - List matches = new ArrayList<>(); - for (SolrDocument document : queryResults.chunks) { - String docId = (String) document.getFieldValue(Server.Schema.ID.toString()); - - try { - int hitCountInChunk = ((Float) document.getFieldValue(Server.Schema.TERMFREQ.toString())).intValue(); - SolrDocument miniChunk = queryResults.miniChunks.get(docId); - if (miniChunk == null) { - // last chunk does not have mini chunk because there's no overlapped region with next one - matches.add(createKeywordHit(originalKeyword, queryResults.highlighting, docId)); - } else { - int hitCountInMiniChunk = ((Float) miniChunk.getFieldValue(Server.Schema.TERMFREQ.toString())).intValue(); - if (hitCountInMiniChunk < hitCountInChunk) { - // there are at least one hit in base chunk - matches.add(createKeywordHit(originalKeyword, queryResults.highlighting, docId)); - } - } - } catch (TskException ex) { - throw new KeywordSearchModuleException(ex); - } - } - return matches; - } - - /** - * copied from LuceneQuery and modified to use getHighlightFieldValue - */ - private static KeywordHit createKeywordHit(Keyword originalKeyword, Map>> highlightResponse, String docId) throws TskException { - /** - * Get the first snippet from the document if keyword search is - * configured to use snippets. - */ - String snippet = ""; - if (KeywordSearchSettings.getShowSnippets()) { - List snippetList = getHighlightFieldValue(highlightResponse.get(docId)).orElse(null); - // list is null if there wasn't a snippet - if (snippetList != null) { - snippet = EscapeUtil.unEscapeHtml(snippetList.get(0)).trim(); - } - } - - return new KeywordHit(docId, snippet, originalKeyword.getSearchTerm()); - } - - /** - * @return Optional.empty if empty - */ - private static Optional> getHighlightFieldValue(Map> highlight) { - for (Server.Schema field : LANGUAGE_SPECIFIC_CONTENT_FIELDS) { - if (highlight.containsKey(field.toString())) { - return Optional.of(highlight.get(field.toString())); - } - } - return Optional.empty(); - } -} diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java index a324c03324..70c6155d5f 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/LuceneQuery.java @@ -134,7 +134,6 @@ class LuceneQuery implements KeywordSearchQuery { String cursorMark = CursorMarkParams.CURSOR_MARK_START; boolean allResultsProcessed = false; List matches = new ArrayList<>(); - LanguageSpecificContentQueryHelper.QueryResults languageSpecificQueryResults = new LanguageSpecificContentQueryHelper.QueryResults(); while (!allResultsProcessed) { solrQuery.set(CursorMarkParams.CURSOR_MARK_PARAM, cursorMark); QueryResponse response = solrServer.query(solrQuery, SolrRequest.METHOD.POST); @@ -142,18 +141,7 @@ class LuceneQuery implements KeywordSearchQuery { // objectId_chunk -> "text" -> List of previews Map>> highlightResponse = response.getHighlighting(); - if (2.2 <= indexSchemaVersion) { - languageSpecificQueryResults.highlighting.putAll(response.getHighlighting()); - } - for (SolrDocument resultDoc : resultList) { - if (2.2 <= indexSchemaVersion) { - Object language = resultDoc.getFieldValue(Server.Schema.LANGUAGE.toString()); - if (language != null) { - LanguageSpecificContentQueryHelper.updateQueryResults(languageSpecificQueryResults, resultDoc); - } - } - try { /* * for each result doc, check that the first occurence of @@ -165,11 +153,6 @@ class LuceneQuery implements KeywordSearchQuery { final Integer chunkSize = (Integer) resultDoc.getFieldValue(Server.Schema.CHUNK_SIZE.toString()); final Collection content = resultDoc.getFieldValues(Server.Schema.CONTENT_STR.toString()); - // if the document has language, it should be hit in language specific content fields. So skip here. - if (resultDoc.containsKey(Server.Schema.LANGUAGE.toString())) { - continue; - } - if (indexSchemaVersion < 2.0) { //old schema versions don't support chunk_size or the content_str fields, so just accept hits matches.add(createKeywordtHit(highlightResponse, docId)); @@ -196,16 +179,9 @@ class LuceneQuery implements KeywordSearchQuery { cursorMark = nextCursorMark; } - List mergedMatches; - if (2.2 <= indexSchemaVersion) { - mergedMatches = LanguageSpecificContentQueryHelper.mergeKeywordHits(matches, originalKeyword, languageSpecificQueryResults); - } else { - mergedMatches = matches; - } - QueryResults results = new QueryResults(this); //in case of single term literal query there is only 1 term - results.addResult(new Keyword(originalKeyword.getSearchTerm(), true, true, originalKeyword.getListName(), originalKeyword.getOriginalTerm()), mergedMatches); + results.addResult(new Keyword(originalKeyword.getSearchTerm(), true, true, originalKeyword.getListName(), originalKeyword.getOriginalTerm()), matches); return results; } @@ -286,25 +262,19 @@ class LuceneQuery implements KeywordSearchQuery { * * @return */ - private SolrQuery createAndConfigureSolrQuery(boolean snippets) throws NoOpenCoreException, KeywordSearchModuleException { - double indexSchemaVersion = NumberUtils.toDouble(KeywordSearch.getServer().getIndexInfo().getSchemaVersion()); - + private SolrQuery createAndConfigureSolrQuery(boolean snippets) { SolrQuery q = new SolrQuery(); q.setShowDebugInfo(DEBUG); //debug // Wrap the query string in quotes if this is a literal search term. String queryStr = originalKeyword.searchTermIsLiteral() - ? KeywordSearchUtil.quoteQuery(keywordStringEscaped) : keywordStringEscaped; + ? KeywordSearchUtil.quoteQuery(keywordStringEscaped) : keywordStringEscaped; // Run the query against an optional alternative field. if (field != null) { //use the optional field queryStr = field + ":" + queryStr; - q.setQuery(queryStr); - } else if (2.2 <= indexSchemaVersion && originalKeyword.searchTermIsLiteral()) { - q.setQuery(LanguageSpecificContentQueryHelper.expandQueryString(queryStr)); - } else { - q.setQuery(queryStr); } + q.setQuery(queryStr); q.setRows(MAX_RESULTS_PER_CURSOR_MARK); // Setting the sort order is necessary for cursor based paging to work. q.setSort(SolrQuery.SortClause.asc(Server.Schema.ID.toString())); @@ -313,11 +283,6 @@ class LuceneQuery implements KeywordSearchQuery { Server.Schema.CHUNK_SIZE.toString(), Server.Schema.CONTENT_STR.toString()); - if (2.2 <= indexSchemaVersion && originalKeyword.searchTermIsLiteral()) { - q.addField(Server.Schema.LANGUAGE.toString()); - LanguageSpecificContentQueryHelper.configureTermfreqQuery(q, keywordStringEscaped); - } - for (KeywordQueryFilter filter : filters) { q.addFilterQuery(filter.toString()); } @@ -335,16 +300,8 @@ class LuceneQuery implements KeywordSearchQuery { * * @param q The SolrQuery to configure. */ - private static void configurwQueryForHighlighting(SolrQuery q) throws NoOpenCoreException { - double indexSchemaVersion = NumberUtils.toDouble(KeywordSearch.getServer().getIndexInfo().getSchemaVersion()); - if (2.2 <= indexSchemaVersion) { - for (Server.Schema field : LanguageSpecificContentQueryHelper.getQueryFields()) { - q.addHighlightField(field.toString()); - } - } else { - q.addHighlightField(HIGHLIGHT_FIELD); - } - + private static void configurwQueryForHighlighting(SolrQuery q) { + q.addHighlightField(HIGHLIGHT_FIELD); q.setHighlightSnippets(1); q.setHighlightFragsize(SNIPPET_LENGTH); @@ -447,13 +404,7 @@ class LuceneQuery implements KeywordSearchQuery { if (responseHighlightID == null) { return ""; } - double indexSchemaVersion = NumberUtils.toDouble(solrServer.getIndexInfo().getSchemaVersion()); - List contentHighlights; - if (2.2 <= indexSchemaVersion) { - contentHighlights = LanguageSpecificContentQueryHelper.getHighlights(responseHighlightID).orElse(null); - } else { - contentHighlights = responseHighlightID.get(LuceneQuery.HIGHLIGHT_FIELD); - } + List contentHighlights = responseHighlightID.get(LuceneQuery.HIGHLIGHT_FIELD); if (contentHighlights == null) { return ""; } else { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/MiniChunkHelper.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/MiniChunkHelper.java deleted file mode 100644 index 9e958587cd..0000000000 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/MiniChunkHelper.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2019 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.keywordsearch; - -/** - * Mini-chunk related methods. - */ -final class MiniChunkHelper { - - private MiniChunkHelper() {} - - static String SUFFIX = "_mini"; - - static String getChunkIdString(String baseChunkID) { - return baseChunkID + SUFFIX; - } - - static boolean isMiniChunkID(String chunkID) { - return chunkID.endsWith(SUFFIX); - } - - static String getBaseChunkID(String miniChunkID) { - return miniChunkID.replaceFirst(SUFFIX + "$", ""); - } -} diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryTermHelper.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryTermHelper.java deleted file mode 100644 index 39a050c47f..0000000000 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/QueryTermHelper.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2019 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.keywordsearch; - -import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.request.FieldAnalysisRequest; -import org.apache.solr.client.solrj.response.AnalysisResponseBase; -import org.apache.solr.client.solrj.response.FieldAnalysisResponse; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * Get terms from query using Solr. - * - * This class is used to find matched terms from query results. - */ -final class QueryTermHelper { - - private QueryTermHelper() {} - - /** - * Result of {@link #parse} method - */ - static class Result { - /** - * field name -> [term] - */ - final Map> fieldTermsMap = new HashMap<>(); - } - - /** - * Parse the given query string on Solr and return the result - * - * @param query query to parse - * @param fields field names to use for parsing - */ - static Result parse(String query, List fields) throws KeywordSearchModuleException, NoOpenCoreException { - Server server = KeywordSearch.getServer(); - - FieldAnalysisRequest request = new FieldAnalysisRequest(); - for (Server.Schema field : fields) { - request.addFieldName(field.toString()); - } - // FieldAnalysisRequest requires to set its field value property, - // while the corresponding analysis.fieldvalue parameter is not needed in the API. - // Setting an empty value does not effect on the result. - request.setFieldValue(""); - request.setQuery(query); - - FieldAnalysisResponse response = new FieldAnalysisResponse(); - try { - response.setResponse(server.request(request)); - } catch (SolrServerException e) { - throw new KeywordSearchModuleException(e); - } - - Result result = new Result(); - for (Map.Entry entry : response.getAllFieldNameAnalysis()) { - Iterator it = entry.getValue().getQueryPhases().iterator(); - - // The last phase is the one which is used in the search process. - AnalysisResponseBase.AnalysisPhase lastPhase = null; - while (it.hasNext()) { - lastPhase = it.next(); - } - - if (lastPhase != null) { - List tokens = lastPhase.getTokens().stream().map(AnalysisResponseBase.TokenInfo::getText).collect(Collectors.toList()); - result.fieldTermsMap.put(entry.getKey(), tokens); - } - } - - return result; - } -} diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java index 2db4bd6638..0e047456f6 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java @@ -130,18 +130,6 @@ public class Server { return "content_ws"; //NON-NLS } }, - CONTENT_JA { - @Override - public String toString() { - return "content_ja"; //NON-NLS - } - }, - LANGUAGE { - @Override - public String toString() { - return "language"; //NON-NLS - } - }, FILE_NAME { @Override public String toString() { @@ -187,17 +175,6 @@ public class Server { public String toString() { return "chunk_size"; //NON-NLS } - }, - /** - * termfreq is a function which returns the number of times the term appears. - * This is not an actual field defined in schema.xml, but can be gotten from returned documents - * in the same way as fields. - */ - TERMFREQ { - @Override - public String toString() { - return "termfreq"; //NON-NLS - } } }; @@ -1658,8 +1635,7 @@ public class Server { private int queryNumFileChunks(long contentID) throws SolrServerException, IOException { String id = KeywordSearchUtil.escapeLuceneQuery(Long.toString(contentID)); final SolrQuery q - = new SolrQuery(Server.Schema.ID + ":" + id + Server.CHUNK_ID_SEPARATOR + "*" - + " NOT " + Server.Schema.ID + ":*" + MiniChunkHelper.SUFFIX); + = new SolrQuery(Server.Schema.ID + ":" + id + Server.CHUNK_ID_SEPARATOR + "*"); q.setRows(0); return (int) query(q).getResults().getNumFound(); } diff --git a/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/LanguageSpecificContentQueryHelperTest.java b/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/LanguageSpecificContentQueryHelperTest.java deleted file mode 100644 index d8c876592e..0000000000 --- a/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/LanguageSpecificContentQueryHelperTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2019 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.keywordsearch; - -import org.junit.Test; - -import java.util.Arrays; - -import static org.junit.Assert.assertEquals; - -/** - * tests for LanguageSpecificContentQueryHelper - */ -public class LanguageSpecificContentQueryHelperTest { - - @Test - public void makeQueryString() { - assertEquals("text:query OR content_ja:query", LanguageSpecificContentQueryHelper.expandQueryString("query")); - } - - @Test - public void findNthIndexOf() { - assertEquals(-1, LanguageSpecificContentQueryHelper.findNthIndexOf("A1AA45", "_", 0)); - assertEquals(0, LanguageSpecificContentQueryHelper.findNthIndexOf("A1AA45", "A", 0)); - assertEquals(2, LanguageSpecificContentQueryHelper.findNthIndexOf("A1AA45", "A", 1)); - assertEquals(3, LanguageSpecificContentQueryHelper.findNthIndexOf("A1AA45", "A", 2)); - assertEquals(-1, LanguageSpecificContentQueryHelper.findNthIndexOf("A1AA45", "A", 3)); - assertEquals(0, LanguageSpecificContentQueryHelper.findNthIndexOf("A1AA45", "", 0)); - assertEquals(-1, LanguageSpecificContentQueryHelper.findNthIndexOf("", "A", 0)); - assertEquals(-1, LanguageSpecificContentQueryHelper.findNthIndexOf("A1AA45", "A", -1)); - assertEquals(-1, LanguageSpecificContentQueryHelper.findNthIndexOf("A1AA45", "A", 999)); - } - - @Test - public void buildTermfreqQuery() { - QueryTermHelper.Result result = new QueryTermHelper.Result(); - result.fieldTermsMap.put("field1", Arrays.asList("term1")); - result.fieldTermsMap.put("field2", Arrays.asList("term1", "term2")); - assertEquals( - "termfreq:sum(termfreq(\"field1\",\"term1\"),termfreq(\"field2\",\"term1\"),termfreq(\"field2\",\"term2\"))", - LanguageSpecificContentQueryHelper.buildTermfreqQuery("query", result)); - } -} diff --git a/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/MiniChunkHelperTest.java b/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/MiniChunkHelperTest.java deleted file mode 100644 index 27336b8297..0000000000 --- a/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/MiniChunkHelperTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011-2019 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.keywordsearch; - -import org.junit.Assert; -import org.junit.Test; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * tests for MiniChunkHelper - */ -public class MiniChunkHelperTest { - - @Test - public void isMiniChunkID() { - assertTrue(MiniChunkHelper.isMiniChunkID("1_1_mini")); - assertFalse(MiniChunkHelper.isMiniChunkID("1_1")); - assertFalse(MiniChunkHelper.isMiniChunkID("1")); - } - - @Test - public void getBaseChunkID() { - Assert.assertEquals("1_1", MiniChunkHelper.getBaseChunkID("1_1_mini")); - Assert.assertEquals("1_1", MiniChunkHelper.getBaseChunkID("1_1")); - Assert.assertEquals("1", MiniChunkHelper.getBaseChunkID("1")); - } - -} \ No newline at end of file From 4cfd8a9ab0579693a36aaeb4357fb5b1ce4c5de0 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Wed, 25 Sep 2019 12:00:47 -0400 Subject: [PATCH 06/17] 5587: Error from ShareIt module - filter out Null & blank strings while appending attachments list to msg body. --- InternalPythonModules/android/general.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InternalPythonModules/android/general.py b/InternalPythonModules/android/general.py index 53c123d13c..e8cb199b8d 100644 --- a/InternalPythonModules/android/general.py +++ b/InternalPythonModules/android/general.py @@ -34,6 +34,6 @@ def appendAttachmentList(msgBody, attachmentsList): body = msgBody if attachmentsList: body = body + "\n\n------------Attachments------------\n" - body = body + "\n".join(attachmentsList) + body = body + "\n".join(list(filter(None, attachmentsList))) return body From bb8d29cc9b16288a993e009c70f216cf745cb523 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Wed, 25 Sep 2019 12:02:20 -0400 Subject: [PATCH 07/17] Made exception fire wall message more general --- .../src/org/sleuthkit/autopsy/keywordsearch/Ingester.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java index be0b93088d..2d5ae4941b 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Ingester.java @@ -184,7 +184,7 @@ class Ingester { return false; } } catch (Exception ex) { - logger.log(Level.WARNING, "Unexpected error, can't read content stream from " + sourceID + ": " + sourceName, ex);//NON-NLS + logger.log(Level.WARNING, "Unexpected error while indexing content from " + sourceID + ": " + sourceName, ex);//NON-NLS return false; } finally { if (context != null && context.fileIngestIsCancelled()) { From 2df6288aec82da9f549780241b2da8c858e2bb36 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 25 Sep 2019 13:04:42 -0400 Subject: [PATCH 08/17] 5572 improve logging for correlation attribute failure to include info about artifact --- .../centralrepository/datamodel/EamArtifactUtil.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java index 98914afeec..18a21d0ab6 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java @@ -211,8 +211,11 @@ public class EamArtifactUtil { TskData.FileKnown.UNKNOWN, bbSourceFile.getId()); - } catch (TskCoreException | EamDbException | CorrelationAttributeNormalizationException ex) { - logger.log(Level.SEVERE, "Error creating artifact instance.", ex); // NON-NLS + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error getting AbstractFile for artifact: " + bbArtifact.toString(), ex); // NON-NLS + return null; + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + logger.log(Level.WARNING, "Error creating artifact instance for artifact: " + bbArtifact.toString(), ex); // NON-NLS return null; } catch (NoCurrentCaseException ex) { logger.log(Level.SEVERE, "Case is closed.", ex); // NON-NLS From 8d1a4a5f163d0dc433acbb9782f712124b1f413e Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 25 Sep 2019 14:03:39 -0400 Subject: [PATCH 09/17] Fixed issue with eml and mbox files --- .../autopsy/thunderbirdparser/Bundle.properties-MERGED | 3 --- .../sleuthkit/autopsy/thunderbirdparser/EMLParser.java | 4 ---- .../autopsy/thunderbirdparser/MimeJ4MessageParser.java | 10 +++++++++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/Bundle.properties-MERGED b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/Bundle.properties-MERGED index aa01a19072..18a00e9d3e 100755 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/Bundle.properties-MERGED +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/Bundle.properties-MERGED @@ -1,4 +1,3 @@ -MboxParser.handleAttch.noOpenCase.errMsg=Exception while getting open case. MimeJ4MessageParser.handleAttch.noOpenCase.errMsg=Exception while getting open case. OpenIDE-Module-Display-Category=Ingest Module OpenIDE-Module-Long-Description=Email Parser ingest module.\n\nThe module extracts MBOX and PST e-mail files and posts the results to the blackboard.\nIt knows about the Thunderbird folder structure for MBOX files. @@ -13,8 +12,6 @@ PstParser.noOpenCase.errMsg=Exception while getting open case. PstParser.parse.errMsg.failedToParseNMsgs=Failed to extract {0} email messages. PstParser.extractAttch.errMsg.failedToExtractToDisk=Failed to extract PST attachment to disk: {0} ThunderbirdMboxFileIngestModule.addArtifact.indexError.message=Failed to index email message detected artifact for keyword search. -# {0} - file name -# {1} - file ID ThunderbirdMboxFileIngestModule.errorMessage.outOfDiskSpace=Out of disk space. Cannot copy '{0}' (id={1}) to parse. ThunderbirdMboxFileIngestModule.moduleName=Email Parser ThunderbirdMboxFileIngestModule.noOpenCase.errMsg=Exception while getting open case. diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/EMLParser.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/EMLParser.java index e0b50ffa8c..4003144685 100755 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/EMLParser.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/EMLParser.java @@ -43,10 +43,6 @@ class EMLParser extends MimeJ4MessageParser { static boolean isEMLFile(AbstractFile abFile, byte[] buffer) { String ext = abFile.getNameExtension(); boolean isEMLFile = ext != null && ext.equals("eml"); - if (isEMLFile) { - isEMLFile = (new String(buffer)).contains("To:"); //NON-NLS - } - return isEMLFile; } diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/MimeJ4MessageParser.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/MimeJ4MessageParser.java index 1114d71eba..4fb1d5fad7 100755 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/MimeJ4MessageParser.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/MimeJ4MessageParser.java @@ -298,7 +298,15 @@ class MimeJ4MessageParser { logger.log(Level.SEVERE, Bundle.MimeJ4MessageParser_handleAttch_noOpenCase_errMsg(), ex); //NON-NLS return; } - String filename = FileUtil.escapeFileName(e.getFilename()); + String filename = e.getFilename(); + + if (filename == null) { + filename = "attachment" + e.hashCode(); + logger.log(Level.WARNING, String.format("Attachment has no file name using '%s'", filename)); + filename = "attachment" + e.hashCode(); + } + + filename = FileUtil.escapeFileName(filename); // also had some crazy long names, so make random one if we get those. // also from Japanese image that had encoded name From 1de1b9f5d8b258fda865df9b0541b53ebac82f41 Mon Sep 17 00:00:00 2001 From: Kelly Kelly Date: Wed, 25 Sep 2019 14:43:50 -0400 Subject: [PATCH 10/17] fixed exceptions --- .../autopsy/recentactivity/ExtractRegistry.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index b7d168147c..0f6b4ec926 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -865,13 +865,13 @@ class ExtractRegistry extends Extract { } // for return true; } catch (FileNotFoundException ex) { - logger.log(Level.SEVERE, String.format("Error finding the registry file: %s", regFilePath), ex); //NON-NLS + logger.log(Level.WARNING, String.format("Error finding the registry file: %s", regFilePath), ex); //NON-NLS } catch (SAXException ex) { - logger.log(Level.SEVERE, String.format("Error parsing the registry XML: %s", regFilePath), ex); //NON-NLS + logger.log(Level.WARNING, String.format("Error parsing the registry XML: %s", regFilePath), ex); //NON-NLS } catch (IOException ex) { - logger.log(Level.SEVERE, String.format("Error building the document parser: %s", regFilePath), ex); //NON-NLS + logger.log(Level.WARNING, String.format("Error building the document parser: %s", regFilePath), ex); //NON-NLS } catch (ParserConfigurationException ex) { - logger.log(Level.SEVERE, String.format("Error configuring the registry parser: %s", regFilePath), ex); //NON-NLS + logger.log(Level.WARNING, String.format("Error configuring the registry parser: %s", regFilePath), ex); //NON-NLS } finally { try { if (fstream != null) { @@ -947,13 +947,13 @@ class ExtractRegistry extends Extract { } return true; } catch (FileNotFoundException ex) { - logger.log(Level.SEVERE, "Error finding the registry file.", ex); //NON-NLS + logger.log(Level.WARNING, "Error finding the registry file.", ex); //NON-NLS } catch (IOException ex) { - logger.log(Level.SEVERE, "Error building the document parser: {0}", ex); //NON-NLS + logger.log(Level.WARNING, "Error building the document parser: {0}", ex); //NON-NLS } catch (ParseException ex) { - logger.log(Level.SEVERE, "Error parsing the the date from the registry file", ex); //NON-NLS + logger.log(Level.WARNING, "Error parsing the the date from the registry file", ex); //NON-NLS } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error updating TSK_OS_ACCOUNT artifacts to include newly parsed data.", ex); //NON-NLS + logger.log(Level.WARNING, "Error updating TSK_OS_ACCOUNT artifacts to include newly parsed data.", ex); //NON-NLS } finally { postArtifacts(newArtifacts); } From e5d71e419b2ea393d554e49e8ba1177f86ce1b2c Mon Sep 17 00:00:00 2001 From: esaunders Date: Wed, 25 Sep 2019 17:30:05 -0400 Subject: [PATCH 11/17] Moved Gst.init() call out of constructor because it was conflicting with other glib initialization on Linux which ultimately caused Autopsy to crash. --- .../autopsy/contentviewers/MediaPlayerPanel.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaPlayerPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaPlayerPanel.java index 5e0c85e807..1b30c49ef4 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaPlayerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaPlayerPanel.java @@ -187,7 +187,6 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie */ public MediaPlayerPanel() throws GstException, UnsatisfiedLinkError { initComponents(); - initGst(); customizeComponents(); } @@ -251,11 +250,6 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie }; } - private void initGst() throws GstException, UnsatisfiedLinkError { - logger.log(Level.INFO, "Attempting initializing of gstreamer for video/audio viewing"); //NON-NLS - Gst.init(); - } - /** * Loads the file by spawning off a background task to handle file copying * and video component initializations. @@ -453,6 +447,12 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie if(this.isCancelled()) { return; } + + // Initialize Gstreamer. It is safe to call this for every file. + // It was moved here from the constructor because having it happen + // earlier resulted in conflicts on Linux. + Gst.init(); + //Video is ready for playback. Create new components gstPlayBin = new PlayBin("VideoPlayer", tempFile.toURI()); //Configure event handling From 2dd6a622073537979ac80b9f9abc5d758bac9e38 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Wed, 25 Sep 2019 18:41:37 -0400 Subject: [PATCH 12/17] 5564: Confusing contacts associated with account - Fixed SQL query for the contacts to correctly skip over users own account --- InternalPythonModules/android/fbmessenger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InternalPythonModules/android/fbmessenger.py b/InternalPythonModules/android/fbmessenger.py index 765d727e1a..bde2aeae4f 100644 --- a/InternalPythonModules/android/fbmessenger.py +++ b/InternalPythonModules/android/fbmessenger.py @@ -91,7 +91,7 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): self._MODULE_NAME, contactsDb.getDBFile(), Account.Type.FACEBOOK) - contactsResultSet = contactsDb.runQuery("SELECT fbid, display_name FROM contacts WHERE added_time_ms <> " + self.selfAccountAddress.getUniqueID() ) + contactsResultSet = contactsDb.runQuery("SELECT fbid, display_name FROM contacts WHERE added_time_ms <> 0") if contactsResultSet is not None: while contactsResultSet.next(): contactsDBHelper.addContact( contactsResultSet.getString("fbid"), ## unique id for account From c8454e2f702b0304536b8f0786bf9a45a0741a87 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 26 Sep 2019 11:00:51 -0400 Subject: [PATCH 13/17] Updated solr log config --- docs/doxygen-user/images/log4j.PNG | Bin 22228 -> 19174 bytes docs/doxygen-user/multi-user/installSolr.dox | 17 ++++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/doxygen-user/images/log4j.PNG b/docs/doxygen-user/images/log4j.PNG index 15a4ba1113a58b9238159fc06356e33de4b3e223..c9800a1fe4cadb962ed9b31c051d83c0c91c7aaa 100644 GIT binary patch literal 19174 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 FV1jIMm!SXv literal 22228 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 O1R3bTb<4HwBmM~|A##}j diff --git a/docs/doxygen-user/multi-user/installSolr.dox b/docs/doxygen-user/multi-user/installSolr.dox index 9ef8e3c907..3d55f29efc 100644 --- a/docs/doxygen-user/multi-user/installSolr.dox +++ b/docs/doxygen-user/multi-user/installSolr.dox @@ -66,13 +66,16 @@ The following steps will configure Solr to run using an account that will have a \image html transientcache.PNG

4. Log Configuration: Edit "C:\Bitnami\solr-4.10.3-0\apache-solr\resources/log4j.properties" to configure Solr log settings: - - Increase the log rotation size threshold (_log4j\.appender\.file\.MaxFileSize_) from 4MB to 100MB. - - Remove the _CONSOLE_ appender from the _log4j\.rootLogger_ line. -

- The log file should end up looking like this (modified lines are highlighted in yellow -

- \image html log4j.PNG -

+
    +
  1. Increase the log rotation size threshold (_log4j\.appender\.file\.MaxFileSize_) from 4MB to 100MB. +
  2. Remove the _CONSOLE_ appender from the _log4j\.rootLogger_ line. +
  3. Add the line "log4j.logger.org.apache.solr.update.processor.LogUpdateProcessor=WARN". +
+The log file should end up looking like this (modified lines are highlighted in yellow + +\image html log4j.PNG + + 5. Schema Configuration: From an Autopsy installation, copy the following into "C:\Bitnami\solr-4.10.3-0\apache-solr\solr": - The folder "C:\Program Files\Autopsy-XXX(current version)\autopsy\solr\solr\configsets" - The folder "C:\Program Files\Autopsy-XXX(current version)\autopsy\solr\solr\lib" From 0be4a967b9344f13bb6b142f5e8b1f4e54966412 Mon Sep 17 00:00:00 2001 From: Raman Arora Date: Thu, 26 Sep 2019 12:55:53 -0400 Subject: [PATCH 14/17] 5588: additional attribute for contacts. --- InternalPythonModules/android/fbmessenger.py | 16 ++++++++++++---- InternalPythonModules/android/imo.py | 4 ++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/InternalPythonModules/android/fbmessenger.py b/InternalPythonModules/android/fbmessenger.py index bde2aeae4f..fec2f3d2ec 100644 --- a/InternalPythonModules/android/fbmessenger.py +++ b/InternalPythonModules/android/fbmessenger.py @@ -91,15 +91,23 @@ class FBMessengerAnalyzer(general.AndroidComponentAnalyzer): self._MODULE_NAME, contactsDb.getDBFile(), Account.Type.FACEBOOK) - contactsResultSet = contactsDb.runQuery("SELECT fbid, display_name FROM contacts WHERE added_time_ms <> 0") + contactsResultSet = contactsDb.runQuery("SELECT fbid, display_name, added_time_ms FROM contacts WHERE added_time_ms <> 0") if contactsResultSet is not None: while contactsResultSet.next(): - contactsDBHelper.addContact( contactsResultSet.getString("fbid"), ## unique id for account - contactsResultSet.getString("display_name"), ## contact name + fbid = contactsResultSet.getString("fbid") + contactAddress = Account.Address(contactsResultSet.getString("fbid"), contactsResultSet.getString("display_name")) + dateCreated = contactsResultSet.getLong("added_time_ms") / 1000 + + ## create additional attributes for contact. + additionalAttributes = ArrayList(); + additionalAttributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED, self._MODULE_NAME, dateCreated)) + + contactsDBHelper.addContact( contactAddress, ## contact account "", ## phone "", ## home phone "", ## mobile - "") ## email + "", ## email + additionalAttributes) except SQLException as ex: self._logger.log(Level.WARNING, "Error processing query result for account", ex) diff --git a/InternalPythonModules/android/imo.py b/InternalPythonModules/android/imo.py index 714c029445..7f0a18dcfa 100644 --- a/InternalPythonModules/android/imo.py +++ b/InternalPythonModules/android/imo.py @@ -99,8 +99,8 @@ class IMOAnalyzer(general.AndroidComponentAnalyzer): contactsResultSet = friendsDb.runQuery("SELECT buid, name FROM friends") if contactsResultSet is not None: while contactsResultSet.next(): - friendsDBHelper.addContact( contactsResultSet.getString("buid"), ## unique id for account - contactsResultSet.getString("name"), ## contact name + contactAddress = Account.Address(contactsResultSet.getString("buid"), contactsResultSet.getString("name")) + friendsDBHelper.addContact( contactAddress, ## contact address "", ## phone "", ## home phone "", ## mobile From 7c2a7c5b02d939735b2d8bf770893917930c954c Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 26 Sep 2019 12:58:08 -0400 Subject: [PATCH 15/17] Update logical imager doc --- .../images/LogicalImager/dsp_select.png | Bin 41677 -> 42067 bytes .../LogicalImager/main_config_panel.png | Bin 52848 -> 52795 bytes docs/doxygen-user/logical_imager.dox | 8 ++++++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/doxygen-user/images/LogicalImager/dsp_select.png b/docs/doxygen-user/images/LogicalImager/dsp_select.png index e05f677af802db3a1fcdd0ac7e8c6dacddca0c69..e40d9800445921f7871b493f47cb2db3bd598e28 100644 GIT binary patch delta 24212 zcmcG#cT`hb_cn^6pm+d}iU+fc5V@^Yk7&Tt8h41&w zy2Ewpcn6`hl58Q?Dp#3m_^cbR3)&$?%$%vrq!}1~hC4eaT95Ila=Q0c>f1^hmp<=i z5flw(eUXvak^W7Ql4E3f-ETwE*R7Fd_K{DH0tH9gejwmj!NELB%4kXY@yqoTe>8NF zHgMr%RP*@KkEE_@*B7X7L7vPu3%lK({(6W!?cpav z*v#kfLB4^4;#E0STfHZ9?gq=+&0XS4Zi73>&n5$mdu4 z>*@bN{4xXpn)|Gj;c+$)?VoFFYsG7)#pdaw2{CTzxXi#t!tmdb5$Tu^M)|Sby(?pQ zFJ(2L#fBf(li`?v>O82rK6Yz%_n#K5X9kb?NbWsquGGh~jU9lFAFL-KGUPpu=C)Hnwi@U{^#8drRQZ?D|7PF~+3^zKmlDsT_cGn@!wtG5pwj*lEPUEigsoS2jDhJ5s@bFYGH1=Q;4nBykDZ+9O!En_KTJm1~|1wJVYGt8q=<`=m!`~^}JLpoGGy`V1{u; zW(X`NGzSwGq9dXlZ4x>}m)bsVG85o|T;YU#;hH{r^782fNLqR8;)=&fZe>TWKRT`zsG)rZ2=*G)*Zh}j^ffodbUnz~t_k)MK@ed8q?gv;LUv#KZs#Umri zVWAQX7G=Q8V9;mF3F$Bq2Jk-`%v_gjg|?eLsiV8lj`US5$01jJS<_JgNzfSz3W^JG z3b8;a`~wwJXAG}So*eC{WYT&Z*0$pvclb4)l5*RssgORLqB@*fv!*om3eiag*%K<6i zO>w+*V$!1)`y@}-p;MvnM$Uu37(%UNcfnS{(6Zz-*3cZxvl@`Ri$|fVGz=rrhaBpizpva0*IgZX8N+?chy zYD{`B)=5R~-->n;6&f14yVcE(ywVw)rkYoIfbbiAZ=3#wruNv~+iG6aT0ip{=*;Ay zGAysHVFuHs3G+#+oU<(f$T?bfQ3bwq69?lesy{})nK%<(z)q!*)#$U~U}xvuX@G{J zyqIs?$YKFw5$vzc@nuEc$4X9UMMrJQVa^oH6Fa5xf%&TO%s- z8{qVBLD-VO4}LEP`1_T>1KKN-k4CYFE@Kf4;0OPRevM%a&87)??fr8yn_m9tg<>>u z%0A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 SWd!dqgUCt0k}3n6_WmCRR=hI+ delta 33292 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
  • Alert if encryption programs are found - This will add a predefined rule to find encryption programs and alert and export any that are found. You will not be able to edit this rule. -
  • Continue imaging after searches are performed - Only relevant when creating a VHD. By default, the logical imager will only copy sectors that it uses or that are part of matching files being exported. If this option is selected, logical imager will go back through the image after the rule matching is complete and copy over any remaining sectors. This will take longer to run and result in much larger VHD images. + +
  • Prompt before exiting imager - If selected, you will have to press a key at the end of the logical imager run. This keeps the command prompt window open so you can look at the output.
  • Create VHD - If selected, a sparse VHD will be created while running logical imager. See more details below. +
      +
    • Continue imaging after searches are performed - Only relevant when creating a VHD. By default, the logical imager will only copy sectors that it uses or that are part of matching files being exported. If this option is selected, logical imager will go back through the image after the rule matching is complete and copy over any remaining sectors. This will take longer to run and result in much larger VHD images. +
    More information on creating a VHD versus saving any matching files directly: @@ -146,7 +150,7 @@ Folder contents:
  • users.txt contains information on user accounts found in the system. It will also be added to the Autopsy case as a \ref reporting_page "report". -If logical imager was set to create VHDs, you'll see those VHDs in the output folder (along with the other output files described above): +If logical imager was set to create VHDs, you'll see those VHDs in the output folder (along with the other output files described above except the root folder): \image html LogicalImager/VHDfolder.png From c8c1fbd91deeed6c648909964a72c59e7ffb9da8 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 26 Sep 2019 13:51:34 -0400 Subject: [PATCH 16/17] Wrapped data into a Account.Address instance --- InternalPythonModules/android/TskContactsParser.py | 8 +++----- InternalPythonModules/android/line.py | 10 ++++------ InternalPythonModules/android/skype.py | 11 ++++------- InternalPythonModules/android/textnow.py | 13 +++++-------- InternalPythonModules/android/viber.py | 11 ++++------- InternalPythonModules/android/whatsapp.py | 13 +++++-------- 6 files changed, 25 insertions(+), 41 deletions(-) diff --git a/InternalPythonModules/android/TskContactsParser.py b/InternalPythonModules/android/TskContactsParser.py index 122e6a9445..9f1d4d293e 100644 --- a/InternalPythonModules/android/TskContactsParser.py +++ b/InternalPythonModules/android/TskContactsParser.py @@ -29,12 +29,10 @@ class TskContactsParser(ResultSetIterator): def __init__(self, result_set): super(TskContactsParser, self).__init__(result_set) self._DEFAULT_VALUE = "" + self._DEFAULT_ACCOUNT_ADDRESS = None - def get_account_name(self): - return self._DEFAULT_VALUE - - def get_contact_name(self): - return self._DEFAULT_VALUE + def get_account_instance(self): + return self._DEFAULT_ACCOUNT_ADDRESS def get_phone(self): return self._DEFAULT_VALUE diff --git a/InternalPythonModules/android/line.py b/InternalPythonModules/android/line.py index b8655b46e8..242c5d1503 100644 --- a/InternalPythonModules/android/line.py +++ b/InternalPythonModules/android/line.py @@ -142,8 +142,7 @@ class LineAnalyzer(general.AndroidComponentAnalyzer): contacts_parser = LineContactsParser(contacts_db) while contacts_parser.next(): helper.addContact( - contacts_parser.get_account_name(), - contacts_parser.get_contact_name(), + contacts_parser.get_account_instance(), contacts_parser.get_phone(), contacts_parser.get_home_phone(), contacts_parser.get_mobile_phone(), @@ -341,11 +340,10 @@ class LineContactsParser(TskContactsParser): """ ) ) - def get_account_name(self): - return self.result_set.getString("m_id") - def get_contact_name(self): - return self.result_set.getString("server_name") + def get_account_instance(self): + return Account.Address(self.result_set.getString("m_id"), + self.result_set.getString("server_name")) class LineMessagesParser(TskMessagesParser): """ diff --git a/InternalPythonModules/android/skype.py b/InternalPythonModules/android/skype.py index 6d0df56259..3556567305 100644 --- a/InternalPythonModules/android/skype.py +++ b/InternalPythonModules/android/skype.py @@ -151,8 +151,7 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): contacts_parser = SkypeContactsParser(skype_db) while contacts_parser.next(): helper.addContact( - contacts_parser.get_account_name(), - contacts_parser.get_contact_name(), + contacts_parser.get_account_instance(), contacts_parser.get_phone(), contacts_parser.get_home_phone(), contacts_parser.get_mobile_phone(), @@ -362,11 +361,9 @@ class SkypeContactsParser(TskContactsParser): ) ) - def get_account_name(self): - return self.result_set.getString("entry_id") - - def get_contact_name(self): - return self.result_set.getString("name") + def get_account_instance(self): + return Account.Address(self.result_set.getString("entry_id"), + self.result_set.getString("name")) class SkypeMessagesParser(TskMessagesParser): """ diff --git a/InternalPythonModules/android/textnow.py b/InternalPythonModules/android/textnow.py index 216864f2e1..b45bae37a5 100644 --- a/InternalPythonModules/android/textnow.py +++ b/InternalPythonModules/android/textnow.py @@ -108,8 +108,7 @@ class TextNowAnalyzer(general.AndroidComponentAnalyzer): contacts_parser = TextNowContactsParser(textnow_db) while contacts_parser.next(): helper.addContact( - contacts_parser.get_account_name(), - contacts_parser.get_contact_name(), + contacts_parser.get_account_instance(), contacts_parser.get_phone(), contacts_parser.get_home_phone(), contacts_parser.get_mobile_phone(), @@ -267,12 +266,10 @@ class TextNowContactsParser(TskContactsParser): ) ) - def get_account_name(self): - return self.result_set.getString("number") - - def get_contact_name(self): - return self.result_set.getString("name") - + def get_account_instance(self): + return Account.Address(self.result_set.getString("number"), + self.result_set.getString("name")) + def get_phone(self): return self.result_set.getString("number") diff --git a/InternalPythonModules/android/viber.py b/InternalPythonModules/android/viber.py index fb2b77ac7a..fb73f145b2 100644 --- a/InternalPythonModules/android/viber.py +++ b/InternalPythonModules/android/viber.py @@ -116,8 +116,7 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): contacts_parser = ViberContactsParser(contacts_db) while contacts_parser.next(): helper.addContact( - contacts_parser.get_account_name(), - contacts_parser.get_contact_name(), + contacts_parser.get_account_instance(), contacts_parser.get_phone(), contacts_parser.get_home_phone(), contacts_parser.get_mobile_phone(), @@ -273,11 +272,9 @@ class ViberContactsParser(TskContactsParser): ) ) - def get_account_name(self): - return self.result_set.getString("number") - - def get_contact_name(self): - return self.result_set.getString("name") + def get_account_instance(self): + return Account.Address(self.result_set.getString("number"), + self.result_set.getString("name")) def get_phone(self): return self.result_set.getString("number") diff --git a/InternalPythonModules/android/whatsapp.py b/InternalPythonModules/android/whatsapp.py index 8fdb09f13b..15f60cbd89 100644 --- a/InternalPythonModules/android/whatsapp.py +++ b/InternalPythonModules/android/whatsapp.py @@ -170,8 +170,7 @@ class WhatsAppAnalyzer(general.AndroidComponentAnalyzer): contacts_parser = WhatsAppContactsParser(contacts_db) while contacts_parser.next(): helper.addContact( - contacts_parser.get_account_name(), - contacts_parser.get_contact_name(), + contacts_parser.get_account_instance(), contacts_parser.get_phone(), contacts_parser.get_home_phone(), contacts_parser.get_mobile_phone(), @@ -410,12 +409,10 @@ class WhatsAppContactsParser(TskContactsParser): """ ) ) - - def get_account_name(self): - return self.result_set.getString("jid") - - def get_contact_name(self): - return self.result_set.getString("name") + + def get_account_instance(self): + return Account.Address(self.result_set.getString("jid"), + self.result_set.getString("name")) def get_phone(self): return self.result_set.getString("number") From fafb297cd1fedcafead237ec8c582254356d4697 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dsmyda" Date: Thu, 26 Sep 2019 13:55:44 -0400 Subject: [PATCH 17/17] Changed name from instance to address --- InternalPythonModules/android/TskContactsParser.py | 2 +- InternalPythonModules/android/line.py | 4 ++-- InternalPythonModules/android/skype.py | 4 ++-- InternalPythonModules/android/textnow.py | 4 ++-- InternalPythonModules/android/viber.py | 4 ++-- InternalPythonModules/android/whatsapp.py | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/InternalPythonModules/android/TskContactsParser.py b/InternalPythonModules/android/TskContactsParser.py index 9f1d4d293e..4e03613bcd 100644 --- a/InternalPythonModules/android/TskContactsParser.py +++ b/InternalPythonModules/android/TskContactsParser.py @@ -31,7 +31,7 @@ class TskContactsParser(ResultSetIterator): self._DEFAULT_VALUE = "" self._DEFAULT_ACCOUNT_ADDRESS = None - def get_account_instance(self): + def get_account_address(self): return self._DEFAULT_ACCOUNT_ADDRESS def get_phone(self): diff --git a/InternalPythonModules/android/line.py b/InternalPythonModules/android/line.py index 242c5d1503..f8e826542f 100644 --- a/InternalPythonModules/android/line.py +++ b/InternalPythonModules/android/line.py @@ -142,7 +142,7 @@ class LineAnalyzer(general.AndroidComponentAnalyzer): contacts_parser = LineContactsParser(contacts_db) while contacts_parser.next(): helper.addContact( - contacts_parser.get_account_instance(), + contacts_parser.get_account_address(), contacts_parser.get_phone(), contacts_parser.get_home_phone(), contacts_parser.get_mobile_phone(), @@ -341,7 +341,7 @@ class LineContactsParser(TskContactsParser): ) ) - def get_account_instance(self): + def get_account_address(self): return Account.Address(self.result_set.getString("m_id"), self.result_set.getString("server_name")) diff --git a/InternalPythonModules/android/skype.py b/InternalPythonModules/android/skype.py index 3556567305..fe027961ff 100644 --- a/InternalPythonModules/android/skype.py +++ b/InternalPythonModules/android/skype.py @@ -151,7 +151,7 @@ class SkypeAnalyzer(general.AndroidComponentAnalyzer): contacts_parser = SkypeContactsParser(skype_db) while contacts_parser.next(): helper.addContact( - contacts_parser.get_account_instance(), + contacts_parser.get_account_address(), contacts_parser.get_phone(), contacts_parser.get_home_phone(), contacts_parser.get_mobile_phone(), @@ -361,7 +361,7 @@ class SkypeContactsParser(TskContactsParser): ) ) - def get_account_instance(self): + def get_account_address(self): return Account.Address(self.result_set.getString("entry_id"), self.result_set.getString("name")) diff --git a/InternalPythonModules/android/textnow.py b/InternalPythonModules/android/textnow.py index b45bae37a5..8361b0d3eb 100644 --- a/InternalPythonModules/android/textnow.py +++ b/InternalPythonModules/android/textnow.py @@ -108,7 +108,7 @@ class TextNowAnalyzer(general.AndroidComponentAnalyzer): contacts_parser = TextNowContactsParser(textnow_db) while contacts_parser.next(): helper.addContact( - contacts_parser.get_account_instance(), + contacts_parser.get_account_address(), contacts_parser.get_phone(), contacts_parser.get_home_phone(), contacts_parser.get_mobile_phone(), @@ -266,7 +266,7 @@ class TextNowContactsParser(TskContactsParser): ) ) - def get_account_instance(self): + def get_account_address(self): return Account.Address(self.result_set.getString("number"), self.result_set.getString("name")) diff --git a/InternalPythonModules/android/viber.py b/InternalPythonModules/android/viber.py index fb73f145b2..54f0b260a0 100644 --- a/InternalPythonModules/android/viber.py +++ b/InternalPythonModules/android/viber.py @@ -116,7 +116,7 @@ class ViberAnalyzer(general.AndroidComponentAnalyzer): contacts_parser = ViberContactsParser(contacts_db) while contacts_parser.next(): helper.addContact( - contacts_parser.get_account_instance(), + contacts_parser.get_account_address(), contacts_parser.get_phone(), contacts_parser.get_home_phone(), contacts_parser.get_mobile_phone(), @@ -272,7 +272,7 @@ class ViberContactsParser(TskContactsParser): ) ) - def get_account_instance(self): + def get_account_address(self): return Account.Address(self.result_set.getString("number"), self.result_set.getString("name")) diff --git a/InternalPythonModules/android/whatsapp.py b/InternalPythonModules/android/whatsapp.py index 15f60cbd89..09f2521a8d 100644 --- a/InternalPythonModules/android/whatsapp.py +++ b/InternalPythonModules/android/whatsapp.py @@ -170,7 +170,7 @@ class WhatsAppAnalyzer(general.AndroidComponentAnalyzer): contacts_parser = WhatsAppContactsParser(contacts_db) while contacts_parser.next(): helper.addContact( - contacts_parser.get_account_instance(), + contacts_parser.get_account_address(), contacts_parser.get_phone(), contacts_parser.get_home_phone(), contacts_parser.get_mobile_phone(), @@ -410,7 +410,7 @@ class WhatsAppContactsParser(TskContactsParser): ) ) - def get_account_instance(self): + def get_account_address(self): return Account.Address(self.result_set.getString("jid"), self.result_set.getString("name"))