Merge branch 'sleuthkit:develop' into develop

This commit is contained in:
Seb2lyon 2021-07-09 17:59:48 +02:00 committed by GitHub
commit c5fcf71303
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 1420 additions and 1067 deletions

View File

@ -2,7 +2,7 @@ Manifest-Version: 1.0
OpenIDE-Module: org.sleuthkit.autopsy.core/10 OpenIDE-Module: org.sleuthkit.autopsy.core/10
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties
OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml
OpenIDE-Module-Implementation-Version: 35 OpenIDE-Module-Implementation-Version: 36
OpenIDE-Module-Requires: org.openide.windows.WindowManager OpenIDE-Module-Requires: org.openide.windows.WindowManager
AutoUpdate-Show-In-Client: true AutoUpdate-Show-In-Client: true
AutoUpdate-Essential-Module: true AutoUpdate-Essential-Module: true

View File

@ -109,8 +109,8 @@ file.reference.protobuf-java-util-3.7.0.jar=release\\modules\\ext\\protobuf-java
file.reference.Rejistry-1.1-SNAPSHOT.jar=release\\modules\\ext\\Rejistry-1.1-SNAPSHOT.jar file.reference.Rejistry-1.1-SNAPSHOT.jar=release\\modules\\ext\\Rejistry-1.1-SNAPSHOT.jar
file.reference.sevenzipjbinding-AllPlatforms.jar=release\\modules\\ext\\sevenzipjbinding-AllPlatforms.jar file.reference.sevenzipjbinding-AllPlatforms.jar=release\\modules\\ext\\sevenzipjbinding-AllPlatforms.jar
file.reference.sevenzipjbinding.jar=release\\modules\\ext\\sevenzipjbinding.jar file.reference.sevenzipjbinding.jar=release\\modules\\ext\\sevenzipjbinding.jar
file.reference.sleuthkit-4.10.2.jar=release/modules/ext/sleuthkit-4.10.2.jar file.reference.sleuthkit-4.11.0.jar=release/modules/ext/sleuthkit-4.11.0.jar
file.reference.sleuthkit-caseuco-4.10.2.jar=release/modules/ext/sleuthkit-caseuco-4.10.2.jar file.reference.sleuthkit-caseuco-4.11.0.jar=release/modules/ext/sleuthkit-caseuco-4.11.0.jar
file.reference.slf4j-api-1.7.6.jar=release\\modules\\ext\\slf4j-api-1.7.6.jar file.reference.slf4j-api-1.7.6.jar=release\\modules\\ext\\slf4j-api-1.7.6.jar
file.reference.slf4j-log4j12-1.7.6.jar=release\\modules\\ext\\slf4j-log4j12-1.7.6.jar file.reference.slf4j-log4j12-1.7.6.jar=release\\modules\\ext\\slf4j-log4j12-1.7.6.jar
file.reference.SparseBitSet-1.1.jar=release\\modules\\ext\\SparseBitSet-1.1.jar file.reference.SparseBitSet-1.1.jar=release\\modules\\ext\\SparseBitSet-1.1.jar
@ -128,4 +128,4 @@ nbm.homepage=http://www.sleuthkit.org/
nbm.module.author=Brian Carrier nbm.module.author=Brian Carrier
nbm.needs.restart=true nbm.needs.restart=true
source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar
spec.version.base=10.23 spec.version.base=10.24

View File

@ -682,8 +682,8 @@
<binary-origin>release\modules\ext\grpc-alts-1.19.0.jar</binary-origin> <binary-origin>release\modules\ext\grpc-alts-1.19.0.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/sleuthkit-caseuco-4.10.2.jar</runtime-relative-path> <runtime-relative-path>ext/sleuthkit-caseuco-4.11.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-caseuco-4.10.2.jar</binary-origin> <binary-origin>release/modules/ext/sleuthkit-caseuco-4.11.0.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/jdom-2.0.5.jar</runtime-relative-path> <runtime-relative-path>ext/jdom-2.0.5.jar</runtime-relative-path>
@ -802,8 +802,8 @@
<binary-origin>release\modules\ext\sevenzipjbinding-AllPlatforms.jar</binary-origin> <binary-origin>release\modules\ext\sevenzipjbinding-AllPlatforms.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/sleuthkit-4.10.2.jar</runtime-relative-path> <runtime-relative-path>ext/sleuthkit-4.11.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-4.10.2.jar</binary-origin> <binary-origin>release/modules/ext/sleuthkit-4.11.0.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/jutf7-1.0.0.jar</runtime-relative-path> <runtime-relative-path>ext/jutf7-1.0.0.jar</runtime-relative-path>

View File

@ -70,6 +70,7 @@ MediaViewVideoPanel.progressLabel.text=00:00
MediaViewVideoPanel.infoLabel.text=info MediaViewVideoPanel.infoLabel.text=info
MediaViewImagePanel.imgFileTooLarge.msg=Could not load image file (too large): {0} MediaViewImagePanel.imgFileTooLarge.msg=Could not load image file (too large): {0}
Metadata.headerTitle=Metadata
Metadata.nodeText.loading=Metadata loading... Metadata.nodeText.loading=Metadata loading...
Metadata.nodeText.none=None Metadata.nodeText.none=None
Metadata.nodeText.truncated=(results truncated) Metadata.nodeText.truncated=(results truncated)
@ -106,6 +107,7 @@ MessageArtifactViewer.textbodyScrollPane.TabConstraints.tabTitle=Text
JPEGViewerDummy.jLabel1.text=You are looking at a JPEG file: JPEGViewerDummy.jLabel1.text=You are looking at a JPEG file:
JPEGViewerDummy.jTextField1.text=jTextField1 JPEGViewerDummy.jTextField1.text=jTextField1
Metadata_dataArtifactTitle=Source File Metadata Metadata_dataArtifactTitle=Source File Metadata
MetadataWorker.doInBackground.noDataMsg=No Data
PDFViewer.encryptedDialog=This document is password protected. PDFViewer.encryptedDialog=This document is password protected.
PDFViewer.errorDialog=An error occurred while opening this PDF document. Check the logs for more information. You may continue to use this feature on other PDF documents. PDFViewer.errorDialog=An error occurred while opening this PDF document. Check the logs for more information. You may continue to use this feature on other PDF documents.
PListNode.KeyCol=Key PListNode.KeyCol=Key
@ -403,29 +405,44 @@ viewer.menu.help.about.label=About ICEpdf viewer...
## General error dialog ## General error dialog
viewer.dialog.error.exception.title = ICEsoft ICEpdf - Exception viewer.dialog.error.exception.title = ICEsoft ICEpdf - Exception
viewer.dialog.error.exception.msg=There was an error executing your command do to the following exception\n{0}. viewer.dialog.error.exception.msg = \
There was an error executing your command do to the following exception\n\
{0}.
## Open File Dialog ## Open File Dialog
viewer.dialog.openFile.title = Open File viewer.dialog.openFile.title = Open File
viewer.dialog.openFile.error.title = ICEsoft ICEpdf - Open File Error viewer.dialog.openFile.error.title = ICEsoft ICEpdf - Open File Error
viewer.dialog.openFile.error.msg=ICEpdf could not open the specified file at {0}\nThe file may be corrupt or not a supported file type. viewer.dialog.openFile.error.msg = \
ICEpdf could not open the specified file at {0}\n\
The file may be corrupt or not a supported file type.
viewer.dialog.openDocument.pdfException.title = ICEsoft ICEpdf - PDF Exception viewer.dialog.openDocument.pdfException.title = ICEsoft ICEpdf - PDF Exception
viewer.dialog.openDocument.pdfException.msg=ICEpdf could not open the specified file {0} \nThe file may be corrupt or not a supported file type. viewer.dialog.openDocument.pdfException.msg = \
ICEpdf could not open the specified file {0} \n\
The file may be corrupt or not a supported file type.
viewer.dialog.openDocument.pdfSecurityException.title = ICEsoft ICEpdf - PDF Security Exception viewer.dialog.openDocument.pdfSecurityException.title = ICEsoft ICEpdf - PDF Security Exception
viewer.dialog.openDocument.pdfSecurityException.msg=ICEpdf could not open the encrypted file at {0}\nThis may be the result of an invalid password or a missing JCE Security Provider.\n\nPlease refer to ICEpdf Developer's Guide for more information. viewer.dialog.openDocument.pdfSecurityException.msg = \
ICEpdf could not open the encrypted file at {0}\n\
This may be the result of an invalid password or a missing JCE Security Provider.\n\n\
Please refer to ICEpdf Developer's Guide for more information.
viewer.dialog.openDocument.exception.title = ICEsoft ICEpdf - Exception viewer.dialog.openDocument.exception.title = ICEsoft ICEpdf - Exception
viewer.dialog.openDocument.exception.msg=ICEpdf could not open the specified file at {0}\nThe file may be corrupt or not a supported file type. viewer.dialog.openDocument.exception.msg = \
ICEpdf could not open the specified file at {0}\n\
The file may be corrupt or not a supported file type.
viewer.dialog.openURL.exception.title = ICEsoft ICEpdf - URL Exception viewer.dialog.openURL.exception.title = ICEsoft ICEpdf - URL Exception
viewer.dialog.openURL.exception.msg=ICEpdf could not open the specified file. {0} \nat URL: {1} viewer.dialog.openURL.exception.msg = \
ICEpdf could not open the specified file. {0} \n\
at URL: {1}
viewer.dialog.openURL.downloading.msg = Downloading {0} viewer.dialog.openURL.downloading.msg = Downloading {0}
## General error dialog ## General error dialog
viewer.dialog.information.copyAll.title = ICEsoft ICEpdf - Information viewer.dialog.information.copyAll.title = ICEsoft ICEpdf - Information
viewer.dialog.information.copyAll.msg=The document has more than {0} pages, please use\n"Export text..." to extract document text. viewer.dialog.information.copyAll.msg = \
The document has more than {0} pages, please use\n\
"Export text..." to extract document text.
## Open URL Dialog ## Open URL Dialog
viewer.dialog.security.title = Document Security viewer.dialog.security.title = Document Security
@ -443,11 +460,13 @@ viewer.dialog.openURL.title=Open URL
### Save a Copy Dialog ### Save a Copy Dialog
viewer.dialog.saveAs.title = Save As viewer.dialog.saveAs.title = Save As
viewer.dialog.saveAs.extensionError.title = ICEsoft ICEpdf - Save Error viewer.dialog.saveAs.extensionError.title = ICEsoft ICEpdf - Save Error
viewer.dialog.saveAs.extensionError.msg=ICEpdf could not save to {0} because it is not a supported file type. viewer.dialog.saveAs.extensionError.msg = \
ICEpdf could not save to {0} because it is not a supported file type.
viewer.dialog.saveAs.noExtensionError.title = ICEsoft ICEpdf - Save Error viewer.dialog.saveAs.noExtensionError.title = ICEsoft ICEpdf - Save Error
viewer.dialog.saveAs.noExtensionError.msg = Please specify a file extension. viewer.dialog.saveAs.noExtensionError.msg = Please specify a file extension.
viewer.dialog.saveAs.noneUniqueName.title = ICEsoft ICEpdf - Save Error viewer.dialog.saveAs.noneUniqueName.title = ICEsoft ICEpdf - Save Error
viewer.dialog.saveAs.noneUniqueName.msg=The file named {0} already exists. Please specify a unique name. viewer.dialog.saveAs.noneUniqueName.msg = \
The file named {0} already exists. Please specify a unique name.
viewer.dialog.saveAs.noPermission.title = ICEpdf Viewer RI - Save Error viewer.dialog.saveAs.noPermission.title = ICEpdf Viewer RI - Save Error
viewer.dialog.saveAs.noPermission.msg = You do not have permission or the credentials to save this document. viewer.dialog.saveAs.noPermission.msg = You do not have permission or the credentials to save this document.
viewer.dialog.saveAs.noUpdates.title = ICEpdf Viewer RI viewer.dialog.saveAs.noUpdates.title = ICEpdf Viewer RI
@ -464,19 +483,25 @@ viewer.dialog.exportText.noExtensionError.msg=Please specify a file extension.
viewer.exportText.fileStamp.msg = ICEsoft ICEpdf Viewer, (c) ICEsoft Technologies, Inc. viewer.exportText.fileStamp.msg = ICEsoft ICEpdf Viewer, (c) ICEsoft Technologies, Inc.
viewer.exportText.pageStamp.msg = <!----- Page {0} Text ----> viewer.exportText.pageStamp.msg = <!----- Page {0} Text ---->
# Completed x out of y page(s). # Completed x out of y page(s).
viewer.exportText.fileStamp.progress.msg=Completed {0} out of {1}. viewer.exportText.fileStamp.progress.msg = \
Completed {0} out of {1}.
viewer.exportText.fileStamp.progress.oneFile.msg = {2} page viewer.exportText.fileStamp.progress.oneFile.msg = {2} page
viewer.exportText.fileStamp.progress.moreFile.msg = {2} pages viewer.exportText.fileStamp.progress.moreFile.msg = {2} pages
## Export SVG Dialog ## Export SVG Dialog
viewer.dialog.exportSVG.title = Export to SVG viewer.dialog.exportSVG.title = Export to SVG
viewer.dialog.exportSVG.status.exporting.msg = Exporting page {0} to SVG file {1} ... viewer.dialog.exportSVG.status.exporting.msg = Exporting page {0} to SVG file {1} ...
viewer.dialog.exportSVG.status.error.msg=Problem exporting page {0} to SVG file {1} : {2} viewer.dialog.exportSVG.status.error.msg = \
viewer.dialog.exportSVG.status.finished.msg=Finished exporting page {0} to SVG file {1} Problem exporting page {0} to SVG file {1} : {2}
viewer.dialog.exportSVG.status.finished.msg = \
Finished exporting page {0} to SVG file {1}
viewer.dialog.exportSVG.noExtensionError.title = ICEsoft ICEpdf - SVG Error viewer.dialog.exportSVG.noExtensionError.title = ICEsoft ICEpdf - SVG Error
viewer.dialog.exportSVG.noExtensionError.msg = Please specify a file extension. viewer.dialog.exportSVG.noExtensionError.msg = Please specify a file extension.
viewer.dialog.exportSVG.exportError.title = ICEsoft ICEpdf - SVG Error viewer.dialog.exportSVG.exportError.title = ICEsoft ICEpdf - SVG Error
viewer.dialog.exportSVG.exportError.msg=ICEpdf could not export to {0} \nbecuase it is either not a supported file type or \nbecause the file has been corrupted. viewer.dialog.exportSVG.exportError.msg = \
ICEpdf could not export to {0} \n\
becuase it is either not a supported file type or \n\
because the file has been corrupted.
# Printing Progress bar # Printing Progress bar
viewer.dialog.printing.status.progress.msg = Page {0} of {1} viewer.dialog.printing.status.progress.msg = Page {0} of {1}
@ -525,7 +550,10 @@ viewer.dialog.goToPage.description.label=Page Number
## About Dialog ## About Dialog
viewer.dialog.about.title = About ICEpdf Viewer viewer.dialog.about.title = About ICEpdf Viewer
viewer.dialog.about.pageNumber.label=\n\nCheck the ICEpdf web site for the latest news:\nhttp://www.icepdf.org/ \n\n viewer.dialog.about.pageNumber.label = \n\
\n\
Check the ICEpdf web site for the latest news:\n\
http://www.icepdf.org/ \n\n
## Font Properties Dialog ## Font Properties Dialog
viewer.dialog.fonts.title = Document Font Properties viewer.dialog.fonts.title = Document Font Properties
@ -550,7 +578,8 @@ viewer.utilityPane.attachments.column.size.title=Size
viewer.utilityPane.attachments.column.compressedSize.title = Compressed size viewer.utilityPane.attachments.column.compressedSize.title = Compressed size
viewer.utilityPane.attachments.menu.saveAs.label = Save As... viewer.utilityPane.attachments.menu.saveAs.label = Save As...
viewer.utilityPane.attachments.saveAs.replace.title = ICEsoft ICEpdf - Save Error viewer.utilityPane.attachments.saveAs.replace.title = ICEsoft ICEpdf - Save Error
viewer.utilityPane.attachments.saveAs.replace.msg=The file named {0} already exists. Do you want to replace It? viewer.utilityPane.attachments.saveAs.replace.msg = \
The file named {0} already exists. Do you want to replace It?
## Utility Pane Thumbnails ## Utility Pane Thumbnails
viewer.utilityPane.thumbs.tab.title = Thumbnails viewer.utilityPane.thumbs.tab.title = Thumbnails
@ -560,20 +589,25 @@ viewer.utilityPane.layers.tab.title=Layers
## Signature Pane ## Signature Pane
viewer.utilityPane.signatures.tab.title = Signatures viewer.utilityPane.signatures.tab.title = Signatures
viewer.utilityPane.signatures.tab.certTree.error.label=Unsigned Signature Fields Signer certificate could not be validated {0} {1} viewer.utilityPane.signatures.tab.certTree.error.label = \
Unsigned Signature Fields Signer certificate could not be validated {0} {1}
viewer.utilityPane.signatures.tab.certTree.rootSigned.label = Signed by {0} {1} viewer.utilityPane.signatures.tab.certTree.rootSigned.label = Signed by {0} {1}
viewer.utilityPane.signatures.tab.certTree.rootValidating.label = Validating signature {0} {1} viewer.utilityPane.signatures.tab.certTree.rootValidating.label = Validating signature {0} {1}
viewer.utilityPane.signatures.tab.certTree.cert.invalid.label = Signature is invalid: viewer.utilityPane.signatures.tab.certTree.cert.invalid.label = Signature is invalid:
viewer.utilityPane.signatures.tab.certTree.cert.unknown.label = Signature is valid: viewer.utilityPane.signatures.tab.certTree.cert.unknown.label = Signature is valid:
viewer.utilityPane.signatures.tab.certTree.cert.valid.label = Signature validity is unknown: viewer.utilityPane.signatures.tab.certTree.cert.valid.label = Signature validity is unknown:
viewer.utilityPane.signatures.tab.certTree.doc.modified.label=This version of the document is unaltered but subsequent changes have been made viewer.utilityPane.signatures.tab.certTree.doc.modified.label = \
This version of the document is unaltered but subsequent changes have been made
viewer.utilityPane.signatures.tab.certTree.doc.unmodified.label = Document has not been modified since it was signed viewer.utilityPane.signatures.tab.certTree.doc.unmodified.label = Document has not been modified since it was signed
viewer.utilityPane.signatures.tab.certTree.doc.major.label = Document has been altered or corrupted since it was signed viewer.utilityPane.signatures.tab.certTree.doc.major.label = Document has been altered or corrupted since it was signed
viewer.utilityPane.signatures.tab.certTree.signature.identity.unknown.label=Signer's identity is unknown because it could not be found in your keystore viewer.utilityPane.signatures.tab.certTree.signature.identity.unknown.label = \
viewer.utilityPane.signatures.tab.certTree.signature.identity.unchecked.label=Signature is valid, but revocation of the signer's identity could not be checked Signer's identity is unknown because it could not be found in your keystore
viewer.utilityPane.signatures.tab.certTree.signature.identity.unchecked.label = \
Signature is valid, but revocation of the signer's identity could not be checked
viewer.utilityPane.signatures.tab.certTree.signature.identity.valid.label = Signer's identity is valid viewer.utilityPane.signatures.tab.certTree.signature.identity.valid.label = Signer's identity is valid
viewer.utilityPane.signatures.tab.certTree.signature.time.local.label = Signing time is from the clock on this signer's computer viewer.utilityPane.signatures.tab.certTree.signature.time.local.label = Signing time is from the clock on this signer's computer
viewer.utilityPane.signatures.tab.certTree.signature.time.embedded.label=Signature included an embedded timestamp but it could not be validated viewer.utilityPane.signatures.tab.certTree.signature.time.embedded.label = \
Signature included an embedded timestamp but it could not be validated
viewer.utilityPane.signatures.tab.certTree.signature.details.label = Signature Details viewer.utilityPane.signatures.tab.certTree.signature.details.label = Signature Details
viewer.utilityPane.signatures.tab.certTree.signature.details.reason.label = Reason: {0} viewer.utilityPane.signatures.tab.certTree.signature.details.reason.label = Reason: {0}
viewer.utilityPane.signatures.tab.certTree.signature.details.location.label = Location: {0} viewer.utilityPane.signatures.tab.certTree.signature.details.location.label = Location: {0}
@ -598,11 +632,13 @@ viewer.utilityPane.signatures.cert.dialog.info.serialNumber.value={0}
viewer.utilityPane.signatures.cert.dialog.info.signatureAlgorithm.label = Signature Algorithm viewer.utilityPane.signatures.cert.dialog.info.signatureAlgorithm.label = Signature Algorithm
viewer.utilityPane.signatures.cert.dialog.info.signatureAlgorithm.value = {0} viewer.utilityPane.signatures.cert.dialog.info.signatureAlgorithm.value = {0}
viewer.utilityPane.signatures.cert.dialog.info.issuer.label = Issuer viewer.utilityPane.signatures.cert.dialog.info.issuer.label = Issuer
viewer.utilityPane.signatures.cert.dialog.info.issuer.value=Organization: {0} \nOrganization Unit: {1} \nCommon Name: {2} \nLocal: {3} \nState: {4} \nCountry: {5} \nEmail: {6} viewer.utilityPane.signatures.cert.dialog.info.issuer.value = \
Organization: {0} \nOrganization Unit: {1} \nCommon Name: {2} \nLocal: {3} \nState: {4} \nCountry: {5} \nEmail: {6}
viewer.utilityPane.signatures.cert.dialog.info.validity.label = Validity viewer.utilityPane.signatures.cert.dialog.info.validity.label = Validity
viewer.utilityPane.signatures.cert.dialog.info.validity.value = From: {0}\n To: {1} viewer.utilityPane.signatures.cert.dialog.info.validity.value = From: {0}\n To: {1}
viewer.utilityPane.signatures.cert.dialog.info.subject.label = Subject viewer.utilityPane.signatures.cert.dialog.info.subject.label = Subject
viewer.utilityPane.signatures.cert.dialog.info.subject.value=Organization: {0} \nOrganization Unit: {1} \nCommon Name: {2} \nLocal: {3} \nState: {4} \nCountry: {5} \nEmail: {6} viewer.utilityPane.signatures.cert.dialog.info.subject.value = \
Organization: {0} \nOrganization Unit: {1} \nCommon Name: {2} \nLocal: {3} \nState: {4} \nCountry: {5} \nEmail: {6}
viewer.utilityPane.signatures.cert.dialog.info.signature.label = Signature viewer.utilityPane.signatures.cert.dialog.info.signature.label = Signature
viewer.utilityPane.signatures.cert.dialog.info.md5.label = MD5 Fingerprint viewer.utilityPane.signatures.cert.dialog.info.md5.label = MD5 Fingerprint
viewer.utilityPane.signatures.cert.dialog.info.md5.value = {0} viewer.utilityPane.signatures.cert.dialog.info.md5.value = {0}
@ -814,7 +850,8 @@ viewer.utilityPane.search.showPagesCheckbox.label=Show Pages
viewer.utilityPane.search.stopButton.label = Stop viewer.utilityPane.search.stopButton.label = Stop
viewer.utilityPane.search.searching.msg = Search... viewer.utilityPane.search.searching.msg = Search...
# Searching x out of y page(s) # Searching x out of y page(s)
viewer.utilityPane.search.searching1.msg=Searching {0} out of {1} viewer.utilityPane.search.searching1.msg = \
Searching {0} out of {1}
viewer.utilityPane.search.searching1.oneFile.msg = {2} page viewer.utilityPane.search.searching1.oneFile.msg = {2} page
viewer.utilityPane.search.searching1.moreFile.msg = {2} pages viewer.utilityPane.search.searching1.moreFile.msg = {2} pages
# Page x (y result(s)) # Page x (y result(s))
@ -822,7 +859,8 @@ viewer.utilityPane.search.result.msg=Page {0} ({1})
viewer.utilityPane.search.result.oneFile.msg = {2} result viewer.utilityPane.search.result.oneFile.msg = {2} result
viewer.utilityPane.search.result.moreFile.msg = {2} results viewer.utilityPane.search.result.moreFile.msg = {2} results
# Searched x page(s) (y matches) # Searched x page(s) (y matches)
viewer.utilityPane.search.progress.msg=Searched {0} {1} ({2}) viewer.utilityPane.search.progress.msg = \
Searched {0} {1} ({2})
viewer.utilityPane.search.progress.onePage.msg = page viewer.utilityPane.search.progress.onePage.msg = page
viewer.utilityPane.search.progress.morePage.msg = pages viewer.utilityPane.search.progress.morePage.msg = pages
viewer.utilityPane.search.progress.oneMatch.msg = {2} match viewer.utilityPane.search.progress.oneMatch.msg = {2} match
@ -866,14 +904,18 @@ viewer.annotation.signature.validation.common.invalid.label=Signature is invalid
viewer.annotation.signature.validation.common.unknown.label = Signature is valid: viewer.annotation.signature.validation.common.unknown.label = Signature is valid:
viewer.annotation.signature.validation.common.valid.label = Signature validity is unknown: viewer.annotation.signature.validation.common.valid.label = Signature validity is unknown:
viewer.annotation.signature.validation.common.signedBy.label = - Signed by {0} {1} viewer.annotation.signature.validation.common.signedBy.label = - Signed by {0} {1}
viewer.annotation.signature.validation.common.doc.modified.label=- This version of the document is unaltered but subsequent changes have been made viewer.annotation.signature.validation.common.doc.modified.label = \
- This version of the document is unaltered but subsequent changes have been made
viewer.annotation.signature.validation.common.doc.unmodified.label = - Document has not been modified since it was signed viewer.annotation.signature.validation.common.doc.unmodified.label = - Document has not been modified since it was signed
viewer.annotation.signature.validation.common.doc.major.label = - Document has been altered or corrupted since it was signed viewer.annotation.signature.validation.common.doc.major.label = - Document has been altered or corrupted since it was signed
viewer.annotation.signature.validation.common.identity.unknown.label=- Signer's identity is unknown because it could not be found in your keystore viewer.annotation.signature.validation.common.identity.unknown.label = \
viewer.annotation.signature.validation.common.identity.unchecked.label=- Signature is valid, but revocation of the signer's identity could not be checked - Signer's identity is unknown because it could not be found in your keystore
viewer.annotation.signature.validation.common.identity.unchecked.label = \
- Signature is valid, but revocation of the signer's identity could not be checked
viewer.annotation.signature.validation.common.identity.valid.label = - Signer's identity is valid viewer.annotation.signature.validation.common.identity.valid.label = - Signer's identity is valid
viewer.annotation.signature.validation.common.time.local.label = - Signing time is from the clock on this signer's computer viewer.annotation.signature.validation.common.time.local.label = - Signing time is from the clock on this signer's computer
viewer.annotation.signature.validation.common.time.embedded.label=- Signature included an embedded timestamp but it could not be validated viewer.annotation.signature.validation.common.time.embedded.label = \
- Signature included an embedded timestamp but it could not be validated
viewer.annotation.signature.validation.common.notAvailable.label = N/A viewer.annotation.signature.validation.common.notAvailable.label = N/A
## Signatures properties Dialog. ## Signatures properties Dialog.
@ -906,14 +948,16 @@ pilot.title=ICEbrowser - ICEpdf Pilot Errror
pilot.loading.msg =Opening document {0} ... pilot.loading.msg =Opening document {0} ...
pilot.display.msg = Displaying {0} pilot.display.msg = Displaying {0}
pilot.loading.error.msg = PDF Pilot: Failed to load {0}. pilot.loading.error.msg = PDF Pilot: Failed to load {0}.
pilot.error.classLoading=Required class {0} not found. Required library 'icepdf.jar' may not be on the classpath - PDF Pilot disabled."; pilot.error.classLoading = Required class {0} not found. Required library \
'icepdf.jar' may not be on the classpath - PDF Pilot disabled.";
### ###
# General Error Messages # General Error Messages
# Command Line Errors # Command Line Errors
viewer.commandLin.error=Usage: java org.icepdf.ri.viewer.Main [-loadfile <value>] [-loadurl <value>] viewer.commandLin.error = \
Usage: java org.icepdf.ri.viewer.Main [-loadfile <value>] [-loadurl <value>]
# Launcher errors # Launcher errors
viewer.launcher.URLError.dialog.title =ICEsoft ICEpdf viewer.launcher.URLError.dialog.title =ICEsoft ICEpdf
viewer.launcher.URLError.dialog.message = ICEpdf could not open the specified file. {0} at URL: {1}. viewer.launcher.URLError.dialog.message = ICEpdf could not open the specified file. {0} at URL: {1}.
@ -934,21 +978,40 @@ parse.laf=Warning : look-and-feel {0} is not supported.
manager.properties.title = ICEpdf Properties Manager manager.properties.title = ICEpdf Properties Manager
fontManager.properties.title = ICEpdf Font Manager fontManager.properties.title = ICEpdf Font Manager
manager.properties.createNewDirectory=To create the directory {0},\nwhere the ICEpdf Viewer will store changes to its setup, click Yes.\n\nIf you click "No", all changes you make to the ICEpdf Viewer setup\nwill be lost when you quit the application. \n\n manager.properties.createNewDirectory = \
To create the directory {0},\n\
where the ICEpdf Viewer will store changes to its setup, click Yes.\n\n\
If you click "No", all changes you make to the ICEpdf Viewer setup\n\
will be lost when you quit the application. \n\n
manager.properties.failedCreation=ICEpdf Viewer directory to store user data can not be created:\n{0}\nICEpdf Viewer will not save changes to its default setup. manager.properties.failedCreation = \
ICEpdf Viewer directory to store user data can not be created:\n\
{0}\n\
ICEpdf Viewer will not save changes to its default setup.
manager.properties.session.nolock=Error creating the lock file :\n{0}\n manager.properties.session.nolock = \
Error creating the lock file :\n\
{0}\n
manager.properties.session.readError=Error loading properties file: \n{0} manager.properties.session.readError = \
Error loading properties file: \n\
{0}
manager.properties.deleted=Property file has been deleted\n({0})\nRecreate it ? manager.properties.deleted = Property file has been deleted\n\
({0})\n\
Recreate it ?
manager.properties.modified=Property file has been modified since last update\n({0,date,long})\nWould you like to merge changes in the file with the current properties? manager.properties.modified = Property file has been modified since last update\n\
({0,date,long})\n\
Would you like to merge changes in the file with the current properties?
manager.properties.saveError=Impossible to save property file.\nEncountered the folowing error :\n{0} manager.properties.saveError = Impossible to save property file.\n\
Encountered the folowing error :\n\
{0}
manager.properties.lafError=Look&Feel {0} given in the default properties is unsupported.\nUsing system default. manager.properties.lafError =\
Look&Feel {0} given in the default properties is unsupported.\n\
Using system default.
manager.properties.brokenProperty = Broken default property {0} value: {1} manager.properties.brokenProperty = Broken default property {0} value: {1}

View File

@ -324,6 +324,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
this.node = node; this.node = node;
} }
@Messages("MetadataWorker.doInBackground.noDataMsg=No Data")
@Override @Override
protected String doInBackground() throws Exception { protected String doInBackground() throws Exception {
AbstractFile file = node.getLookup().lookup(AbstractFile.class); AbstractFile file = node.getLookup().lookup(AbstractFile.class);
@ -397,7 +398,6 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
FsContent fsFile = (FsContent) file; FsContent fsFile = (FsContent) file;
addHeader(sb, NbBundle.getMessage(this.getClass(), "Metadata.nodeText.text"), true); addHeader(sb, NbBundle.getMessage(this.getClass(), "Metadata.nodeText.text"), true);
startTable(sb);
List<String> istatStrings = Collections.emptyList(); List<String> istatStrings = Collections.emptyList();
try { try {
@ -406,6 +406,14 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
istatStrings = Arrays.asList(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.exceptionNotice.text") + ex.getLocalizedMessage()); istatStrings = Arrays.asList(NbBundle.getMessage(this.getClass(), "Metadata.nodeText.exceptionNotice.text") + ex.getLocalizedMessage());
} }
if (istatStrings.isEmpty() || (istatStrings.size() == 1 && StringUtils.isEmpty(istatStrings.get(0)))) {
sb.append(MessageFormat.format("<div class=\"{0}\"><p class=\"{1}\">{2}</p><div>",
ContentViewerHtmlStyles.getIndentedClassName(),
ContentViewerHtmlStyles.getTextClassName(),
Bundle.MetadataWorker_doInBackground_noDataMsg()));
} else {
startTable(sb);
for (String str : istatStrings) { for (String str : istatStrings) {
addMonospacedRow(sb, str); addMonospacedRow(sb, str);
@ -421,6 +429,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
endTable(sb); endTable(sb);
} }
}
} else { } else {
try { try {
@ -461,7 +470,6 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer {
// Add all the data source paths to the "Local Path" value cell. // Add all the data source paths to the "Local Path" value cell.
String[] imagePaths = image.getPaths(); String[] imagePaths = image.getPaths();
if (imagePaths.length > 0) { if (imagePaths.length > 0) {
addRowWithMultipleValues(sb, addRowWithMultipleValues(sb,
NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.localPath"), NbBundle.getMessage(this.getClass(), "Metadata.tableRowTitle.localPath"),

View File

@ -42,6 +42,7 @@ import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults; import org.sleuthkit.autopsy.contentviewers.layout.ContentViewerDefaults;
import org.sleuthkit.autopsy.contentviewers.osaccount.SectionData.RowData; import org.sleuthkit.autopsy.contentviewers.osaccount.SectionData.RowData;
import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.Host; import org.sleuthkit.datamodel.Host;
@ -191,11 +192,7 @@ public class OsAccountDataPanel extends JPanel {
account.getOsAccountType().isPresent() ? account.getOsAccountType().get().getName() : ""); account.getOsAccountType().isPresent() ? account.getOsAccountType().get().getName() : "");
Optional<Long> crTime = account.getCreationTime(); Optional<Long> crTime = account.getCreationTime();
if (crTime.isPresent()) { data.addData(Bundle.OsAccountDataPanel_basic_creationDate(), crTime.isPresent() ? TimeZoneUtils.getFormattedTime(crTime.get()) : "");
data.addData(Bundle.OsAccountDataPanel_basic_creationDate(), DATE_FORMAT.format(new Date(crTime.get() * 1000)));
} else {
data.addData(Bundle.OsAccountDataPanel_basic_creationDate(), "");
}
return data; return data;
} }

View File

@ -207,7 +207,7 @@ public final class OsAccounts implements AutopsyVisitableItem {
Bundle.OsAccounts_accountRealmNameProperty_name(), Bundle.OsAccounts_accountRealmNameProperty_name(),
Bundle.OsAccounts_accountRealmNameProperty_displayName(), Bundle.OsAccounts_accountRealmNameProperty_displayName(),
Bundle.OsAccounts_accountRealmNameProperty_desc(), Bundle.OsAccounts_accountRealmNameProperty_desc(),
"")); realmNames.get(0)));
} }
} }
} }
@ -308,7 +308,7 @@ public final class OsAccounts implements AutopsyVisitableItem {
Optional<Long> creationTimeValue = account.getCreationTime(); Optional<Long> creationTimeValue = account.getCreationTime();
String timeDisplayStr String timeDisplayStr
= creationTimeValue.isPresent() ? TimeZoneUtils.getFormattedTime(creationTimeValue.get() * 1000) : ""; = creationTimeValue.isPresent() ? TimeZoneUtils.getFormattedTime(creationTimeValue.get()) : "";
propertiesSet.put(new NodeProperty<>( propertiesSet.put(new NodeProperty<>(
Bundle.OsAccounts_createdTimeProperty_name(), Bundle.OsAccounts_createdTimeProperty_name(),

View File

@ -24,6 +24,7 @@ DateFilterPanel.invalidRange.text=Range or Only Last must be selected.
DateFilterPanel.startAfterEnd.text=Start date should be before the end date when both are enabled. DateFilterPanel.startAfterEnd.text=Start date should be before the end date when both are enabled.
DateFilterPanel.startOrEndNeeded.text=A start or end date must be specified to use the range filter. DateFilterPanel.startOrEndNeeded.text=A start or end date must be specified to use the range filter.
DiscoveryDialog.name.text=Discovery DiscoveryDialog.name.text=Discovery
DiscoveryExtractAction.title.extractFiles.text=Extract File
DiscoveryTopComponent.additionalFilters.text=; DiscoveryTopComponent.additionalFilters.text=;
DiscoveryTopComponent.cancelButton.text=Cancel Search DiscoveryTopComponent.cancelButton.text=Cancel Search
DiscoveryTopComponent.domainSearch.text=Type: Domain DiscoveryTopComponent.domainSearch.text=Type: Domain

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy * Autopsy
* *
* Copyright 2019 Basis Technology Corp. * Copyright 2019-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -40,8 +40,9 @@ final class DiscoveryExtractAction extends AbstractAction {
* *
* @param selectedFiles The files to extract from the current case. * @param selectedFiles The files to extract from the current case.
*/ */
@NbBundle.Messages({"DiscoveryExtractAction.title.extractFiles.text=Extract File"})
DiscoveryExtractAction(Collection<AbstractFile> selectedFiles) { DiscoveryExtractAction(Collection<AbstractFile> selectedFiles) {
super(NbBundle.getMessage(DiscoveryExtractAction.class, "DiscoveryExtractAction.title.extractFiles.text")); super(Bundle.DiscoveryExtractAction_title_extractFiles_text());
files.addAll(selectedFiles); files.addAll(selectedFiles);
} }

View File

@ -106,14 +106,4 @@ public interface KeywordSearchService extends Closeable {
* @throws KeywordSearchServiceException if unable to delete. * @throws KeywordSearchServiceException if unable to delete.
*/ */
void deleteDataSource(Long dataSourceId) throws KeywordSearchServiceException; void deleteDataSource(Long dataSourceId) throws KeywordSearchServiceException;
/**
* A flag to enable or disable OCR on all future text indexing.
*
* @param state Boolean flag to enable/disable OCR. Set to True to enable
* OCR, or False to disable it.
*/
@Beta
void changeOcrState(boolean state);
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2020 Basis Technology Corp. * Copyright 2011-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -49,7 +49,6 @@ import org.sleuthkit.autopsy.modules.pictureanalyzer.PictureAnalyzerIngestModule
import org.sleuthkit.datamodel.Blackboard; import org.sleuthkit.datamodel.Blackboard;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF; import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_USER_CONTENT_SUSPECTED;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
@ -150,7 +149,11 @@ public class EXIFProcessor implements PictureProcessor {
if (!attributes.isEmpty() && !blackboard.artifactExists(file, TSK_METADATA_EXIF, attributes)) { if (!attributes.isEmpty() && !blackboard.artifactExists(file, TSK_METADATA_EXIF, attributes)) {
final BlackboardArtifact exifArtifact = file.newDataArtifact(new BlackboardArtifact.Type(TSK_METADATA_EXIF), attributes); final BlackboardArtifact exifArtifact = (file.newAnalysisResult(
BlackboardArtifact.Type.TSK_METADATA_EXIF,
Score.SCORE_NONE,
null, null, null,
attributes)).getAnalysisResult();
final BlackboardArtifact userSuspectedArtifact = file.newAnalysisResult( final BlackboardArtifact userSuspectedArtifact = file.newAnalysisResult(
BlackboardArtifact.Type.TSK_USER_CONTENT_SUSPECTED, Score.SCORE_UNKNOWN, null, null, null, BlackboardArtifact.Type.TSK_USER_CONTENT_SUSPECTED, Score.SCORE_UNKNOWN, null, null, null,

View File

@ -22,6 +22,8 @@ import java.io.Reader;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import org.openide.util.Lookup; import org.openide.util.Lookup;
import org.sleuthkit.autopsy.textextractors.configs.ImageConfig;
import org.sleuthkit.datamodel.AbstractFile;
/** /**
* Extracts the text out of Content instances and exposes them as a Reader. * Extracts the text out of Content instances and exposes them as a Reader.
@ -73,6 +75,16 @@ public interface TextExtractor {
return Collections.emptyMap(); return Collections.emptyMap();
} }
/**
* Returns true if this text extractor, based on the provided settings, will
* perform ocr.
*
* @return True if will perform OCR.
*/
default boolean willUseOCR() {
return false;
}
/** /**
* System level exception for reader initialization. * System level exception for reader initialization.
*/ */

View File

@ -18,7 +18,6 @@
*/ */
package org.sleuthkit.autopsy.textextractors; package org.sleuthkit.autopsy.textextractors;
import com.google.common.collect.ImmutableList;
import com.google.common.io.CharSource; import com.google.common.io.CharSource;
import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.io.File; import java.io.File;
@ -71,12 +70,15 @@ import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Set;
import org.apache.tika.mime.MimeTypes;
import org.apache.tika.parser.pdf.PDFParserConfig.OCR_STRATEGY; import org.apache.tika.parser.pdf.PDFParserConfig.OCR_STRATEGY;
import org.sleuthkit.autopsy.coreutils.ExecUtil.HybridTerminator; import org.sleuthkit.autopsy.coreutils.ExecUtil.HybridTerminator;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
/** /**
* Extracts text from Tika supported content. Protects against Tika parser hangs * Extracts text from Tika supported content. Protects against Tika parser hangs
@ -86,8 +88,8 @@ final class TikaTextExtractor implements TextExtractor {
//Mimetype groups to aassist extractor implementations in ignoring binary and //Mimetype groups to aassist extractor implementations in ignoring binary and
//archive files. //archive files.
private static final List<String> BINARY_MIME_TYPES private static final Set<String> BINARY_MIME_TYPES
= ImmutableList.of( = ImmutableSet.of(
//ignore binary blob data, for which string extraction will be used //ignore binary blob data, for which string extraction will be used
"application/octet-stream", //NON-NLS "application/octet-stream", //NON-NLS
"application/x-msdownload"); //NON-NLS "application/x-msdownload"); //NON-NLS
@ -96,8 +98,8 @@ final class TikaTextExtractor implements TextExtractor {
* generally text extractors should ignore archives and let unpacking * generally text extractors should ignore archives and let unpacking
* modules take care of them * modules take care of them
*/ */
private static final List<String> ARCHIVE_MIME_TYPES private static final Set<String> ARCHIVE_MIME_TYPES
= ImmutableList.of( = ImmutableSet.of(
//ignore unstructured binary and compressed data, for which string extraction or unzipper works better //ignore unstructured binary and compressed data, for which string extraction or unzipper works better
"application/x-7z-compressed", //NON-NLS "application/x-7z-compressed", //NON-NLS
"application/x-ace-compressed", //NON-NLS "application/x-ace-compressed", //NON-NLS
@ -134,22 +136,36 @@ final class TikaTextExtractor implements TextExtractor {
// Used to log to the tika file that is why it uses the java.util.logging.logger class instead of the Autopsy one // Used to log to the tika file that is why it uses the java.util.logging.logger class instead of the Autopsy one
private static final java.util.logging.Logger TIKA_LOGGER = java.util.logging.Logger.getLogger("Tika"); //NON-NLS private static final java.util.logging.Logger TIKA_LOGGER = java.util.logging.Logger.getLogger("Tika"); //NON-NLS
private static final Logger AUTOPSY_LOGGER = Logger.getLogger(TikaTextExtractor.class.getName()); private static final Logger AUTOPSY_LOGGER = Logger.getLogger(TikaTextExtractor.class.getName());
private static final int LIMITED_OCR_SIZE_MIN = 100 * 1024;
private final ThreadFactory tikaThreadFactory private final ThreadFactory tikaThreadFactory
= new ThreadFactoryBuilder().setNameFormat("tika-reader-%d").build(); = new ThreadFactoryBuilder().setNameFormat("tika-reader-%d").build();
private final ExecutorService executorService = Executors.newSingleThreadExecutor(tikaThreadFactory); private final ExecutorService executorService = Executors.newSingleThreadExecutor(tikaThreadFactory);
private static final String SQLITE_MIMETYPE = "application/x-sqlite3"; private static final String SQLITE_MIMETYPE = "application/x-sqlite3";
private final AutoDetectParser parser = new AutoDetectParser(); private final AutoDetectParser parser = new AutoDetectParser();
private final FileTypeDetector fileTypeDetector;
private final Content content; private final Content content;
private boolean tesseractOCREnabled; private boolean tesseractOCREnabled;
private boolean limitedOCREnabled;
private static final String TESSERACT_DIR_NAME = "Tesseract-OCR"; //NON-NLS private static final String TESSERACT_DIR_NAME = "Tesseract-OCR"; //NON-NLS
private static final String TESSERACT_EXECUTABLE = "tesseract.exe"; //NON-NLS private static final String TESSERACT_EXECUTABLE = "tesseract.exe"; //NON-NLS
private static final File TESSERACT_PATH = locateTesseractExecutable(); private static final File TESSERACT_PATH = locateTesseractExecutable();
private String languagePacks = formatLanguagePacks(PlatformUtil.getOcrLanguagePacks()); private String languagePacks = formatLanguagePacks(PlatformUtil.getOcrLanguagePacks());
private static final String TESSERACT_OUTPUT_FILE_NAME = "tess_output"; //NON-NLS private static final String TESSERACT_OUTPUT_FILE_NAME = "tess_output"; //NON-NLS
// documents where OCR is performed
private static final ImmutableSet OCR_DOCUMENTS = ImmutableSet.of(
"application/pdf",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.ms-powerpoint",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
);
private static final String IMAGE_MIME_TYPE_PREFIX = "image/";
private Map<String, String> metadataMap; private Map<String, String> metadataMap;
private ProcessTerminator processTerminator; private ProcessTerminator processTerminator;
@ -162,18 +178,62 @@ final class TikaTextExtractor implements TextExtractor {
TikaTextExtractor(Content content) { TikaTextExtractor(Content content) {
this.content = content; this.content = content;
FileTypeDetector detector = null;
try {
detector = new FileTypeDetector();
} catch (FileTypeDetector.FileTypeDetectorInitException ex) {
TIKA_LOGGER.log(Level.SEVERE, "Unable to instantiate a file type detector", ex);
}
this.fileTypeDetector = detector;
} }
/** /**
* If Tesseract has been installed and is set to be used through * Obtains the mime type of the file using a FileTypeDetector with the
* configuration, then ocr is enabled. OCR can only currently be run on 64 * file's mime type as fallback if the FileTypeDetector is not instantiated.
* bit Windows OS. * If no mime type present, MimeTypes.OCTET_STREAM is returned.
* *
* @return Flag indicating if OCR is set to be used. * @param file The abstract file instance.
*
* @return The mime type or MimeTypes.OCTET_STREAM if the mime type cannot
* be determined.
*/ */
private boolean ocrEnabled() { private String getMimeType(AbstractFile file) {
return TESSERACT_PATH != null && tesseractOCREnabled String mimeType = MimeTypes.OCTET_STREAM;
&& PlatformUtil.isWindowsOS() == true && PlatformUtil.is64BitOS(); if (fileTypeDetector != null) {
mimeType = fileTypeDetector.getMIMEType(file);
} else if (file.getMIMEType() != null) {
mimeType = file.getMIMEType();
}
return mimeType.trim().toLowerCase();
}
@Override
public boolean willUseOCR() {
if (!isOcrSupported() || (!(content instanceof AbstractFile))) {
return false;
}
String mimeType = getMimeType((AbstractFile) content);
// in order to ocr, it needs to either be an image or a document with embedded content
return mimeType.startsWith(IMAGE_MIME_TYPE_PREFIX) || OCR_DOCUMENTS.contains(mimeType);
}
/**
* Whether or not OCR is supported in environment.
*
* @return True if OCR is supported.
*/
private boolean isOcrSupported() {
// If Tesseract has been installed and is set to be used through
// configuration, then ocr is enabled. OCR can only currently be run on 64
// bit Windows OS.
return TESSERACT_PATH != null
&& tesseractOCREnabled
&& PlatformUtil.isWindowsOS()
&& PlatformUtil.is64BitOS()
&& isSupported();
} }
/** /**
@ -195,33 +255,31 @@ final class TikaTextExtractor implements TextExtractor {
// Only abstract files are supported, see isSupported() // Only abstract files are supported, see isSupported()
final AbstractFile file = ((AbstractFile) content); final AbstractFile file = ((AbstractFile) content);
// This mime type must be non-null, see isSupported()
final String mimeType = file.getMIMEType(); String mimeType = getMimeType(file);
// Handle images seperately so the OCR task can be cancelled. // Handle images seperately so the OCR task can be cancelled.
// See JIRA-4519 for the need to have cancellation in the UI and ingest. // See JIRA-4519 for the need to have cancellation in the UI and ingest.
if (ocrEnabled() && mimeType.toLowerCase().startsWith("image/") && useOcrOnFile(file)) { if (isOcrSupported() && mimeType.startsWith(IMAGE_MIME_TYPE_PREFIX)) {
InputStream imageOcrStream = performOCR(file); InputStream imageOcrStream = performOCR(file);
return new InputStreamReader(imageOcrStream, Charset.forName("UTF-8")); return new InputStreamReader(imageOcrStream, Charset.forName("UTF-8"));
} }
// Set up Tika // Set up Tika
final InputStream stream = new ReadContentInputStream(content); final InputStream stream = new ReadContentInputStream(content);
final ParseContext parseContext = new ParseContext();
final ParseContext parseContext = new ParseContext();
// Documents can contain other documents. By adding // Documents can contain other documents. By adding
// the parser back into the context, Tika will recursively // the parser back into the context, Tika will recursively
// parse embedded documents. // parse embedded documents.
parseContext.set(Parser.class, parser); parseContext.set(Parser.class, parser);
// Use the more memory efficient Tika SAX parsers for DOCX and // Use the more memory efficient Tika SAX parsers for DOCX and
// PPTX files (it already uses SAX for XLSX). // PPTX files (it already uses SAX for XLSX).
OfficeParserConfig officeParserConfig = new OfficeParserConfig(); OfficeParserConfig officeParserConfig = new OfficeParserConfig();
officeParserConfig.setUseSAXPptxExtractor(true); officeParserConfig.setUseSAXPptxExtractor(true);
officeParserConfig.setUseSAXDocxExtractor(true); officeParserConfig.setUseSAXDocxExtractor(true);
parseContext.set(OfficeParserConfig.class, officeParserConfig); parseContext.set(OfficeParserConfig.class, officeParserConfig);
if (isOcrSupported()) {
if (ocrEnabled() && useOcrOnFile(file)) {
// Configure OCR for Tika if it chooses to run OCR // Configure OCR for Tika if it chooses to run OCR
// during extraction // during extraction
TesseractOCRConfig ocrConfig = new TesseractOCRConfig(); TesseractOCRConfig ocrConfig = new TesseractOCRConfig();
@ -347,22 +405,6 @@ final class TikaTextExtractor implements TextExtractor {
} }
} }
/**
* Method to indicate if OCR should be performed on this image file. Checks
* to see if the limited OCR setting is enabled. If it is it will also check
* that one of the limiting factors is true.
*
* @param file The AbstractFile which OCR might be performed on.
* @param boolean The configuration setting which indicates if limited OCR
* is enabled in Keyword Search.
*
* @return True if limited OCR is not enabled or the image is greater than
* 100KB in size or the image is a derived file.
*/
private boolean useOcrOnFile(AbstractFile file) {
return !limitedOCREnabled || file.getSize() > LIMITED_OCR_SIZE_MIN || file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED;
}
/** /**
* Wraps the creation of a TikaReader into a Future so that it can be * Wraps the creation of a TikaReader into a Future so that it can be
* cancelled. * cancelled.
@ -552,7 +594,6 @@ final class TikaTextExtractor implements TextExtractor {
ImageConfig configInstance = context.lookup(ImageConfig.class); ImageConfig configInstance = context.lookup(ImageConfig.class);
if (configInstance != null) { if (configInstance != null) {
this.tesseractOCREnabled = configInstance.getOCREnabled(); this.tesseractOCREnabled = configInstance.getOCREnabled();
this.limitedOCREnabled = configInstance.getLimitedOCREnabled();
if (Objects.nonNull(configInstance.getOCRLanguages())) { if (Objects.nonNull(configInstance.getOCRLanguages())) {
this.languagePacks = formatLanguagePacks(configInstance.getOCRLanguages()); this.languagePacks = formatLanguagePacks(configInstance.getOCRLanguages());

View File

@ -35,7 +35,6 @@ public class ImageConfig {
private static final int OCR_TIMEOUT_SECONDS = 30 * 60; private static final int OCR_TIMEOUT_SECONDS = 30 * 60;
private boolean OCREnabled = false; private boolean OCREnabled = false;
private boolean limitedOCREnabled = false;
private List<String> ocrLanguages = null; private List<String> ocrLanguages = null;
private final TimedProcessTerminator ocrTimedTerminator = new TimedProcessTerminator(OCR_TIMEOUT_SECONDS); private final TimedProcessTerminator ocrTimedTerminator = new TimedProcessTerminator(OCR_TIMEOUT_SECONDS);
@ -49,16 +48,6 @@ public class ImageConfig {
this.OCREnabled = enabled; this.OCREnabled = enabled;
} }
/**
* Enables the limiting OCR to be run on larger images and images which were
* extracted from documents.
*
* @param enabled Flag indicating if OCR is enabled.
*/
public void setLimitedOCREnabled(boolean enabled) {
this.limitedOCREnabled = enabled;
}
/** /**
* Gets the OCR flag that has been set. By default this flag is turned off. * Gets the OCR flag that has been set. By default this flag is turned off.
* *
@ -98,15 +87,4 @@ public class ImageConfig {
public ProcessTerminator getOCRTimeoutTerminator() { public ProcessTerminator getOCRTimeoutTerminator() {
return ocrTimedTerminator; return ocrTimedTerminator;
} }
/**
* Gets the limited OCR flag to indicate if OCR should be limited to larger
* images and images which were extracted from documents.
*
* @return Flag indicating if limited OCR is enabled. True if OCR should be
* limited, false otherwise..
*/
public boolean getLimitedOCREnabled() {
return limitedOCREnabled;
}
} }

View File

@ -1270,7 +1270,7 @@ public class CentralRepoDatamodelTest extends TestCase {
// We expect 10 - the custom type is disabled // We expect 10 - the custom type is disabled
// Note: this test will need to be updated based on the current default items defined in the correlation_types table // Note: this test will need to be updated based on the current default items defined in the correlation_types table
assertTrue("getDefinedCorrelationTypes returned " + types.size() + " enabled entries - expected 27", types.size() == 27); assertTrue("getDefinedCorrelationTypes returned " + types.size() + " enabled entries - expected 29", types.size() == 29);
} catch (CentralRepoException ex) { } catch (CentralRepoException ex) {
Exceptions.printStackTrace(ex); Exceptions.printStackTrace(ex);
Assert.fail(ex.getMessage()); Assert.fail(ex.getMessage());
@ -1282,7 +1282,7 @@ public class CentralRepoDatamodelTest extends TestCase {
// We expect 10 - the custom type is not supported // We expect 10 - the custom type is not supported
// Note: this test will need to be updated based on the current default items defined in the correlation_types table // Note: this test will need to be updated based on the current default items defined in the correlation_types table
assertTrue("getDefinedCorrelationTypes returned " + types.size() + " supported entries - expected 27", types.size() == 27); assertTrue("getDefinedCorrelationTypes returned " + types.size() + " supported entries - expected 29", types.size() == 29);
} catch (CentralRepoException ex) { } catch (CentralRepoException ex) {
Exceptions.printStackTrace(ex); Exceptions.printStackTrace(ex);
Assert.fail(ex.getMessage()); Assert.fail(ex.getMessage());

View File

@ -144,7 +144,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>10</release-version> <release-version>10</release-version>
<specification-version>10.23</specification-version> <specification-version>10.24</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -105,11 +105,11 @@ import org.sleuthkit.autopsy.ingest.IngestModuleError;
import org.sleuthkit.autopsy.ingest.IngestStream; import org.sleuthkit.autopsy.ingest.IngestStream;
import org.sleuthkit.autopsy.keywordsearch.KeywordSearchModuleException; import org.sleuthkit.autopsy.keywordsearch.KeywordSearchModuleException;
import org.sleuthkit.autopsy.keywordsearch.Server; import org.sleuthkit.autopsy.keywordsearch.Server;
import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.keywordsearch.KeywordSearchJobSettings;
/** /**
* An auto ingest manager is responsible for processing auto ingest jobs defined * An auto ingest manager is responsible for processing auto ingest jobs defined
@ -2295,15 +2295,6 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
currentJob.setProcessingStage(AutoIngestJob.Stage.UPDATING_SHARED_CONFIG, Date.from(Instant.now())); currentJob.setProcessingStage(AutoIngestJob.Stage.UPDATING_SHARED_CONFIG, Date.from(Instant.now()));
new SharedConfiguration().downloadConfiguration(); new SharedConfiguration().downloadConfiguration();
} }
// update the OCR enabled/disabled setting
if (currentJob.getOcrEnabled()) {
sysLogger.log(Level.INFO, "Enabling OCR for job {0}", currentJob.getManifest().getFilePath());
} else {
sysLogger.log(Level.INFO, "Disabling OCR for job {0}", currentJob.getManifest().getFilePath());
}
KeywordSearchService kwsService = Lookup.getDefault().lookup(KeywordSearchService.class);
kwsService.changeOcrState(currentJob.getOcrEnabled());
} }
/** /**
@ -2755,6 +2746,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
} }
} }
/** /**
* Analyzes the data source content returned by the data source * Analyzes the data source content returned by the data source
* processor using the configured set of data source level and file * processor using the configured set of data source level and file
@ -2798,6 +2790,20 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
throw new AnalysisStartupException("Error(s) in ingest job settings"); throw new AnalysisStartupException("Error(s) in ingest job settings");
} }
// update the OCR enabled/disabled setting
if (currentJob.getOcrEnabled()) {
sysLogger.log(Level.INFO, "Enabling OCR for job {0}", currentJob.getManifest().getFilePath());
} else {
sysLogger.log(Level.INFO, "Disabling OCR for job {0}", currentJob.getManifest().getFilePath());
}
// find the KeywordSearchJobSettings instance in the templates, and if present, set ocr enabled
ingestJobSettings.getIngestModuleTemplates().stream()
.filter(template -> template.getModuleSettings() instanceof KeywordSearchJobSettings)
.map(template -> (KeywordSearchJobSettings) template.getModuleSettings())
.findFirst()
.ifPresent((keywordJobSettings) -> keywordJobSettings.setOCREnabled(currentJob.getOcrEnabled()));
ingestJobStartResult = IngestManager.getInstance().beginIngestJob(dataSource.getContent(), ingestJobSettings); ingestJobStartResult = IngestManager.getInstance().beginIngestJob(dataSource.getContent(), ingestJobSettings);
ingestJob = ingestJobStartResult.getJob(); ingestJob = ingestJobStartResult.getJob();
@ -2862,6 +2868,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
} }
} }
/** /**
* Gather metrics to store in auto ingest job nodes. A SleuthkitCase * Gather metrics to store in auto ingest job nodes. A SleuthkitCase
* instance is used to get the content size. * instance is used to get the content size.

View File

@ -127,7 +127,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>10</release-version> <release-version>10</release-version>
<specification-version>10.23</specification-version> <specification-version>10.24</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -1,7 +1,7 @@
Manifest-Version: 1.0 Manifest-Version: 1.0
AutoUpdate-Show-In-Client: true AutoUpdate-Show-In-Client: true
OpenIDE-Module: org.sleuthkit.autopsy.keywordsearch/6 OpenIDE-Module: org.sleuthkit.autopsy.keywordsearch/6
OpenIDE-Module-Implementation-Version: 22 OpenIDE-Module-Implementation-Version: 23
OpenIDE-Module-Install: org/sleuthkit/autopsy/keywordsearch/Installer.class OpenIDE-Module-Install: org/sleuthkit/autopsy/keywordsearch/Installer.class
OpenIDE-Module-Layer: org/sleuthkit/autopsy/keywordsearch/layer.xml OpenIDE-Module-Layer: org/sleuthkit/autopsy/keywordsearch/layer.xml
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/keywordsearch/Bundle.properties OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/keywordsearch/Bundle.properties

View File

@ -128,7 +128,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>10</release-version> <release-version>10</release-version>
<specification-version>10.23</specification-version> <specification-version>10.24</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -319,5 +319,6 @@ ExtractedContentPanel.pageTotalLabel.text=-
ExtractedContentPanel.pageOfLabel.text=of ExtractedContentPanel.pageOfLabel.text=of
ExtractedContentPanel.pageCurLabel.text=- ExtractedContentPanel.pageCurLabel.text=-
ExtractedContentPanel.pagesLabel.text=Page: ExtractedContentPanel.pagesLabel.text=Page:
KeywordSearchGlobalSearchSettingsPanel.ocrCheckBox.text=Enable Optical Character Recognition (OCR) KeywordSearchJobSettingsPanel.ocrCheckBox.text=Enable Optical Character Recognition (OCR)
KeywordSearchGlobalSearchSettingsPanel.limitedOcrCheckbox.text=Only process images which are over 100KB in size or extracted from a document (Beta) KeywordSearchJobSettingsPanel.limitedOcrCheckbox.text=<html>Only process PDFs, MS Office docs and images which are over 100KB in size or extracted from another file (Beta)</html>
KeywordSearchJobSettingsPanel.ocrOnlyCheckbox.text=Only index text extracted using OCR

View File

@ -402,8 +402,9 @@ ExtractedContentPanel.pageTotalLabel.text=-
ExtractedContentPanel.pageOfLabel.text=of ExtractedContentPanel.pageOfLabel.text=of
ExtractedContentPanel.pageCurLabel.text=- ExtractedContentPanel.pageCurLabel.text=-
ExtractedContentPanel.pagesLabel.text=Page: ExtractedContentPanel.pagesLabel.text=Page:
KeywordSearchGlobalSearchSettingsPanel.ocrCheckBox.text=Enable Optical Character Recognition (OCR) KeywordSearchJobSettingsPanel.ocrCheckBox.text=Enable Optical Character Recognition (OCR)
KeywordSearchGlobalSearchSettingsPanel.limitedOcrCheckbox.text=Only process images which are over 100KB in size or extracted from a document (Beta) KeywordSearchJobSettingsPanel.limitedOcrCheckbox.text=<html>Only process images which are over 100KB in size or extracted from a document (Beta)</html>
KeywordSearchJobSettingsPanel.ocrOnlyCheckbox.text=Only index text extracted using OCR
TextZoomPanel.zoomInButton.text= TextZoomPanel.zoomInButton.text=
TextZoomPanel.zoomOutButton.text= TextZoomPanel.zoomOutButton.text=
TextZoomPanel.zoomResetButton.text=Reset TextZoomPanel.zoomResetButton.text=Reset

View File

@ -388,3 +388,4 @@ SolrSearchService.exceptionMessage.noCurrentSolrCore=IndexMetadata\u306b\u306f\u
SolrSearchService.exceptionMessage.noIndexMetadata=\u30b1\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30fc\u304b\u3089\u6b21\u306eIndexMetaData\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\: {0} SolrSearchService.exceptionMessage.noIndexMetadata=\u30b1\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30fc\u304b\u3089\u6b21\u306eIndexMetaData\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\: {0}
SolrSearchService.exceptionMessage.unableToDeleteCollection=\u30b3\u30ec\u30af\u30b7\u30e7\u30f3{0}\u3092\u524a\u9664\u3067\u304d\u307e\u305b\u3093 SolrSearchService.exceptionMessage.unableToDeleteCollection=\u30b3\u30ec\u30af\u30b7\u30e7\u30f3{0}\u3092\u524a\u9664\u3067\u304d\u307e\u305b\u3093
TextZoomPanel.zoomResetButton.text=\u30ea\u30bb\u30c3\u30c8 TextZoomPanel.zoomResetButton.text=\u30ea\u30bb\u30c3\u30c8
KeywordSearchJobSettingsPanel.ocrCheckBox.text=OCR\u6587\u5b57\u8a8d\u8b58\u3092\u6709\u52b9\u306b\u3059\u308b

View File

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

View File

@ -50,13 +50,9 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
private void activateWidgets() { private void activateWidgets() {
skipNSRLCheckBox.setSelected(KeywordSearchSettings.getSkipKnown()); skipNSRLCheckBox.setSelected(KeywordSearchSettings.getSkipKnown());
showSnippetsCB.setSelected(KeywordSearchSettings.getShowSnippets()); showSnippetsCB.setSelected(KeywordSearchSettings.getShowSnippets());
ocrCheckBox.setSelected(KeywordSearchSettings.getOcrOption());
limitedOcrCheckbox.setSelected(KeywordSearchSettings.getLimitedOcrOption());
boolean ingestRunning = IngestManager.getInstance().isIngestRunning(); boolean ingestRunning = IngestManager.getInstance().isIngestRunning();
ingestWarningLabel.setVisible(ingestRunning); ingestWarningLabel.setVisible(ingestRunning);
skipNSRLCheckBox.setEnabled(!ingestRunning); skipNSRLCheckBox.setEnabled(!ingestRunning);
ocrCheckBox.setEnabled(!ingestRunning);
limitedOcrCheckbox.setEnabled(ocrCheckBox.isSelected() && !ingestRunning);
setTimeSettingEnabled(!ingestRunning); setTimeSettingEnabled(!ingestRunning);
final UpdateFrequency curFreq = KeywordSearchSettings.getUpdateFrequency(); final UpdateFrequency curFreq = KeywordSearchSettings.getUpdateFrequency();
@ -111,8 +107,6 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
showSnippetsCB = new javax.swing.JCheckBox(); showSnippetsCB = new javax.swing.JCheckBox();
timeRadioButton5 = new javax.swing.JRadioButton(); timeRadioButton5 = new javax.swing.JRadioButton();
ingestWarningLabel = new javax.swing.JLabel(); ingestWarningLabel = new javax.swing.JLabel();
ocrCheckBox = new javax.swing.JCheckBox();
limitedOcrCheckbox = new javax.swing.JCheckBox();
skipNSRLCheckBox.setText(org.openide.util.NbBundle.getMessage(KeywordSearchGlobalSearchSettingsPanel.class, "KeywordSearchGlobalSearchSettingsPanel.skipNSRLCheckBox.text")); // NOI18N skipNSRLCheckBox.setText(org.openide.util.NbBundle.getMessage(KeywordSearchGlobalSearchSettingsPanel.class, "KeywordSearchGlobalSearchSettingsPanel.skipNSRLCheckBox.text")); // NOI18N
skipNSRLCheckBox.setToolTipText(org.openide.util.NbBundle.getMessage(KeywordSearchGlobalSearchSettingsPanel.class, "KeywordSearchGlobalSearchSettingsPanel.skipNSRLCheckBox.toolTipText")); // NOI18N skipNSRLCheckBox.setToolTipText(org.openide.util.NbBundle.getMessage(KeywordSearchGlobalSearchSettingsPanel.class, "KeywordSearchGlobalSearchSettingsPanel.skipNSRLCheckBox.toolTipText")); // NOI18N
@ -186,20 +180,6 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
ingestWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/hashdatabase/warning16.png"))); // NOI18N ingestWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/hashdatabase/warning16.png"))); // NOI18N
ingestWarningLabel.setText(org.openide.util.NbBundle.getMessage(KeywordSearchGlobalSearchSettingsPanel.class, "KeywordSearchGlobalSearchSettingsPanel.ingestWarningLabel.text")); // NOI18N ingestWarningLabel.setText(org.openide.util.NbBundle.getMessage(KeywordSearchGlobalSearchSettingsPanel.class, "KeywordSearchGlobalSearchSettingsPanel.ingestWarningLabel.text")); // NOI18N
ocrCheckBox.setText(org.openide.util.NbBundle.getMessage(KeywordSearchGlobalSearchSettingsPanel.class, "KeywordSearchGlobalSearchSettingsPanel.ocrCheckBox.text")); // NOI18N
ocrCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
ocrCheckBoxActionPerformed(evt);
}
});
limitedOcrCheckbox.setText(org.openide.util.NbBundle.getMessage(KeywordSearchGlobalSearchSettingsPanel.class, "KeywordSearchGlobalSearchSettingsPanel.limitedOcrCheckbox.text")); // NOI18N
limitedOcrCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
limitedOcrCheckboxActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout); this.setLayout(layout);
layout.setHorizontalGroup( layout.setHorizontalGroup(
@ -207,13 +187,15 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(ingestWarningLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup()
.addGap(16, 16, 16)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(skipNSRLCheckBox)
.addComponent(showSnippetsCB))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .addComponent(ingestWarningLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(settingsLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(settingsSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 326, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addComponent(informationLabel) .addComponent(informationLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -221,14 +203,15 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGap(16, 16, 16) .addGap(16, 16, 16)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(skipNSRLCheckBox)
.addComponent(showSnippetsCB)
.addComponent(ocrCheckBox)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addComponent(filesIndexedLabel) .addComponent(filesIndexedLabel)
.addGap(18, 18, 18) .addGap(18, 18, 18)
.addComponent(filesIndexedValue)) .addComponent(filesIndexedValue))
.addComponent(frequencyLabel) .addComponent(frequencyLabel)
.addGroup(layout.createSequentialGroup()
.addComponent(chunksLabel)
.addGap(18, 18, 18)
.addComponent(chunksValLabel))
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGap(16, 16, 16) .addGap(16, 16, 16)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -236,16 +219,13 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
.addComponent(timeRadioButton1) .addComponent(timeRadioButton1)
.addComponent(timeRadioButton3) .addComponent(timeRadioButton3)
.addComponent(timeRadioButton4) .addComponent(timeRadioButton4)
.addComponent(timeRadioButton5))) .addComponent(timeRadioButton5))))))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addComponent(chunksLabel) .addComponent(settingsLabel)
.addGap(18, 18, 18) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(chunksValLabel)) .addComponent(settingsSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 326, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGroup(layout.createSequentialGroup() .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
.addGap(16, 16, 16)
.addComponent(limitedOcrCheckbox)))))
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
); );
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {chunksLabel, filesIndexedLabel}); layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {chunksLabel, filesIndexedLabel});
@ -262,10 +242,6 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(showSnippetsCB) .addComponent(showSnippetsCB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(ocrCheckBox)
.addGap(0, 0, 0)
.addComponent(limitedOcrCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(frequencyLabel) .addComponent(frequencyLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(timeRadioButton1) .addComponent(timeRadioButton1)
@ -323,15 +299,6 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_timeRadioButton4ActionPerformed }//GEN-LAST:event_timeRadioButton4ActionPerformed
private void ocrCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ocrCheckBoxActionPerformed
limitedOcrCheckbox.setEnabled(ocrCheckBox.isSelected());
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_ocrCheckBoxActionPerformed
private void limitedOcrCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_limitedOcrCheckboxActionPerformed
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_limitedOcrCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel chunksLabel; private javax.swing.JLabel chunksLabel;
private javax.swing.JLabel chunksValLabel; private javax.swing.JLabel chunksValLabel;
@ -341,8 +308,6 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
private javax.swing.JLabel informationLabel; private javax.swing.JLabel informationLabel;
private javax.swing.JSeparator informationSeparator; private javax.swing.JSeparator informationSeparator;
private javax.swing.JLabel ingestWarningLabel; private javax.swing.JLabel ingestWarningLabel;
private javax.swing.JCheckBox limitedOcrCheckbox;
private javax.swing.JCheckBox ocrCheckBox;
private javax.swing.JLabel settingsLabel; private javax.swing.JLabel settingsLabel;
private javax.swing.JSeparator settingsSeparator; private javax.swing.JSeparator settingsSeparator;
private javax.swing.JCheckBox showSnippetsCB; private javax.swing.JCheckBox showSnippetsCB;
@ -360,8 +325,6 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
KeywordSearchSettings.setSkipKnown(skipNSRLCheckBox.isSelected()); KeywordSearchSettings.setSkipKnown(skipNSRLCheckBox.isSelected());
KeywordSearchSettings.setUpdateFrequency(getSelectedTimeValue()); KeywordSearchSettings.setUpdateFrequency(getSelectedTimeValue());
KeywordSearchSettings.setShowSnippets(showSnippetsCB.isSelected()); KeywordSearchSettings.setShowSnippets(showSnippetsCB.isSelected());
KeywordSearchSettings.setOcrOption(ocrCheckBox.isSelected());
KeywordSearchSettings.setLimitedOcrOption(limitedOcrCheckbox.isSelected());
} }
@Override @Override
@ -412,15 +375,6 @@ class KeywordSearchGlobalSearchSettingsPanel extends javax.swing.JPanel implemen
logger.log(Level.WARNING, "Could not get number of indexed files/chunks"); //NON-NLS logger.log(Level.WARNING, "Could not get number of indexed files/chunks"); //NON-NLS
} }
if (!PlatformUtil.isWindowsOS() || !PlatformUtil.is64BitOS()) {
ocrCheckBox.setText(Bundle.KeywordSearchGlobalSearchSettingsPanel_customizeComponents_windowsOCR());
ocrCheckBox.setSelected(false);
ocrCheckBox.setEnabled(false);
limitedOcrCheckbox.setSelected(false);
limitedOcrCheckbox.setEnabled(false);
limitedOcrCheckbox.setText(Bundle.KeywordSearchGlobalSearchSettingsPanel_customizeComponents_windowsLimitedOCR());
}
KeywordSearch.addNumIndexedFilesChangeListener( KeywordSearch.addNumIndexedFilesChangeListener(
new PropertyChangeListener() { new PropertyChangeListener() {
@Override @Override

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2019 Basis Technology Corp. * Copyright 2011-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.keywordsearch;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.CharSource; import com.google.common.io.CharSource;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
@ -32,6 +33,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import static java.util.Locale.US; import static java.util.Locale.US;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -43,7 +45,6 @@ import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.ExecUtil.ProcessTerminator; import org.sleuthkit.autopsy.coreutils.ExecUtil.ProcessTerminator;
import org.sleuthkit.autopsy.coreutils.ExecUtil.TimedProcessTerminator;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.autopsy.ingest.FileIngestModule;
@ -87,6 +88,8 @@ import org.sleuthkit.datamodel.TskData.FileKnown;
}) })
public final class KeywordSearchIngestModule implements FileIngestModule { public final class KeywordSearchIngestModule implements FileIngestModule {
private static final int LIMITED_OCR_SIZE_MIN = 100 * 1024;
/** /**
* generally text extractors should ignore archives and let unpacking * generally text extractors should ignore archives and let unpacking
* modules take care of them * modules take care of them
@ -145,6 +148,18 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
.put("pdf:PDFVersion", BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VERSION) .put("pdf:PDFVersion", BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VERSION)
.build(); .build();
private static final String IMAGE_MIME_TYPE_PREFIX = "image/";
// documents where OCR is performed
private static final ImmutableSet<String> OCR_DOCUMENTS = ImmutableSet.of(
"application/pdf",
"application/msword",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.ms-powerpoint",
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
"application/vnd.ms-excel",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
);
/** /**
* Options for this extractor * Options for this extractor
@ -350,12 +365,31 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
return ProcessResult.OK; return ProcessResult.OK;
} }
// if ocr only is enabled and not an ocr file, return
Optional<TextExtractor> extractorOpt = getExtractor(abstractFile);
String mimeType = fileTypeDetector.getMIMEType(abstractFile).trim().toLowerCase();
if (settings.isOCREnabled()) {
// if ocr only and the extractor is not present or will not perform ocr on this file, continue
if (settings.isOCROnly() && (!extractorOpt.isPresent() || !extractorOpt.get().willUseOCR())) {
return ProcessResult.OK;
}
// if limited ocr is enabled, the extractor will use ocr, and
// the file would not be subject to limited ocr reading, continue
if (settings.isLimitedOCREnabled() && extractorOpt.isPresent()
&& extractorOpt.get().willUseOCR() && !isLimitedOCRFile(abstractFile, mimeType)) {
return ProcessResult.OK;
}
}
if (KeywordSearchSettings.getSkipKnown() && abstractFile.getKnown().equals(FileKnown.KNOWN)) { if (KeywordSearchSettings.getSkipKnown() && abstractFile.getKnown().equals(FileKnown.KNOWN)) {
//index meta-data only //index meta-data only
if (context.fileIngestIsCancelled()) { if (context.fileIngestIsCancelled()) {
return ProcessResult.OK; return ProcessResult.OK;
} }
indexer.indexFile(abstractFile, false); indexer.indexFile(extractorOpt, abstractFile, mimeType, false);
return ProcessResult.OK; return ProcessResult.OK;
} }
@ -363,7 +397,7 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
if (context.fileIngestIsCancelled()) { if (context.fileIngestIsCancelled()) {
return ProcessResult.OK; return ProcessResult.OK;
} }
indexer.indexFile(abstractFile, true); indexer.indexFile(extractorOpt, abstractFile, mimeType, true);
// Start searching if it hasn't started already // Start searching if it hasn't started already
if (!startedSearching) { if (!startedSearching) {
@ -427,6 +461,29 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
initialized = false; initialized = false;
} }
/**
* Returns true if file should have OCR performed on it when limited OCR
* setting is specified.
*
* @param aFile The abstract file.
* @param mimeType The file mime type.
*
* @return True if file should have text extracted when limited OCR setting
* is on.
*/
private boolean isLimitedOCRFile(AbstractFile aFile, String mimeType) {
if (OCR_DOCUMENTS.contains(mimeType)) {
return true;
}
if (mimeType.startsWith(IMAGE_MIME_TYPE_PREFIX)) {
return aFile.getSize() > LIMITED_OCR_SIZE_MIN
|| aFile.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED;
}
return false;
}
/** /**
* Posts inbox message with summary of text_ingested files * Posts inbox message with summary of text_ingested files
*/ */
@ -489,6 +546,18 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
} }
} }
private Optional<TextExtractor> getExtractor(AbstractFile abstractFile) {
ImageConfig imageConfig = new ImageConfig();
imageConfig.setOCREnabled(settings.isOCREnabled());
ProcessTerminator terminator = () -> context.fileIngestIsCancelled();
Lookup extractionContext = Lookups.fixed(imageConfig, terminator);
try {
return Optional.ofNullable(TextExtractorFactory.getExtractor(abstractFile, extractionContext));
} catch (TextExtractorFactory.NoTextExtractorFound ex) {
return Optional.empty();
}
}
/** /**
* File indexer, processes and indexes known/allocated files, * File indexer, processes and indexes known/allocated files,
* unknown/unallocated files and directories accordingly * unknown/unallocated files and directories accordingly
@ -502,25 +571,26 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
* streaming) from the file Divide the file into chunks and index the * streaming) from the file Divide the file into chunks and index the
* chunks * chunks
* *
* @param aFile file to extract strings from, divide into chunks and * @param extractorOptional The textExtractor to use with this file or
* index * empty.
* @param extractedMetadata Map that will be populated with the file's metadata. * @param aFile file to extract strings from, divide into
* chunks and index
* @param extractedMetadata Map that will be populated with the file's
* metadata.
* *
* @return true if the file was text_ingested, false otherwise * @return true if the file was text_ingested, false otherwise
* *
* @throws IngesterException exception thrown if indexing failed * @throws IngesterException exception thrown if indexing failed
*/ */
private boolean extractTextAndIndex(AbstractFile aFile, Map<String, String> extractedMetadata) throws IngesterException { private boolean extractTextAndIndex(Optional<TextExtractor> extractorOptional, AbstractFile aFile,
ImageConfig imageConfig = new ImageConfig(); Map<String, String> extractedMetadata) throws IngesterException {
imageConfig.setOCREnabled(KeywordSearchSettings.getOcrOption());
imageConfig.setLimitedOCREnabled(KeywordSearchSettings.getLimitedOcrOption());
ProcessTerminator terminator = () -> context.fileIngestIsCancelled();
Lookup extractionContext = Lookups.fixed(imageConfig, terminator);
try { try {
TextExtractor extractor = TextExtractorFactory.getExtractor(aFile, extractionContext); if (!extractorOptional.isPresent()) {
return false;
}
TextExtractor extractor = extractorOptional.get();
Reader fileText = extractor.getReader(); Reader fileText = extractor.getReader();
Reader finalReader; Reader finalReader;
try { try {
Map<String, String> metadata = extractor.getMetadata(); Map<String, String> metadata = extractor.getMetadata();
@ -547,8 +617,8 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
} }
//divide into chunks and index //divide into chunks and index
return Ingester.getDefault().indexText(finalReader, aFile.getId(), aFile.getName(), aFile, context); return Ingester.getDefault().indexText(finalReader, aFile.getId(), aFile.getName(), aFile, context);
} catch (TextExtractorFactory.NoTextExtractorFound | TextExtractor.InitReaderException ex) { } catch (TextExtractor.InitReaderException ex) {
//No text extractor found... run the default instead // Text extractor could not be initialized. No text will be extracted.
return false; return false;
} }
} }
@ -588,7 +658,6 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
} }
} }
private BlackboardAttribute checkAttribute(String key, String value) { private BlackboardAttribute checkAttribute(String key, String value) {
String moduleName = KeywordSearchIngestModule.class.getName(); String moduleName = KeywordSearchIngestModule.class.getName();
if (!value.isEmpty() && value.charAt(0) != ' ') { if (!value.isEmpty() && value.charAt(0) != ' ') {
@ -614,7 +683,6 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
} }
/** /**
* Pretty print the text extractor metadata. * Pretty print the text extractor metadata.
* *
@ -668,21 +736,24 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
/** /**
* Adds the file to the index. Detects file type, calls extractors, etc. * Adds the file to the index. Detects file type, calls extractors, etc.
* *
* @param aFile File to analyze * @param extractor The textExtractor to use with this file or empty
* if no extractor found.
* @param aFile File to analyze.
* @param mimeType The file mime type.
* @param indexContent False if only metadata should be text_ingested. * @param indexContent False if only metadata should be text_ingested.
* True if content and metadata should be index. * True if content and metadata should be index.
*/ */
private void indexFile(AbstractFile aFile, boolean indexContent) { private void indexFile(Optional<TextExtractor> extractor, AbstractFile aFile, String mimeType, boolean indexContent) {
//logger.log(Level.INFO, "Processing AbstractFile: " + abstractFile.getName()); //logger.log(Level.INFO, "Processing AbstractFile: " + abstractFile.getName());
TskData.TSK_DB_FILES_TYPE_ENUM aType = aFile.getType(); TskData.TSK_DB_FILES_TYPE_ENUM aType = aFile.getType();
/** /**
* Extract unicode strings from unallocated and unused blocks and * Extract unicode strings from unallocated and unused blocks and
* carved text files. The reason for performing string extraction * carved text files. The reason for performing string extraction on
* on these is because they all may contain multiple encodings which * these is because they all may contain multiple encodings which
* can cause text to be missed by the more specialized text extractors * can cause text to be missed by the more specialized text
* used below. * extractors used below.
*/ */
if ((aType.equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) if ((aType.equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
|| aType.equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)) || aType.equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS))
@ -714,11 +785,10 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
if (context.fileIngestIsCancelled()) { if (context.fileIngestIsCancelled()) {
return; return;
} }
String fileType = fileTypeDetector.getMIMEType(aFile);
// we skip archive formats that are opened by the archive module. // we skip archive formats that are opened by the archive module.
// @@@ We could have a check here to see if the archive module was enabled though... // @@@ We could have a check here to see if the archive module was enabled though...
if (ARCHIVE_MIME_TYPES.contains(fileType)) { if (ARCHIVE_MIME_TYPES.contains(mimeType)) {
try { try {
if (context.fileIngestIsCancelled()) { if (context.fileIngestIsCancelled()) {
return; return;
@ -741,11 +811,11 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
if (context.fileIngestIsCancelled()) { if (context.fileIngestIsCancelled()) {
return; return;
} }
if (fileType.equals(MimeTypes.OCTET_STREAM)) { if (MimeTypes.OCTET_STREAM.equals(mimeType)) {
extractStringsAndIndex(aFile); extractStringsAndIndex(aFile);
return; return;
} }
if (!extractTextAndIndex(aFile, extractedMetadata)) { if (!extractTextAndIndex(extractor, aFile, extractedMetadata)) {
// Text extractor not found for file. Extract string only. // Text extractor not found for file. Extract string only.
putIngestStatus(jobId, aFile.getId(), IngestStatus.SKIPPED_ERROR_TEXTEXTRACT); putIngestStatus(jobId, aFile.getId(), IngestStatus.SKIPPED_ERROR_TEXTEXTRACT);
} else { } else {
@ -783,8 +853,8 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
} }
/** /**
* Adds the text file to the index given an encoding. * Adds the text file to the index given an encoding. Returns true if
* Returns true if indexing was successful and false otherwise. * indexing was successful and false otherwise.
* *
* @param aFile Text file to analyze * @param aFile Text file to analyze
*/ */

View File

@ -26,19 +26,35 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
/** /**
* Ingest job settings for the keywords search module. * Ingest job settings for the keywords search module.
*/ */
final class KeywordSearchJobSettings implements IngestModuleIngestJobSettings { public final class KeywordSearchJobSettings implements IngestModuleIngestJobSettings {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private HashSet<String> namesOfEnabledKeywordLists; private HashSet<String> namesOfEnabledKeywordLists;
private HashSet<String> namesOfDisabledKeywordLists; // Added in version 1.1 private HashSet<String> namesOfDisabledKeywordLists; // Added in version 1.1
/**
* These are nullable so that if no serialized setting, the setting can
* defer to legacy KeywordSearchSettings.
*/
private Boolean ocrEnabled;
private Boolean limitedOCREnabled;
private boolean ocrOnly;
/** /**
* Constructs ingest job settings for the keywords search module. * Constructs ingest job settings for the keywords search module.
* *
* @param namesOfEnabledKeywordLists A list of enabled keywords lists. * @param namesOfEnabledKeywordLists A list of enabled keywords lists.
*/ */
KeywordSearchJobSettings(List<String> namesOfEnabledKeywordLists) { KeywordSearchJobSettings(List<String> namesOfEnabledKeywordLists) {
this(namesOfEnabledKeywordLists, new ArrayList<String>()); this.namesOfEnabledKeywordLists = new HashSet<>(namesOfEnabledKeywordLists);
this.namesOfDisabledKeywordLists = new HashSet<>();
// explicitly set to default value
this.ocrEnabled = null;
this.limitedOCREnabled = null;
this.ocrOnly = false;
} }
/** /**
@ -46,10 +62,88 @@ final class KeywordSearchJobSettings implements IngestModuleIngestJobSettings {
* *
* @param namesOfEnabledKeywordLists A list of enabled keywords lists. * @param namesOfEnabledKeywordLists A list of enabled keywords lists.
* @param namesOfDisabledKeywordLists A list of disabled keywords lists. * @param namesOfDisabledKeywordLists A list of disabled keywords lists.
* @param ocrEnabled Whether or not OCR is enabled for
* keyword search.
* @param limitedOCREnabled If true, OCR is to be performed only
* on images larger than 100KB.
* @param ocrOnly True if keyword search ingest should
* be solely limited to OCR.
*/ */
KeywordSearchJobSettings(List<String> namesOfEnabledKeywordLists, List<String> namesOfDisabledKeywordLists) { KeywordSearchJobSettings(List<String> namesOfEnabledKeywordLists, List<String> namesOfDisabledKeywordLists, boolean ocrEnabled, boolean limitedOCREnabled, boolean ocrOnly) {
this.namesOfEnabledKeywordLists = new HashSet<>(namesOfEnabledKeywordLists); this.namesOfEnabledKeywordLists = new HashSet<>(namesOfEnabledKeywordLists);
this.namesOfDisabledKeywordLists = new HashSet<>(namesOfDisabledKeywordLists); this.namesOfDisabledKeywordLists = new HashSet<>(namesOfDisabledKeywordLists);
this.ocrEnabled = ocrEnabled;
this.limitedOCREnabled = limitedOCREnabled;
this.ocrOnly = ocrOnly;
}
/**
* Whether or not OCR is enabled for keyword search.
*
* @return Whether or not OCR is enabled for keyword search.
*/
@SuppressWarnings("deprecation")
public boolean isOCREnabled() {
if (ocrEnabled == null) {
ocrEnabled = KeywordSearchSettings.getOcrOption();
}
return ocrEnabled;
}
/**
* Sets whether or not OCR is enabled for keyword search.
*
* @param ocrEnabled Whether or not OCR is enabled for keyword search.
*/
public void setOCREnabled(boolean ocrEnabled) {
this.ocrEnabled = ocrEnabled;
}
/**
* Returns true if OCR is to be performed only on images larger than 100KB.
* May defer to KeywordSearchSettings if no setting serialized.
*
* @return If true, OCR is to be performed only on images larger than 100KB.
*/
@SuppressWarnings("deprecation")
boolean isLimitedOCREnabled() {
if (limitedOCREnabled == null) {
limitedOCREnabled = KeywordSearchSettings.getLimitedOcrOption();
}
return limitedOCREnabled;
}
/**
* Sets whether or not OCR should be performed only on images larger than
* 100KB.
*
* @param limitedOCREnabled Whether or not OCR should be performed only on
* images larger than 100KB.
*/
void setLimitedOCREnabled(boolean limitedOCREnabled) {
this.limitedOCREnabled = limitedOCREnabled;
}
/**
* Returns true if keyword search ingest should be solely limited to OCR.
*
* @return True if keyword search ingest should be solely limited to OCR.
*/
boolean isOCROnly() {
return ocrOnly;
}
/**
* Sets whether or not keyword search ingest should be solely limited to
* OCR.
*
* @param ocrOnly Whether or not keyword search ingest should be solely
* limited to OCR.
*/
void setOCROnly(boolean ocrOnly) {
this.ocrOnly = ocrOnly;
} }
/** /**

View File

@ -20,30 +20,34 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="1" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Component id="listsScrollPane" pref="0" max="32767" attributes="1"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
</Group> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Component id="languagesValLabel" min="-2" pref="274" max="-2" attributes="0"/>
<EmptySpace min="10" max="32767" attributes="0"/>
</Group>
<Component id="languagesLabel" alignment="1" max="32767" attributes="0"/> <Component id="languagesLabel" alignment="1" max="32767" attributes="0"/>
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="listsScrollPane" pref="316" max="32767" attributes="1"/>
<Component id="titleLabel" min="-2" max="-2" attributes="0"/> <Component id="titleLabel" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Component id="encodingsLabel" min="-2" max="-2" attributes="0"/> <Component id="encodingsLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/> <EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="keywordSearchEncodings" min="-2" max="-2" attributes="0"/> <Component id="keywordSearchEncodings" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Component id="languagesValLabel" min="-2" pref="274" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/> <Component id="ocrCheckBox" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="21" pref="21" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="ocrOnlyCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="limitedOcrCheckbox" min="-2" pref="288" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</Group> </Group>
@ -54,18 +58,24 @@
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="7" max="-2" attributes="0"/> <EmptySpace min="-2" pref="7" max="-2" attributes="0"/>
<Component id="titleLabel" min="-2" max="-2" attributes="0"/> <Component id="titleLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="listsScrollPane" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="listsScrollPane" pref="41" max="32767" attributes="0"/> <Component id="languagesLabel" min="-2" pref="13" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/> <EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="languagesLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="languagesValLabel" min="-2" max="-2" attributes="0"/> <Component id="languagesValLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/> <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
<Component id="encodingsLabel" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="encodingsLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="keywordSearchEncodings" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="keywordSearchEncodings" alignment="3" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Component id="ocrCheckBox" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="ocrOnlyCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Component id="limitedOcrCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -96,8 +106,15 @@
<Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.editors2.TableModelEditor"> <Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.editors2.TableModelEditor">
<Table columnCount="0" rowCount="0"/> <Table columnCount="0" rowCount="0"/>
</Property> </Property>
<Property name="showHorizontalLines" type="boolean" value="false"/> <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Property name="showVerticalLines" type="boolean" value="false"/> <Dimension value="[32767, 32767]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[20, 200]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="null"/>
</Property>
</Properties> </Properties>
<AuxValues> <AuxValues>
<AuxValue name="JavaCodeGenerator_AddingCodePost" type="java.lang.String" value="listsTable.setDefaultRenderer(String.class, new SimpleTableCellRenderer());"/> <AuxValue name="JavaCodeGenerator_AddingCodePost" type="java.lang.String" value="listsTable.setDefaultRenderer(String.class, new SimpleTableCellRenderer());"/>
@ -150,5 +167,36 @@
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="ocrCheckBox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/keywordsearch/Bundle.properties" key="KeywordSearchJobSettingsPanel.ocrCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ocrCheckBoxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="limitedOcrCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/keywordsearch/Bundle.properties" key="KeywordSearchJobSettingsPanel.limitedOcrCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="verticalTextPosition" type="int" value="1"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="limitedOcrCheckboxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="ocrOnlyCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/keywordsearch/Bundle.properties" key="KeywordSearchJobSettingsPanel.ocrOnlyCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="ocrOnlyCheckboxActionPerformed"/>
</Events>
</Component>
</SubComponents> </SubComponents>
</Form> </Form>

View File

@ -18,19 +18,17 @@
*/ */
package org.sleuthkit.autopsy.keywordsearch; package org.sleuthkit.autopsy.keywordsearch;
import java.awt.Component;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.swing.JLabel;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.ListSelectionModel; import javax.swing.ListSelectionModel;
import javax.swing.table.AbstractTableModel; import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn; import javax.swing.table.TableColumn;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT; import org.sleuthkit.autopsy.coreutils.StringExtract.StringExtractUnicodeTable.SCRIPT;
import org.sleuthkit.autopsy.guiutils.SimpleTableCellRenderer; import org.sleuthkit.autopsy.guiutils.SimpleTableCellRenderer;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
@ -42,16 +40,16 @@ import org.sleuthkit.autopsy.keywordsearch.KeywordSearchIngestModule.StringsExtr
*/ */
@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
public final class KeywordSearchJobSettingsPanel extends IngestModuleIngestJobSettingsPanel implements PropertyChangeListener { public final class KeywordSearchJobSettingsPanel extends IngestModuleIngestJobSettingsPanel implements PropertyChangeListener {
private final KeywordListsTableModel tableModel = new KeywordListsTableModel(); private final KeywordListsTableModel tableModel = new KeywordListsTableModel();
private final List<String> keywordListNames = new ArrayList<>(); private final List<String> keywordListNames = new ArrayList<>();
private final Map<String, Boolean> keywordListStates = new HashMap<>(); private final Map<String, Boolean> keywordListStates = new HashMap<>();
private final XmlKeywordSearchList keywordListsManager = XmlKeywordSearchList.getCurrent(); private final XmlKeywordSearchList keywordListsManager = XmlKeywordSearchList.getCurrent();
KeywordSearchJobSettingsPanel(KeywordSearchJobSettings initialSettings) { KeywordSearchJobSettingsPanel(KeywordSearchJobSettings initialSettings) {
initializeKeywordListSettings(initialSettings);
initComponents(); initComponents();
customizeComponents(); customizeComponents();
initializeKeywordListSettings(initialSettings);
} }
private void initializeKeywordListSettings(KeywordSearchJobSettings settings) { private void initializeKeywordListSettings(KeywordSearchJobSettings settings) {
@ -63,6 +61,23 @@ public final class KeywordSearchJobSettingsPanel extends IngestModuleIngestJobSe
keywordListNames.add(listName); keywordListNames.add(listName);
keywordListStates.put(listName, settings.keywordListIsEnabled(listName)); keywordListStates.put(listName, settings.keywordListIsEnabled(listName));
} }
ocrCheckBox.setSelected(settings.isOCREnabled());
limitedOcrCheckbox.setSelected(settings.isLimitedOCREnabled());
ocrOnlyCheckbox.setSelected(settings.isOCROnly());
handleOcrEnabled(settings.isOCREnabled());
}
/**
* Handles setting enabled state of checkbox.
* @param ocrEnabled Whether or not the ocr setting is enabled.
*/
private void handleOcrEnabled(boolean ocrEnabled) {
boolean platformSupported = PlatformUtil.isWindowsOS() && PlatformUtil.is64BitOS();
ocrCheckBox.setEnabled(platformSupported);
limitedOcrCheckbox.setEnabled(platformSupported && ocrEnabled);
ocrOnlyCheckbox.setEnabled(platformSupported && ocrEnabled);
} }
private void customizeComponents() { private void customizeComponents() {
@ -71,6 +86,10 @@ public final class KeywordSearchJobSettingsPanel extends IngestModuleIngestJobSe
displayEncodings(); displayEncodings();
keywordListsManager.addPropertyChangeListener(this); keywordListsManager.addPropertyChangeListener(this);
languagesLabel.setText("<html>" + org.openide.util.NbBundle.getMessage(KeywordSearchJobSettingsPanel.class, "KeywordSearchJobSettingsPanel.languagesLabel.text") + "</html>"); // NOI18N NON-NLS languagesLabel.setText("<html>" + org.openide.util.NbBundle.getMessage(KeywordSearchJobSettingsPanel.class, "KeywordSearchJobSettingsPanel.languagesLabel.text") + "</html>"); // NOI18N NON-NLS
// the gui builder does not explicitly set these to false.
listsTable.setShowHorizontalLines(false);
listsTable.setShowVerticalLines(false);
} }
private void customizeKeywordListsTable() { private void customizeKeywordListsTable() {
@ -174,7 +193,8 @@ public final class KeywordSearchJobSettingsPanel extends IngestModuleIngestJobSe
disabledListNames.add(listName); disabledListNames.add(listName);
} }
} }
return new KeywordSearchJobSettings(enabledListNames, disabledListNames); return new KeywordSearchJobSettings(enabledListNames, disabledListNames,
this.ocrCheckBox.isSelected(), this.limitedOcrCheckbox.isSelected(), this.ocrOnlyCheckbox.isSelected());
} }
void reset(KeywordSearchJobSettings newSettings) { void reset(KeywordSearchJobSettings newSettings) {
@ -241,6 +261,9 @@ public final class KeywordSearchJobSettingsPanel extends IngestModuleIngestJobSe
languagesValLabel = new javax.swing.JLabel(); languagesValLabel = new javax.swing.JLabel();
encodingsLabel = new javax.swing.JLabel(); encodingsLabel = new javax.swing.JLabel();
keywordSearchEncodings = new javax.swing.JLabel(); keywordSearchEncodings = new javax.swing.JLabel();
ocrCheckBox = new javax.swing.JCheckBox();
limitedOcrCheckbox = new javax.swing.JCheckBox();
ocrOnlyCheckbox = new javax.swing.JCheckBox();
setPreferredSize(new java.awt.Dimension(300, 170)); setPreferredSize(new java.awt.Dimension(300, 170));
@ -256,8 +279,9 @@ public final class KeywordSearchJobSettingsPanel extends IngestModuleIngestJobSe
} }
)); ));
listsTable.setShowHorizontalLines(false); listsTable.setMaximumSize(new java.awt.Dimension(32767, 32767));
listsTable.setShowVerticalLines(false); listsTable.setMinimumSize(new java.awt.Dimension(20, 200));
listsTable.setPreferredSize(null);
listsScrollPane.setViewportView(listsTable); listsScrollPane.setViewportView(listsTable);
listsTable.setDefaultRenderer(String.class, new SimpleTableCellRenderer()); listsTable.setDefaultRenderer(String.class, new SimpleTableCellRenderer());
@ -275,29 +299,54 @@ public final class KeywordSearchJobSettingsPanel extends IngestModuleIngestJobSe
keywordSearchEncodings.setText(org.openide.util.NbBundle.getMessage(KeywordSearchJobSettingsPanel.class, "KeywordSearchJobSettingsPanel.keywordSearchEncodings.text")); // NOI18N keywordSearchEncodings.setText(org.openide.util.NbBundle.getMessage(KeywordSearchJobSettingsPanel.class, "KeywordSearchJobSettingsPanel.keywordSearchEncodings.text")); // NOI18N
ocrCheckBox.setText(org.openide.util.NbBundle.getMessage(KeywordSearchJobSettingsPanel.class, "KeywordSearchJobSettingsPanel.ocrCheckBox.text")); // NOI18N
ocrCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
ocrCheckBoxActionPerformed(evt);
}
});
limitedOcrCheckbox.setText(org.openide.util.NbBundle.getMessage(KeywordSearchJobSettingsPanel.class, "KeywordSearchJobSettingsPanel.limitedOcrCheckbox.text")); // NOI18N
limitedOcrCheckbox.setVerticalTextPosition(javax.swing.SwingConstants.TOP);
limitedOcrCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
limitedOcrCheckboxActionPerformed(evt);
}
});
ocrOnlyCheckbox.setText(org.openide.util.NbBundle.getMessage(KeywordSearchJobSettingsPanel.class, "KeywordSearchJobSettingsPanel.ocrOnlyCheckbox.text")); // NOI18N
ocrOnlyCheckbox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
ocrOnlyCheckboxActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout); this.setLayout(layout);
layout.setHorizontalGroup( layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(listsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
.addContainerGap())
.addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(languagesValLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 274, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(languagesLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(languagesLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(listsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 316, Short.MAX_VALUE)
.addComponent(titleLabel) .addComponent(titleLabel)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addComponent(encodingsLabel) .addComponent(encodingsLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(keywordSearchEncodings))) .addComponent(keywordSearchEncodings))
.addGap(0, 0, Short.MAX_VALUE)))) .addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addComponent(languagesValLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 274, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(ocrCheckBox)
.addGroup(layout.createSequentialGroup()
.addGap(21, 21, 21)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(ocrOnlyCheckbox)
.addComponent(limitedOcrCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 288, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addContainerGap())))
); );
layout.setVerticalGroup( layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
@ -305,25 +354,48 @@ public final class KeywordSearchJobSettingsPanel extends IngestModuleIngestJobSe
.addGap(7, 7, 7) .addGap(7, 7, 7)
.addComponent(titleLabel) .addComponent(titleLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(listsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 41, Short.MAX_VALUE) .addComponent(listsScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(languagesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(languagesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 13, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(languagesValLabel) .addComponent(languagesValLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(encodingsLabel) .addComponent(encodingsLabel)
.addComponent(keywordSearchEncodings)) .addComponent(keywordSearchEncodings))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(ocrCheckBox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(ocrOnlyCheckbox)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(limitedOcrCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap()) .addContainerGap())
); );
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
private void ocrCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ocrCheckBoxActionPerformed
handleOcrEnabled(ocrCheckBox.isSelected());
firePropertyChange(KeywordSearchOptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_ocrCheckBoxActionPerformed
private void limitedOcrCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_limitedOcrCheckboxActionPerformed
firePropertyChange(KeywordSearchOptionsPanelController.PROP_CHANGED, null, null);
}//GEN-LAST:event_limitedOcrCheckboxActionPerformed
private void ocrOnlyCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_ocrOnlyCheckboxActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_ocrOnlyCheckboxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel encodingsLabel; private javax.swing.JLabel encodingsLabel;
private javax.swing.JLabel keywordSearchEncodings; private javax.swing.JLabel keywordSearchEncodings;
private javax.swing.JLabel languagesLabel; private javax.swing.JLabel languagesLabel;
private javax.swing.JLabel languagesValLabel; private javax.swing.JLabel languagesValLabel;
private javax.swing.JCheckBox limitedOcrCheckbox;
private javax.swing.JScrollPane listsScrollPane; private javax.swing.JScrollPane listsScrollPane;
private javax.swing.JTable listsTable; private javax.swing.JTable listsTable;
private javax.swing.JCheckBox ocrCheckBox;
private javax.swing.JCheckBox ocrOnlyCheckbox;
private javax.swing.JLabel titleLabel; private javax.swing.JLabel titleLabel;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
} }

View File

@ -133,20 +133,14 @@ class KeywordSearchSettings {
ModuleSettings.setConfigSetting(PROPERTIES_OPTIONS, key, val); ModuleSettings.setConfigSetting(PROPERTIES_OPTIONS, key, val);
} }
/**
* Save OCR setting to permanent storage
*
* @param enabled Is OCR enabled?
*/
static void setOcrOption(boolean enabled) {
ModuleSettings.setConfigSetting(PROPERTIES_OPTIONS, OCR_ENABLED, (enabled ? "true" : "false")); //NON-NLS
}
/** /**
* Get OCR setting from permanent storage * Get OCR setting from permanent storage
* *
* @return Is OCR enabled? * @return Is OCR enabled?
*
* @deprecated Please use KeywordSearchJobSettings instead.
*/ */
@Deprecated
static boolean getOcrOption() { static boolean getOcrOption() {
if (ModuleSettings.settingExists(PROPERTIES_OPTIONS, OCR_ENABLED)) { if (ModuleSettings.settingExists(PROPERTIES_OPTIONS, OCR_ENABLED)) {
return ModuleSettings.getConfigSetting(PROPERTIES_OPTIONS, OCR_ENABLED).equals("true"); //NON-NLS return ModuleSettings.getConfigSetting(PROPERTIES_OPTIONS, OCR_ENABLED).equals("true"); //NON-NLS
@ -155,6 +149,24 @@ class KeywordSearchSettings {
} }
} }
/**
* Gets the limited OCR flag to indicate if OCR should be limited to larger
* images and images which were extracted from documents.
*
* @return Flag indicating if limited OCR is enabled. True if OCR should be
* limited, false otherwise.
*
* @deprecated Please use KeywordSearchJobSettings instead.
*/
@Deprecated
static boolean getLimitedOcrOption() {
if (ModuleSettings.settingExists(PROPERTIES_OPTIONS, LIMITED_OCR_ENABLED)) {
return ModuleSettings.getConfigSetting(PROPERTIES_OPTIONS, LIMITED_OCR_ENABLED).equals("true"); //NON-NLS
} else {
return LIMITED_OCR_ENABLED_DEFAULT;
}
}
static void setShowSnippets(boolean showSnippets) { static void setShowSnippets(boolean showSnippets) {
ModuleSettings.setConfigSetting(PROPERTIES_OPTIONS, SHOW_SNIPPETS, (showSnippets ? "true" : "false")); //NON-NLS ModuleSettings.setConfigSetting(PROPERTIES_OPTIONS, SHOW_SNIPPETS, (showSnippets ? "true" : "false")); //NON-NLS
} }
@ -246,45 +258,10 @@ class KeywordSearchSettings {
logger.log(Level.INFO, "No configuration for UTF16 found, generating defaults..."); //NON-NLS logger.log(Level.INFO, "No configuration for UTF16 found, generating defaults..."); //NON-NLS
KeywordSearchSettings.setStringExtractOption(StringsExtractOptions.EXTRACT_UTF16.toString(), Boolean.TRUE.toString()); KeywordSearchSettings.setStringExtractOption(StringsExtractOptions.EXTRACT_UTF16.toString(), Boolean.TRUE.toString());
} }
//setting OCR default (disabled by default)
if (!ModuleSettings.settingExists(KeywordSearchSettings.PROPERTIES_OPTIONS, OCR_ENABLED)) {
logger.log(Level.INFO, "No configuration for OCR found, generating defaults..."); //NON-NLS
KeywordSearchSettings.setOcrOption(OCR_ENABLED_DEFAULT);
}
//setting OCR default (disabled by default)
if (!ModuleSettings.settingExists(KeywordSearchSettings.PROPERTIES_OPTIONS, LIMITED_OCR_ENABLED)) {
logger.log(Level.INFO, "No configuration for OCR found, generating defaults..."); //NON-NLS
KeywordSearchSettings.setLimitedOcrOption(LIMITED_OCR_ENABLED_DEFAULT);
}
//setting default Latin-1 Script //setting default Latin-1 Script
if (!ModuleSettings.settingExists(KeywordSearchSettings.PROPERTIES_SCRIPTS, SCRIPT.LATIN_1.name())) { if (!ModuleSettings.settingExists(KeywordSearchSettings.PROPERTIES_SCRIPTS, SCRIPT.LATIN_1.name())) {
logger.log(Level.INFO, "No configuration for Scripts found, generating defaults..."); //NON-NLS logger.log(Level.INFO, "No configuration for Scripts found, generating defaults..."); //NON-NLS
ModuleSettings.setConfigSetting(KeywordSearchSettings.PROPERTIES_SCRIPTS, SCRIPT.LATIN_1.name(), Boolean.toString(true)); ModuleSettings.setConfigSetting(KeywordSearchSettings.PROPERTIES_SCRIPTS, SCRIPT.LATIN_1.name(), Boolean.toString(true));
} }
} }
/**
* Enables the limiting OCR to be run on larger images and images which were
* extracted from documents.
*
* @param enabled Flag indicating if OCR is enabled.
*/
static void setLimitedOcrOption(boolean enabled) {
ModuleSettings.setConfigSetting(PROPERTIES_OPTIONS, LIMITED_OCR_ENABLED, (enabled ? "true" : "false")); //NON-NLS
}
/**
* Gets the limited OCR flag to indicate if OCR should be limited to larger
* images and images which were extracted from documents.
*
* @return Flag indicating if limited OCR is enabled. True if OCR should be
* limited, false otherwise..
*/
static boolean getLimitedOcrOption() {
if (ModuleSettings.settingExists(PROPERTIES_OPTIONS, LIMITED_OCR_ENABLED)) {
return ModuleSettings.getConfigSetting(PROPERTIES_OPTIONS, LIMITED_OCR_ENABLED).equals("true"); //NON-NLS
} else {
return LIMITED_OCR_ENABLED_DEFAULT;
}
}
} }

View File

@ -466,18 +466,4 @@ public class SolrSearchService implements KeywordSearchService, AutopsyService {
throw new TskCoreException(ex.getCause().getMessage(), ex); throw new TskCoreException(ex.getCause().getMessage(), ex);
} }
} }
/**
* A flag to enable or disable OCR on all future text indexing. Also sets the
* the "Limited OCR" functionality accordingly.
*
* @param state Boolean flag to enable/disable OCR. Set to True to enable
* OCR, or False to disable it.
*/
@Override
public void changeOcrState(boolean state) {
KeywordSearchSettings.setOcrOption(state);
KeywordSearchSettings.setLimitedOcrOption(state);
}
} }

View File

@ -5,12 +5,18 @@ Data Source Management:
- The main tree viewer can be configured to group by person and host. - The main tree viewer can be configured to group by person and host.
OS Accounts: OS Accounts:
- Operating System (OS) accounts and realms are their own data types and not generic artifacts. - Operating System (OS) accounts and realms are their own data types and no longer generic artifacts.
- OS Accounts are created for Windows accounts found in the registry. Domain-scoped realms are not fully detected yet. - OS Accounts are created for Windows accounts found in the registry. Domain-scoped realms are not fully detected yet.
- NTFS files are associated with OS Accounts by SID. - NTFS files are associated with OS Accounts by SID.
- The Recent Activity module associates artifacts with OS Accounts based on SID or path of database. Other modules still need to be updated. - The Recent Activity module associates artifacts with OS Accounts based on SID or path of database. Other modules still need to be updated.
- OS accounts appear in a dedicated sub-tree of the main tree view and their properties can be viewed in the results view. - OS accounts appear in a dedicated sub-tree of the main tree view and their properties can be viewed in the results view.
- A new content viewer in the lower right area of the main window was built to display OS account data for the item selected in the result view. - A new content viewer in the lower right area of the main window was built to display OS account data for the item selected in the results view.
Analysis Result and Data Artifacts
- All modules make either Analysis Results or Data Artifacts instead of “Blackboard Artifacts.”
- New “Analysis Result” content viewer shows the results for a given file and its score.
- The tabular results viewer shows an icon for the aggregate score of a file.
- The tree organizes results into "Analysis Results" and "Data Artifacts" instead of simply “Results.”
Discovery UI: Discovery UI:
- Domain categorization and account types are displayed in Domain Discovery results. - Domain categorization and account types are displayed in Domain Discovery results.
@ -22,17 +28,40 @@ Ingest Modules:
- Parsing of iLEAPP and aLEAPP output was expanded to create communication relationships which can be displayed in the Communications UI. - Parsing of iLEAPP and aLEAPP output was expanded to create communication relationships which can be displayed in the Communications UI.
- EML email parsing handles EML messages that are attachments (and have their own attachments). - EML email parsing handles EML messages that are attachments (and have their own attachments).
- Domain categorization within Recent Activity can be customized by user-defined rules that can be imported and exported. - Domain categorization within Recent Activity can be customized by user-defined rules that can be imported and exported.
- Account IDs and Installed Applications are added to the Central Repository.
- Keyword search can be configured to only do OCR and skip non-OCR files.
Miscellaneous: Miscellaneous:
- A “Reset Windows” feature was created to help redock windows. - A “Reset Windows” feature was created to help redock windows.
- A case-insensitive wordlist of all words in the keyword search index can be exported as a text document. - A case-insensitive wordlist of all words in the keyword search index can be exported as a text document.
- Information from the Data Source Summary panels can be exported as an Excel spreadsheet. - Information from the Data Source Summary panels can be exported as an Excel spreadsheet.
- More artifacts are added to the timeline and artifacts with multiple time-based attributes are mapped to multiple timeline events. - More artifacts are added to the timeline and artifacts with multiple time-based attributes are mapped to multiple timeline events.
- The Auto Ingest Dashboard is resizable.
- Added option to only perform optical character recognition on certain file types. - Added option to only perform optical character recognition on certain file types.
- Heap dumps can be saved to a custom location. - Heap dumps can be saved to a custom location.
- More detailed error messages about encrypted disks when they are added.
- Added file size filter to Ingest Filters.
Performance:
- Keyword search does not make an explicit commit for each report if ingest is running.
- Language ID is performed on a small subset of a file instead of the entire file.
- Recent Activity is more efficient because of TSK changes to file searching (using extension).
- Embedded file extractor module has been made faster by doing file typing in memory and adding extracted files in batches.
- Moved Content Viewers setNode() and isSupported()/isPreferred() code to background threads.
- Moved Data Source Summary Panel population code to background threads.
- Moved Node/Tree queries to background threads.
Bug Fixes:
- Fixed embedded file extractor file name escaping bug.
- Detect VHD files by signature and not extension.
- Fixed iLEAPP path error.
- Content viewers UIs are more consistent.
- Assorted bug fixes are included. - Assorted bug fixes are included.
Auto Ingest:
- The Auto Ingest Dashboard is resizable.
- Get thread dumps from AID
- Added beta pause feature that pauses auto ingest for a set amount of time at a scheduled date and time.
---------------- VERSION 4.18.0 -------------- ---------------- VERSION 4.18.0 --------------
Keyword Search: Keyword Search:
- A major upgrade from Solr 4 to Solr 8.6.3. Single user cases continue to use the embedded server. - A major upgrade from Solr 4 to Solr 8.6.3. Single user cases continue to use the embedded server.

View File

@ -1,6 +1,6 @@
Manifest-Version: 1.0 Manifest-Version: 1.0
OpenIDE-Module: org.sleuthkit.autopsy.recentactivity/6 OpenIDE-Module: org.sleuthkit.autopsy.recentactivity/6
OpenIDE-Module-Implementation-Version: 18 OpenIDE-Module-Implementation-Version: 19
OpenIDE-Module-Layer: org/sleuthkit/autopsy/recentactivity/layer.xml OpenIDE-Module-Layer: org/sleuthkit/autopsy/recentactivity/layer.xml
OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/recentactivity/Bundle.properties OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/recentactivity/Bundle.properties
OpenIDE-Module-Requires: OpenIDE-Module-Requires:

View File

@ -60,7 +60,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>10</release-version> <release-version>10</release-version>
<specification-version>10.23</specification-version> <specification-version>10.24</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -1995,7 +1995,7 @@ class ExtractRegistry extends Extract {
} else { } else {
osAccount = optional.get(); osAccount = optional.get();
if (userName != null && !userName.isEmpty()) { if (userName != null && !userName.isEmpty()) {
OsAccountUpdateResult updateResult= accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, userName, null, host); OsAccountUpdateResult updateResult= accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, userName, domainName.isEmpty() ? null : domainName, host);
osAccount = updateResult.getUpdatedAccount().orElse(osAccount); osAccount = updateResult.getUpdatedAccount().orElse(osAccount);
} }
} }
@ -2187,7 +2187,7 @@ class ExtractRegistry extends Extract {
accountMgr.addExtendedOsAccountAttributes(osAccount, attributes); accountMgr.addExtendedOsAccountAttributes(osAccount, attributes);
// update the loginname // update the loginname
accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, loginName, null, host); accountMgr.updateCoreWindowsOsAccountAttributes(osAccount, null, loginName, domainName.isEmpty() ? null : domainName, host);
// update other standard attributes - fullname, creationdate // update other standard attributes - fullname, creationdate
accountMgr.updateStandardOsAccountAttributes(osAccount, fullName, null, null, creationTime); accountMgr.updateStandardOsAccountAttributes(osAccount, fullName, null, null, creationTime);

View File

@ -1,3 +1,3 @@
<project name="TSK_VERSION"> <project name="TSK_VERSION">
<property name="TSK_VERSION" value="4.10.2"/> <property name="TSK_VERSION" value="4.11.0"/>
</project> </project>

View File

@ -47,7 +47,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>10</release-version> <release-version>10</release-version>
<specification-version>10.23</specification-version> <specification-version>10.24</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy User Documentation"
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 4.18.0 PROJECT_NUMBER = 4.19.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
@ -1025,7 +1025,7 @@ GENERATE_HTML = YES
# The default directory is: html. # The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = 4.18.0 HTML_OUTPUT = 4.19.0
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp). # generated HTML page (for example: .htm, .php, .asp).

View File

@ -34,7 +34,15 @@ With the admin file in place, the user can right-click on jobs in each of the ta
\image html AutoIngest/admin_jobs_panel.png \image html AutoIngest/admin_jobs_panel.png
In the Running Jobs tables, the ingest progress can be viewed and the current job can be cancelled. Note that cancellation can take some time. You can also selectively enable \ref keyword_search_ocr_config "optical character recognition (OCR)" on a case-by-case basis. This will override the normal Keyword Search settings for every job in the case. Jobs in progress will not be affected. To enable OCR for a case, right-click on a job from that case in the Pending Jobs table and select "Enable OCR For This Case".
\image html admin_jobs_ocr1.png
Once enabled, a green checkmark will appear in the OCR column next to every pending job for that case.
\image html admin_jobs_ocr2.png
In the Running Jobs tables, the ingest progress can be viewed and the current job can be cancelled. Note that cancellation can take some time. You can also generate a thread dump if you suspect ingest may be stuck.
\image html AutoIngest/admin_jobs_cancel.png \image html AutoIngest/admin_jobs_cancel.png
@ -42,9 +50,11 @@ In the Completed Jobs table, the user can reprocess a job (generally useful when
\image html AutoIngest/admin_jobs_completed.png \image html AutoIngest/admin_jobs_completed.png
\section auto_ingest_admin_nodes_panel Auto Ingest Nodes Panel \section auto_ingest_admin_nodes_panel Auto Ingest Nodes Panel
The Nodes panel displays the status of every online auto ingest node. Additionally, an admin can pause or resume a node, or shut down a node entirely (i.e., exit the Autopsy app). The Nodes panel displays the status of every online auto ingest node. Additionally, an admin can pause or resume a node, generate a thread dump, or shut down a node entirely (i.e., exit the Autopsy app).
\image html AutoIngest/admin_nodes_panel.png \image html AutoIngest/admin_nodes_panel.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -207,7 +207,7 @@ Solr creates two types of data that need to be backed up:
<ol><li>In a default installation that data is stored in \c "C:\solr-8.6.3\server\solr zoo_data" (assuming that the Solr package ZIP was extracted into \c "C:\solr-8.6.3" directory).</ol> <ol><li>In a default installation that data is stored in \c "C:\solr-8.6.3\server\solr zoo_data" (assuming that the Solr package ZIP was extracted into \c "C:\solr-8.6.3" directory).</ol>
</ul> </ul>
\section Troubleshooting \section troubleshooting Troubleshooting / Performance Tuning
\subsection install_solr_delayed_start Delayed Start Problems With Large Number Of Solr Collections \subsection install_solr_delayed_start Delayed Start Problems With Large Number Of Solr Collections
@ -287,4 +287,36 @@ Some notes:
</ul> </ul>
\subsection solr_commit_tuning Tuning Solr Server Commit Operations
When Autopsy is running in a multi-user cluster environment with multiple auto ingest nodes, it may be beneficial to tune the configuration of Solr "commit" operations.
Solr has two types of "commits" hard commits and soft commits. These are explained in detail the following link: https://lucidworks.com/post/understanding-transaction-logs-softcommit-and-commit-in-sorlcloud/
In short:
<ul>
<li>Hard commits flush newly indexed documents from RAM to Solr index on disk.
<li>Depending on configuration, hard commits may or may not make the newly indexed documents "visible" to search.
<li>Soft commits do not flush newly indexed documents to disk but they make the newly indexed documents "visible" to search.
</ul>
By default (when using AutopsyConfig) the Solr servers are performing a "hard" commit every 5 minutes and are also making the newly indexed documents "visible" to search. These operations can be costly when performed on a large index which is located on a shared network drive. In this stuation it can be very beneficial to modify Solr configuration (located in \c "SOLR_INSTALLATION_DIECTORY\server\solr\configsets\AutopsyConfig\conf\solrconfig.xml") with the following changes:
<ol>
<li>Modify "hard commits" to still flush the newly created documents every 5 minutes but not make them "visible". This is accomplished by setting “openSearcher" to "false" in the "autoCommit" section of Solr configuration file.
<li>Enable "soft commits" to be performed every 30 minutes thus making the newly indexed documents "visible" to search every 30 minutes. This is accomplished by enabling the "autoSoftCommit" section of Solr configuration file. The downside is that it may take up to 30 minutes to be able to search the latest document. Keep in mind that this only affects the scenario where an examiner is searching a case while the ingest is still ongoing. Autopsy automatically performs a commit after the ingest is complete so all the documents are immediately visible at that time.
</ol>
The following image shows the Solr configuration changes discussed above:
\image html solr_config_autocommit.jpg
Until a hard commit is performed, by default Solr also maintains a transaction log which contains the raw text of every newly indexed document since last hard commit. When the Solr index is located on a network share, this again can be a very costly operation. Transaction logs can be disabled by commenting out the "updateLog" section of Solr configuration file:
\image html solr_comment_out_updateLog.jpg
Keep in mind that this has an unfortunate side effect of creating CommitTracker errors in Solr logs and Solr admin console. These errors can be ignored if transaction log has been intentionally disabled.
\image html solr_transaction_log_errors.jpg
*/ */

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy"
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 4.18.0 PROJECT_NUMBER = 4.19.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears a the top of each page and should give viewer a # for a project that appears a the top of each page and should give viewer a
@ -1066,7 +1066,7 @@ GENERATE_HTML = YES
# The default directory is: html. # The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES. # This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = api-docs/4.18.0/ HTML_OUTPUT = api-docs/4.19.0/
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp). # generated HTML page (for example: .htm, .php, .asp).

View File

@ -4,7 +4,7 @@ app.title=Autopsy
### lowercase version of above ### lowercase version of above
app.name=${branding.token} app.name=${branding.token}
### if left unset, version will default to today's date ### if left unset, version will default to today's date
app.version=4.18.0 app.version=4.19.0
### build.type must be one of: DEVELOPMENT, RELEASE ### build.type must be one of: DEVELOPMENT, RELEASE
#build.type=RELEASE #build.type=RELEASE
build.type=DEVELOPMENT build.type=DEVELOPMENT

View File

@ -54,7 +54,7 @@
<compile-dependency/> <compile-dependency/>
<run-dependency> <run-dependency>
<release-version>10</release-version> <release-version>10</release-version>
<specification-version>10.23</specification-version> <specification-version>10.24</specification-version>
</run-dependency> </run-dependency>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -5,7 +5,7 @@
# NOTE: update_sleuthkit_version.pl updates this value and relies # NOTE: update_sleuthkit_version.pl updates this value and relies
# on it keeping the same name and whitespace. Don't change it. # on it keeping the same name and whitespace. Don't change it.
TSK_VERSION=4.10.2 TSK_VERSION=4.11.0
# In the beginning... # In the beginning...