Merge remote-tracking branch 'upstream/develop' into 5718-invert-control-of-case-uco

This commit is contained in:
U-BASIS\dsmyda 2020-01-13 17:44:02 -05:00
commit 66afb97fad
161 changed files with 1379 additions and 464 deletions

View File

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

View File

@ -79,7 +79,7 @@ file.reference.javax.ws.rs-api-2.0.1.jar=release/modules/ext/javax.ws.rs-api-2.0
file.reference.cxf-core-3.0.16.jar=release/modules/ext/cxf-core-3.0.16.jar
file.reference.cxf-rt-frontend-jaxrs-3.0.16.jar=release/modules/ext/cxf-rt-frontend-jaxrs-3.0.16.jar
file.reference.cxf-rt-transports-http-3.0.16.jar=release/modules/ext/cxf-rt-transports-http-3.0.16.jar
file.reference.sleuthkit-postgresql-4.7.0.jar=release/modules/ext/sleuthkit-postgresql-4.7.0.jar
file.reference.sleuthkit-postgresql-4.8.0.jar=release/modules/ext/sleuthkit-postgresql-4.8.0.jar
file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar
file.reference.curator-framework-2.8.0.jar=release/modules/ext/curator-framework-2.8.0.jar
file.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0.jar
@ -127,5 +127,5 @@ nbm.homepage=http://www.sleuthkit.org/
nbm.module.author=Brian Carrier
nbm.needs.restart=true
source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar
spec.version.base=10.17
spec.version.base=10.18

View File

@ -345,6 +345,7 @@
<package>org.sleuthkit.autopsy.textextractors.configs</package>
<package>org.sleuthkit.autopsy.texttranslation</package>
<package>org.sleuthkit.datamodel</package>
<package>org.sleuthkit.datamodel.blackboardutils</package>
</public-packages>
<class-path-extension>
<runtime-relative-path>ext/commons-lang3-3.8.1.jar</runtime-relative-path>
@ -527,8 +528,8 @@
<binary-origin>release/modules/ext/google-http-client-1.29.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sleuthkit-postgresql-4.7.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.7.0.jar</binary-origin>
<runtime-relative-path>ext/sleuthkit-postgresql-4.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sleuthkit-postgresql-4.8.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/bcpkix-jdk15on-1.60.jar</runtime-relative-path>

View File

@ -354,7 +354,7 @@ UnpackagePortableCaseProgressDialog.title.text=Unpackage Portable Case Progress
UnpackageWorker.doInBackground.canceled=Unpackaging canceled by user
UnpackageWorker.doInBackground.errorCompressingCase=Error unpackaging case
UnpackageWorker.doInBackground.errorFinding7zip=Could not locate 7-Zip executable
UnpackageWorker.doInBackground.previousSeenCase=Case with name {0} has been previously opened do you want to open it again?
UnpackageWorker.doInBackground.previouslySeenCase=Case has been previously opened. Open it again?
UpdateRecentCases.menuItem.clearRecentCases.text=Clear Recent Cases
UpdateRecentCases.menuItem.empty=-Empty-
AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel

View File

@ -761,7 +761,7 @@ public class Case {
@Messages({
"Case.progressIndicatorTitle.deletingDataSource=Removing Data Source"
})
public static void deleteDataSourceFromCurrentCase(Long dataSourceObjectID) throws CaseActionException {
static void deleteDataSourceFromCurrentCase(Long dataSourceObjectID) throws CaseActionException {
synchronized (caseActionSerializationLock) {
if (null == currentCase) {
return;

View File

@ -150,14 +150,14 @@ class UnpackagePortableCaseProgressDialog extends javax.swing.JDialog implements
"UnpackageWorker.doInBackground.errorFinding7zip=Could not locate 7-Zip executable",
"UnpackageWorker.doInBackground.errorCompressingCase=Error unpackaging case",
"UnpackageWorker.doInBackground.canceled=Unpackaging canceled by user",
"UnpackageWorker.doInBackground.previousSeenCase=Case with name {0} has been previously opened do you want to open it again?"})
"UnpackageWorker.doInBackground.previouslySeenCase=Case has been previously opened. Open it again?",})
@Override
protected Void doInBackground() throws Exception {
// Check to see if this case has been already opened before
String caseUnpackedBefore = getCaseIfUnpackedBefore(packagedCase);
if ((!caseUnpackedBefore.isEmpty())
&& (MessageNotifyUtil.Message.confirm(Bundle.UnpackageWorker_doInBackground_previousSeenCase(packagedCase)))) {
&& (MessageNotifyUtil.Message.confirm(Bundle.UnpackageWorker_doInBackground_previouslySeenCase()))) {
try {
Case.openAsCurrentCase(caseUnpackedBefore);
success.set(true);

View File

@ -18,16 +18,21 @@
*/
package org.sleuthkit.autopsy.communications.relationships;
import com.google.gson.Gson;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.ImageUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.blackboardutils.FileAttachment;
import org.sleuthkit.datamodel.blackboardutils.MessageAttachments;
/**
*
@ -121,12 +126,31 @@ class AccountSummary {
}
}
try {
// count the attachments from the TSK_ATTACHMENTS attribute.
BlackboardAttribute attachmentsAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS));
if (attachmentsAttr != null) {
String jsonVal = attachmentsAttr.getValueString();
MessageAttachments msgAttachments = new Gson().fromJson(jsonVal, MessageAttachments.class);
Collection<FileAttachment> fileAttachments = msgAttachments.getFileAttachments();
for (FileAttachment fileAttachment : fileAttachments) {
attachmentCnt++;
long attachedFileObjId = fileAttachment.getObjectId();
if (attachedFileObjId >= 0) {
AbstractFile attachedFile = artifact.getSleuthkitCase().getAbstractFileById(attachedFileObjId);
if (ImageUtils.thumbnailSupported(attachedFile)) {
mediaCnt++;
}
}
}
} else { // backward compatibility - email message attachments are derived files, children of the message.
attachmentCnt += artifact.getChildrenCount();
for (Content childContent : artifact.getChildren()) {
if (ImageUtils.thumbnailSupported(childContent)) {
mediaCnt++;
}
}
}
} catch (TskCoreException ex) {
logger.log(Level.WARNING, String.format("Exception thrown "
+ "from getChildrenCount artifactID: %d",

View File

@ -36,7 +36,6 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.TSK_BLACKBOARD_ATTRIBU
import org.sleuthkit.datamodel.TimeUtilities;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.communications.Utils;
import org.sleuthkit.autopsy.coreutils.PhoneNumUtil;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;

View File

@ -16,12 +16,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.coreutils;
package org.sleuthkit.autopsy.communications.relationships;
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
*

View File

@ -29,7 +29,6 @@ import org.openide.util.Lookup;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.datamodel.Account;
import org.sleuthkit.autopsy.coreutils.PhoneNumUtil;
/**
* Account Summary View Panel. This panel shows a list of various counts related

View File

@ -87,13 +87,9 @@ HtmlPanel.showImagesToggleButton.text=Download Images
MediaViewImagePanel.tagsMenu.text_1=Tags Menu
MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00
MediaPlayerPanel.audioSlider.toolTipText=
MediaPlayerPanel.rewindButton.text=\u2bc7\u2bc7
MediaPlayerPanel.fastForwardButton.text=\u2bc8\u2bc8
MediaPlayerPanel.playButton.text=\u25ba
MediaPlayerPanel.rewindButton.text=
MediaPlayerPanel.fastForwardButton.text=
MediaPlayerPanel.playButton.text=
MediaPlayerPanel.infoLabel.text=No Errors
MediaPlayerPanel.VolumeIcon.text=Volume
MediaPlayerPanel.playBackSpeedLabel.text=Speed:
ContextViewer.jSourceGoToResultButton.text=Go to Result
ContextViewer.jSourceNameLabel.text=jSourceNameLabel
ContextViewer.jSourceTextLabel.text=jLabel2
ContextViewer.jSourceLabel.text=Source

View File

@ -10,17 +10,6 @@ AnnotationsContentViewer.title=Annotations
AnnotationsContentViewer.toolTip=Displays tags and comments associated with the selected content.
ApplicationContentViewer.title=Application
ApplicationContentViewer.toolTip=Displays file contents.
ContextViewer.attachmentSource=Attached to:
ContextViewer.downloadedOn=On
ContextViewer.downloadSource=Downloaded from:
ContextViewer.downloadURL=URL
ContextViewer.email=Email
ContextViewer.message=Message
ContextViewer.messageFrom=From
ContextViewer.messageOn=On
ContextViewer.messageTo=From
ContextViewer.title=Context Viewer
ContextViewer.toolTip=Displays context for selected file.
FXVideoPanel.pauseButton.infoLabel.playbackErr=Unable to play video.
FXVideoPanel.progress.bufferingCancelled=media buffering was canceled
FXVideoPanel.progress.bufferingInterrupted=media buffering was interrupted
@ -169,16 +158,12 @@ HtmlPanel.showImagesToggleButton.text=Download Images
MediaViewImagePanel.tagsMenu.text_1=Tags Menu
MediaPlayerPanel.progressLabel.text=00:00:00/00:00:00
MediaPlayerPanel.audioSlider.toolTipText=
MediaPlayerPanel.rewindButton.text=\u2bc7\u2bc7
MediaPlayerPanel.fastForwardButton.text=\u2bc8\u2bc8
MediaPlayerPanel.playButton.text=\u25ba
MediaPlayerPanel.rewindButton.text=
MediaPlayerPanel.fastForwardButton.text=
MediaPlayerPanel.playButton.text=
MediaPlayerPanel.infoLabel.text=No Errors
MediaPlayerPanel.VolumeIcon.text=Volume
MediaPlayerPanel.playBackSpeedLabel.text=Speed:
ContextViewer.jSourceGoToResultButton.text=Go to Result
ContextViewer.jSourceNameLabel.text=jSourceNameLabel
ContextViewer.jSourceTextLabel.text=jLabel2
ContextViewer.jSourceLabel.text=Source
# {0} - tableName
SQLiteViewer.readTable.errorText=Error getting rows for table: {0}
# {0} - tableName

View File

@ -41,7 +41,7 @@
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="131" max="32767" attributes="0"/>
<EmptySpace min="0" pref="117" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
@ -83,7 +83,7 @@
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="buttonPanel" max="32767" attributes="0"/>
<Component id="playBackPanel" pref="0" max="32767" attributes="0"/>
<Component id="playBackPanel" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="14" max="-2" attributes="0"/>
<Component id="infoLabel" min="-2" max="-2" attributes="0"/>
@ -107,7 +107,7 @@
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_InitCodePost" type="java.lang.String" value="progressSlider.setUI(new CircularJSliderUI(progressSlider, new CircularJSliderConfiguration(new Dimension(18,18))));"/>
<AuxValue name="JavaCodeGenerator_InitCodePost" type="java.lang.String" value="progressSlider.setUI(new CircularJSliderUI(progressSlider, new Dimension(18,18)));"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="progressLabel">
@ -123,9 +123,21 @@
<SubComponents>
<Component class="javax.swing.JButton" name="playButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/contentviewers/images/Play-arrow-01.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MediaPlayerPanel.playButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[53, 29]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[53, 29]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[49, 29]"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="playButtonActionPerformed"/>
@ -138,6 +150,9 @@
</Component>
<Component class="javax.swing.JButton" name="fastForwardButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/contentviewers/images/Fast-forward-01.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MediaPlayerPanel.fastForwardButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
@ -153,6 +168,9 @@
</Component>
<Component class="javax.swing.JButton" name="rewindButton">
<Properties>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/org/sleuthkit/autopsy/contentviewers/images/Fast-rewind-01.png"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MediaPlayerPanel.rewindButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
@ -172,6 +190,15 @@
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MediaPlayerPanel.VolumeIcon.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="horizontalTextPosition" type="int" value="2"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[34, 29]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[34, 29]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[34, 19]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
@ -188,15 +215,19 @@
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MediaPlayerPanel.audioSlider.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="value" type="int" value="25"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[32767, 19]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[200, 21]"/>
<Dimension value="[200, 19]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[200, 21]"/>
<Dimension value="[200, 30]"/>
</Property>
<Property name="requestFocusEnabled" type="boolean" value="false"/>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_InitCodePost" type="java.lang.String" value="audioSlider.setUI(new CircularJSliderUI(audioSlider, new CircularJSliderConfiguration(new Dimension(15,15))));"/>
<AuxValue name="JavaCodeGenerator_InitCodePost" type="java.lang.String" value="audioSlider.setUI(new CircularJSliderUI(audioSlider, new Dimension(15,15)));"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
@ -223,7 +254,7 @@
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="playBackSpeedLabel" min="-2" max="-2" attributes="0"/>
<Component id="playBackSpeedLabel" min="-2" pref="34" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="playBackSpeedComboBox" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="13" max="-2" attributes="0"/>
@ -233,12 +264,15 @@
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="playBackSpeedComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="playBackSpeedLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="7" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Group type="102" attributes="0">
<EmptySpace min="2" pref="2" max="-2" attributes="0"/>
<Component id="playBackSpeedLabel" max="32767" attributes="0"/>
</Group>
<EmptySpace max="32767" attributes="0"/>
<Component id="playBackSpeedComboBox" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
@ -260,14 +294,15 @@
</Property>
<Property name="selectedIndex" type="int" value="3"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[53, 23]"/>
<Dimension value="[53, 29]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[53, 23]"/>
<Dimension value="[53, 29]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[53, 23]"/>
<Dimension value="[53, 29]"/>
</Property>
<Property name="requestFocusEnabled" type="boolean" value="false"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="playBackSpeedComboBoxActionPerformed"/>
@ -281,6 +316,15 @@
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="MediaPlayerPanel.playBackSpeedLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[34, 19]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[34, 19]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[34, 19]"/>
</Property>
</Properties>
</Component>
</SubComponents>

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2019 Basis Technology Corp.
* Copyright 2013-2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -29,6 +29,7 @@ import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
@ -61,6 +62,7 @@ import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskData;
import javafx.embed.swing.JFXPanel;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
@ -72,6 +74,7 @@ import org.freedesktop.gstreamer.Format;
import org.freedesktop.gstreamer.GstException;
import org.freedesktop.gstreamer.event.SeekFlags;
import org.freedesktop.gstreamer.event.SeekType;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
/**
* This is a video player that is part of the Media View layered pane. It uses
@ -109,7 +112,7 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
".wav",
".webm",
".wma",
".wmv",}; //NON-NLS
".wmv"}; //NON-NLS
private static final List<String> MIME_TYPES = Arrays.asList(
"video/3gpp",
"video/3gpp2",
@ -200,15 +203,18 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
private static final int PROGRESS_SLIDER_SIZE = 2000;
private static final int SKIP_IN_SECONDS = 30;
private final ImageIcon playIcon = new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/contentviewers/images/Play-arrow-01.png"));
private final ImageIcon pauseIcon = new ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/contentviewers/images/Pause-01.png"));
private ExtractMedia extractMediaWorker;
//Serialize setting the value of the Video progress slider.
//The slider is a shared resource between the VideoPanelUpdater
//and the TrackListener of the JSliderUI.
//and the TrackListener on the slider itself.
private final Semaphore sliderLock;
/**
* Creates new form MediaViewVideoPanel
* Creates a new MediaPlayerPanel
*/
public MediaPlayerPanel() throws GstException, UnsatisfiedLinkError {
initComponents();
@ -216,6 +222,14 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
//True for fairness. In other words,
//acquire() calls are processed in order of invocation.
sliderLock = new Semaphore(1, true);
/**
* See JIRA-5888 for details. Initializing gstreamer here is more stable
* on Windows.
*/
if (PlatformUtil.isWindowsOS()) {
Gst.init();
}
}
private void customizeComponents() {
@ -247,7 +261,37 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
}
}
});
//Manage the audio level when the user is adjusting the volumn slider
//Manage the video while the user is performing actions on the track.
progressSlider.addMouseListener(new MouseListener() {
private State previousState = State.NULL;
@Override
public void mousePressed(MouseEvent e) {
previousState = gstPlayBin.getState();
gstPlayBin.pause();
}
@Override
public void mouseReleased(MouseEvent e) {
if(previousState.equals(State.PLAYING)) {
gstPlayBin.play();
}
previousState = State.NULL;
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
});
//Manage the audio level when the user is adjusting the volume slider
audioSlider.addChangeListener((ChangeEvent event) -> {
if (audioSlider.getValueIsAdjusting()) {
double audioPercent = (audioSlider.getValue() * 2.0) / 100.0;
@ -271,11 +315,11 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
public void stateChanged(GstObject go, State oldState, State currentState, State pendingState) {
if (State.PLAYING.equals(currentState)) {
SwingUtilities.invokeLater(() -> {
playButton.setText("||");
playButton.setIcon(pauseIcon);
});
} else {
SwingUtilities.invokeLater(() -> {
playButton.setText("");
playButton.setIcon(playIcon);
});
}
}
@ -504,8 +548,10 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
// Initialize Gstreamer. It is safe to call this for every file.
// It was moved here from the constructor because having it happen
// earlier resulted in conflicts on Linux.
// earlier resulted in conflicts on Linux. See JIRA-5888.
if (!PlatformUtil.isWindowsOS()) {
Gst.init();
}
//Video is ready for playback. Create new components
gstPlayBin = new PlayBin("VideoPlayer", tempFile.toURI());
@ -574,63 +620,15 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
}
}
/**
* Represents the default configuration for the circular JSliderUI.
*/
private class CircularJSliderConfiguration {
//Thumb configurations
private final Color thumbColor;
private final Dimension thumbDimension;
//Track configurations
//Progress bar can be bisected into a seen group
//and an unseen group.
private final Color unseen;
private final Color seen;
/**
* Default configuration
*
* JSlider is light blue RGB(0,130,255). Seen track is light blue
* RGB(0,130,255). Unseen track is light grey RGB(192, 192, 192).
*
* @param thumbDimension Size of the oval thumb.
*/
public CircularJSliderConfiguration(Dimension thumbDimension) {
Color lightBlue = new Color(0, 130, 255);
seen = lightBlue;
unseen = Color.LIGHT_GRAY;
thumbColor = lightBlue;
this.thumbDimension = new Dimension(thumbDimension);
}
public Color getThumbColor() {
return thumbColor;
}
public Color getUnseenTrackColor() {
return unseen;
}
public Color getSeenTrackColor() {
return seen;
}
public Dimension getThumbDimension() {
return new Dimension(thumbDimension);
}
}
/**
* Custom view for the JSlider.
*/
private class CircularJSliderUI extends BasicSliderUI {
private final CircularJSliderConfiguration config;
private final Dimension thumbDimension;
private final Color thumbColor;
private final Color trackUnseen;
private final Color trackSeen;
/**
* Creates a custom view for the JSlider. This view draws a blue oval
@ -641,18 +639,25 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
* @param config Configuration object. Contains info about thumb
* dimensions and colors.
*/
public CircularJSliderUI(JSlider slider, CircularJSliderConfiguration config) {
public CircularJSliderUI(JSlider slider, Dimension thumbDimension) {
super(slider);
this.config = config;
this.thumbDimension = thumbDimension;
//Configure track and thumb colors.
Color lightBlue = new Color(0, 130, 255);
thumbColor = lightBlue;
trackSeen = lightBlue;
trackUnseen = Color.LIGHT_GRAY;
}
@Override
protected Dimension getThumbSize() {
return config.getThumbDimension();
return new Dimension(thumbDimension);
}
/**
* Modifies the View to be an oval rather than the rectangle Controller.
* Modifies the View to be an oval rather than the underlying
* rectangle Controller.
*/
@Override
public void paintThumb(Graphics graphic) {
@ -662,8 +667,7 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
//Change the thumb view from the rectangle
//controller to an oval.
graphic.setColor(config.getThumbColor());
Dimension thumbDimension = config.getThumbDimension();
graphic.setColor(thumbColor);
graphic.fillOval(thumb.x, thumb.y, thumbDimension.width, thumbDimension.height);
//Preserve the graphics original color
@ -686,12 +690,12 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
Color original = graphic.getColor();
//Paint the seen side
graphic.setColor(config.getSeenTrackColor());
graphic.setColor(trackSeen);
graphic.drawLine(track.x, track.y + track.height / 2,
thumbX, thumbY + track.height / 2);
//Paint the unseen side
graphic.setColor(config.getUnseenTrackColor());
graphic.setColor(trackUnseen);
graphic.drawLine(thumbX, thumbY + track.height / 2,
track.x + track.width, track.y + track.height / 2);
@ -701,7 +705,26 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
@Override
protected TrackListener createTrackListener(JSlider slider) {
return new CustomTrackListener();
/**
* This track listener will force the thumb to be snapped to the mouse
* location. This makes grabbing and dragging the JSlider much easier.
* Using the default track listener, the user would have to click
* exactly on the slider thumb to drag it. Now the thumb positions
* itself under the mouse so that it can always be dragged.
*/
return new TrackListener() {
@Override
public void mousePressed(MouseEvent e) {
if (!slider.isEnabled() || !SwingUtilities.isLeftMouseButton(e)) {
return;
}
//Snap the thumb to position of the mouse
scrollDueToClickInTrack(0);
//Handle the event as normal.
super.mousePressed(e);
}
};
}
@Override
@ -715,7 +738,7 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
int value = this.valueForXPosition(mousePosition.x);
//Lock the slider down, which is a shared resource.
//The VideoPanelUpdater (dedicated thread) keeps the
//The VideoPanelUpdater keeps the
//slider in sync with the video position, so without
//proper locking our change could be overwritten.
sliderLock.acquireUninterruptibly();
@ -738,43 +761,6 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
super.update(graphic, component);
}
/**
* This track listener will force the thumb to be snapped to the mouse
* location. This makes grabbing and dragging the JSlider much easier.
* Using the default track listener, the user would have to click
* exactly on the slider thumb to drag it. Now the thumb positions
* itself under the mouse so that it can always be dragged.
*/
private class CustomTrackListener extends CircularJSliderUI.TrackListener {
@Override
public void mousePressed(MouseEvent e) {
if (!slider.isEnabled()) {
return;
}
//Snap the thumb to position of the mouse
scrollDueToClickInTrack(0);
//Pause the video for convenience
gstPlayBin.pause();
//Handle the event as normal.
super.mousePressed(e);
}
@Override
public void mouseReleased(MouseEvent e) {
if (!slider.isEnabled()) {
return;
}
super.mouseReleased(e);
//Unpause once the mouse has been released.
gstPlayBin.play();
}
}
}
/**
@ -810,7 +796,7 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
);
videoPanelLayout.setVerticalGroup(
videoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 131, Short.MAX_VALUE)
.addGap(0, 117, Short.MAX_VALUE)
);
progressSlider.setValue(0);
@ -818,13 +804,17 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
progressSlider.setDoubleBuffered(true);
progressSlider.setMinimumSize(new java.awt.Dimension(36, 21));
progressSlider.setPreferredSize(new java.awt.Dimension(200, 21));
progressSlider.setUI(new CircularJSliderUI(progressSlider, new CircularJSliderConfiguration(new Dimension(18,18))));
progressSlider.setUI(new CircularJSliderUI(progressSlider, new Dimension(18,18)));
org.openide.awt.Mnemonics.setLocalizedText(progressLabel, org.openide.util.NbBundle.getMessage(MediaPlayerPanel.class, "MediaPlayerPanel.progressLabel.text")); // NOI18N
buttonPanel.setLayout(new java.awt.GridBagLayout());
playButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/contentviewers/images/Play-arrow-01.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(playButton, org.openide.util.NbBundle.getMessage(MediaPlayerPanel.class, "MediaPlayerPanel.playButton.text")); // NOI18N
playButton.setMaximumSize(new java.awt.Dimension(53, 29));
playButton.setMinimumSize(new java.awt.Dimension(53, 29));
playButton.setPreferredSize(new java.awt.Dimension(49, 29));
playButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
playButtonActionPerformed(evt);
@ -838,6 +828,7 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
gridBagConstraints.insets = new java.awt.Insets(5, 6, 0, 0);
buttonPanel.add(playButton, gridBagConstraints);
fastForwardButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/contentviewers/images/Fast-forward-01.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(fastForwardButton, org.openide.util.NbBundle.getMessage(MediaPlayerPanel.class, "MediaPlayerPanel.fastForwardButton.text")); // NOI18N
fastForwardButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -851,6 +842,7 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
gridBagConstraints.insets = new java.awt.Insets(5, 6, 0, 0);
buttonPanel.add(fastForwardButton, gridBagConstraints);
rewindButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/contentviewers/images/Fast-rewind-01.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(rewindButton, org.openide.util.NbBundle.getMessage(MediaPlayerPanel.class, "MediaPlayerPanel.rewindButton.text")); // NOI18N
rewindButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -866,6 +858,9 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
org.openide.awt.Mnemonics.setLocalizedText(VolumeIcon, org.openide.util.NbBundle.getMessage(MediaPlayerPanel.class, "MediaPlayerPanel.VolumeIcon.text")); // NOI18N
VolumeIcon.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
VolumeIcon.setMaximumSize(new java.awt.Dimension(34, 29));
VolumeIcon.setMinimumSize(new java.awt.Dimension(34, 29));
VolumeIcon.setPreferredSize(new java.awt.Dimension(34, 19));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 3;
gridBagConstraints.gridy = 0;
@ -880,9 +875,11 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
audioSlider.setMinorTickSpacing(5);
audioSlider.setToolTipText(org.openide.util.NbBundle.getMessage(MediaPlayerPanel.class, "MediaPlayerPanel.audioSlider.toolTipText")); // NOI18N
audioSlider.setValue(25);
audioSlider.setMinimumSize(new java.awt.Dimension(200, 21));
audioSlider.setPreferredSize(new java.awt.Dimension(200, 21));
audioSlider.setUI(new CircularJSliderUI(audioSlider, new CircularJSliderConfiguration(new Dimension(15,15))));
audioSlider.setMaximumSize(new java.awt.Dimension(32767, 19));
audioSlider.setMinimumSize(new java.awt.Dimension(200, 19));
audioSlider.setPreferredSize(new java.awt.Dimension(200, 30));
audioSlider.setRequestFocusEnabled(false);
audioSlider.setUI(new CircularJSliderUI(audioSlider, new Dimension(15,15)));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 4;
gridBagConstraints.gridy = 0;
@ -898,9 +895,10 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
playBackSpeedComboBox.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "0.25x", "0.50x", "0.75x", "1x", "1.25x", "1.50x", "1.75x", "2x" }));
playBackSpeedComboBox.setSelectedIndex(3);
playBackSpeedComboBox.setMaximumSize(new java.awt.Dimension(53, 23));
playBackSpeedComboBox.setMinimumSize(new java.awt.Dimension(53, 23));
playBackSpeedComboBox.setPreferredSize(new java.awt.Dimension(53, 23));
playBackSpeedComboBox.setMaximumSize(new java.awt.Dimension(53, 29));
playBackSpeedComboBox.setMinimumSize(new java.awt.Dimension(53, 29));
playBackSpeedComboBox.setPreferredSize(new java.awt.Dimension(53, 29));
playBackSpeedComboBox.setRequestFocusEnabled(false);
playBackSpeedComboBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
playBackSpeedComboBoxActionPerformed(evt);
@ -908,13 +906,16 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
});
org.openide.awt.Mnemonics.setLocalizedText(playBackSpeedLabel, org.openide.util.NbBundle.getMessage(MediaPlayerPanel.class, "MediaPlayerPanel.playBackSpeedLabel.text")); // NOI18N
playBackSpeedLabel.setMaximumSize(new java.awt.Dimension(34, 19));
playBackSpeedLabel.setMinimumSize(new java.awt.Dimension(34, 19));
playBackSpeedLabel.setPreferredSize(new java.awt.Dimension(34, 19));
javax.swing.GroupLayout playBackPanelLayout = new javax.swing.GroupLayout(playBackPanel);
playBackPanel.setLayout(playBackPanelLayout);
playBackPanelLayout.setHorizontalGroup(
playBackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(playBackPanelLayout.createSequentialGroup()
.addComponent(playBackSpeedLabel)
.addComponent(playBackSpeedLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(playBackSpeedComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(13, 13, 13))
@ -922,11 +923,13 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
playBackPanelLayout.setVerticalGroup(
playBackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(playBackPanelLayout.createSequentialGroup()
.addGap(6, 6, 6)
.addGroup(playBackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(playBackSpeedComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(playBackSpeedLabel))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGap(7, 7, 7)
.addGroup(playBackPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addGroup(playBackPanelLayout.createSequentialGroup()
.addGap(2, 2, 2)
.addComponent(playBackSpeedLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addComponent(playBackSpeedComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(10, 10, 10))
);
javax.swing.GroupLayout controlPanelLayout = new javax.swing.GroupLayout(controlPanel);
@ -958,7 +961,7 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
.addGap(5, 5, 5)
.addGroup(controlPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(buttonPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(playBackPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
.addComponent(playBackPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGap(14, 14, 14)
.addComponent(infoLabel))
);
@ -1002,13 +1005,21 @@ public class MediaPlayerPanel extends JPanel implements MediaFileViewer.MediaVie
long currentTime = gstPlayBin.queryPosition(TimeUnit.NANOSECONDS);
//Skip 30 seconds.
long fastForwardDelta = TimeUnit.NANOSECONDS.convert(SKIP_IN_SECONDS, TimeUnit.SECONDS);
//Ignore fast forward requests if there are less than 30 seconds left.
if (currentTime + fastForwardDelta >= duration) {
//Don't allow skipping within 2 seconds of video ending. Skipping right to
//the end causes undefined behavior for some gstreamer plugins.
long twoSecondsInNano = TimeUnit.NANOSECONDS.convert(2, TimeUnit.SECONDS);
if((duration - currentTime) <= twoSecondsInNano) {
return;
}
long newTime = currentTime + fastForwardDelta;
long newTime;
if (currentTime + fastForwardDelta >= duration) {
//If there are less than 30 seconds left, only fast forward to the midpoint.
newTime = currentTime + (duration - currentTime)/2;
} else {
newTime = currentTime + fastForwardDelta;
}
double playBackRate = getPlayBackRate();
gstPlayBin.seek(playBackRate,
Format.TIME,

View File

@ -39,6 +39,8 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
@ -47,6 +49,7 @@ import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT;
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE;
@ -67,6 +70,7 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHO
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.blackboardutils.FileAttachment;
import org.sleuthkit.datamodel.blackboardutils.MessageAttachments;
@ -370,7 +374,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
return;
}
artifact = node.getLookup().lookup(BlackboardArtifact.class);
artifact = getNodeArtifact(node);
if (artifact == null) {
resetComponent();
return;
@ -465,7 +469,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
@Override
public boolean isSupported(Node node) {
BlackboardArtifact nodeArtifact = node.getLookup().lookup(BlackboardArtifact.class);
BlackboardArtifact nodeArtifact = getNodeArtifact(node);
if (nodeArtifact == null) {
return false;
@ -498,10 +502,56 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|| artifactTypeID == TSK_MESSAGE.getTypeID();
}
/**
* Returns the artifact represented by node.
*
* If the node lookup has an artifact, that artifact is returned. However,
* if the node lookup is a file, then we look for a TSK_ASSOCIATED_OBJECT
* artifact on the file, and if a message artifact is found associated with
* the file, that artifact is returned.
*
* @param node Node to check.
* @return Blackboard artifact for the node, null if there isn't any.
*/
private BlackboardArtifact getNodeArtifact(Node node) {
BlackboardArtifact nodeArtifact = node.getLookup().lookup(BlackboardArtifact.class);
if (nodeArtifact == null) {
try {
SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
AbstractFile file = node.getLookup().lookup(AbstractFile.class);
if (file != null) {
List<BlackboardArtifact> artifactsList = tskCase.getBlackboardArtifacts(TSK_ASSOCIATED_OBJECT, file.getId());
for (BlackboardArtifact fileArtifact : artifactsList) {
BlackboardAttribute associatedArtifactAttribute = fileArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
if (associatedArtifactAttribute != null) {
BlackboardArtifact associatedArtifact = fileArtifact.getSleuthkitCase().getBlackboardArtifact(associatedArtifactAttribute.getValueLong());
if (isMessageArtifact(associatedArtifact)) {
nodeArtifact = associatedArtifact;
}
}
}
}
} catch (NoCurrentCaseException | TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Failed to get file for selected node.", ex); //NON-NLS
}
}
return nodeArtifact;
}
@Override
public int isPreferred(Node node) {
// For message artifacts this is a high priority viewer,
// but for attachment files, this a lower priority vewer.
if (isSupported(node)) {
BlackboardArtifact nodeArtifact = node.getLookup().lookup(BlackboardArtifact.class);
if (nodeArtifact != null) {
return 7;
} else {
return 1;
}
}
return 0;
}

View File

@ -0,0 +1,4 @@
ContextViewer.jSourceGoToResultButton.text=Go to Result
ContextViewer.jSourceTextLabel.text=jLabel2
ContextViewer.jSourceNameLabel.text=jSourceNameLabel
ContextViewer.jSourceLabel.text=Source

View File

@ -0,0 +1,15 @@
ContextViewer.attachmentSource=Attached to:
ContextViewer.downloadedOn=On
ContextViewer.downloadSource=Downloaded from:
ContextViewer.downloadURL=URL
ContextViewer.email=Email
ContextViewer.jSourceGoToResultButton.text=Go to Result
ContextViewer.jSourceTextLabel.text=jLabel2
ContextViewer.jSourceNameLabel.text=jSourceNameLabel
ContextViewer.jSourceLabel.text=Source
ContextViewer.message=Message
ContextViewer.messageFrom=From
ContextViewer.messageOn=On
ContextViewer.messageTo=To
ContextViewer.title=Context
ContextViewer.toolTip=Displays context for selected file.

View File

@ -65,16 +65,12 @@
<Component class="javax.swing.JButton" name="jSourceGoToResultButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="ContextViewer.jSourceGoToResultButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jSourceGoToResultButton.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="jSourceGoToResultButtonActionPerformed"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="jSourceLabel">
<Properties>
@ -82,25 +78,21 @@
<Font name="Dialog" size="14" style="1"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="ContextViewer.jSourceLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jSourceLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
</Component>
<Component class="javax.swing.JLabel" name="jSourceNameLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="ContextViewer.jSourceNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jSourceNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="jSourceTextLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/Bundle.properties" key="ContextViewer.jSourceTextLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties" key="ContextViewer.jSourceTextLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.contentviewers;
package org.sleuthkit.autopsy.contentviewers.contextviewer;
import java.awt.Component;
import java.util.ArrayList;
@ -79,8 +79,8 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
javax.swing.JButton jSourceGoToResultButton = new javax.swing.JButton();
javax.swing.JLabel jSourceLabel = new javax.swing.JLabel();
jSourceGoToResultButton = new javax.swing.JButton();
jSourceLabel = new javax.swing.JLabel();
jSourceNameLabel = new javax.swing.JLabel();
jSourceTextLabel = new javax.swing.JLabel();
@ -188,6 +188,7 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
@Override
public void resetComponent() {
jSourceGoToResultButton.setVisible(false);
setSourceName("");
setSourceText("");
}
@ -244,17 +245,17 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
addSourceEntry(contextArtifact);
}
}
jSourceGoToResultButton.setVisible(true);
if (foundASource == false) {
setSourceName("Unknown");
showSourceText(false);
}
}
/**
* Adds a source context entry for the selected file based on the given context
* providing artifact.
* Adds a source context entry for the selected file based on the given
* context providing artifact.
*
* @param artifact Artifact that may provide context.
*
@ -315,15 +316,17 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
/**
* Sets the source text string.
*
* @param nameLabel String value for source text.
* @param text String value for source text.
*/
private void setSourceText(String text) {
jSourceTextLabel.setText(text);
showSourceText(true);
showSourceText(!text.isEmpty());
}
private void showSourceText(boolean isVisible) {
jSourceTextLabel.setVisible(isVisible);
private void showSourceText(boolean show) {
jSourceTextLabel.setVisible(show);
jSourceGoToResultButton.setEnabled(show);
jSourceLabel.setVisible(show);
}
/**
@ -366,8 +369,7 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
"ContextViewer.email=Email",
"ContextViewer.messageFrom=From",
"ContextViewer.messageTo=To",
"ContextViewer.messageOn=On",
})
"ContextViewer.messageOn=On",})
private String msgArtifactToAbbreviatedString(BlackboardArtifact artifact) throws TskCoreException {
StringBuilder sb = new StringBuilder(ARTIFACT_STR_MAX_LEN);
@ -394,8 +396,8 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
* @param sb String builder to append to.
* @param attribType Attribute type to look for.
* @param attributesMap Attributes map.
* @param prependStr Optional string that is prepended before the attribute
* value.
* @param prependStr Optional string that is prepended before the
* attribute value.
*/
private void appendAttributeString(StringBuilder sb, BlackboardAttribute.ATTRIBUTE_TYPE attribType,
Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributesMap, String prependStr) {
@ -436,6 +438,8 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton jSourceGoToResultButton;
private javax.swing.JLabel jSourceLabel;
private javax.swing.JLabel jSourceNameLabel;
private javax.swing.JLabel jSourceTextLabel;
// End of variables declaration//GEN-END:variables

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

View File

@ -610,7 +610,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
* display string.
*
* @param element JSON element to convert
* @param indentStr Starting indentation for the element.
* @param startIndent Starting indentation for the element.
*
* @return A multi-line display string.
*/
@ -634,7 +634,8 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
/**
* Converts the given JSON element into string and appends to the given string builder.
*
* @param entry JSON entry to parse
* @param jsonKey
* @param jsonElement
* @param startIndent Starting indentation for the element.
* @param sb String builder to append to.
*/

View File

@ -304,9 +304,6 @@ OpenReportAction.actionPerformed.ReportFileOpenPermissionDeniedMessage=Permissio
PoolNode.createSheet.name.desc=no description
PoolNode.createSheet.name.displayName=Name
PoolNode.createSheet.name.name=Name
PoolNode.createSheet.offset.desc=no description
PoolNode.createSheet.offset.displayName=Starting offset
PoolNode.createSheet.offset.name=Starting offset
PoolNode.createSheet.type.desc=no description
PoolNode.createSheet.type.displayName=Type
PoolNode.createSheet.type.name=Type

View File

@ -227,6 +227,7 @@ public class ExtractedContent implements AutopsyVisitableItem {
// maps the artifact type to its child node
private final HashMap<BlackboardArtifact.Type, TypeNode> typeNodeList = new HashMap<>();
@SuppressWarnings("deprecation")
TypeFactory() {
super();

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017-2018 Basis Technology Corp.
* Copyright 2017-2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.List;
import javax.swing.Action;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.DeleteDataSourceAction;
import org.sleuthkit.autopsy.casemodule.datasourcesummary.ViewSummaryInformationAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.directorytree.ExportCSVAction;
@ -68,6 +69,7 @@ public abstract class SpecialDirectoryNode extends AbstractAbstractFileNode<Spec
if (content.isDataSource()) {
actions.add(new ViewSummaryInformationAction(content.getId()));
actions.add(new RunIngestModulesAction(Collections.<Content>singletonList(content)));
actions.add(new DeleteDataSourceAction(content.getId()));
} else {
actions.add(new RunIngestModulesAction(content));
}

View File

@ -106,7 +106,7 @@ final class XRYMessagesFileParser implements XRYFileParser {
/**
* Indicates if the display name of the XRY key is a recognized type.
*
* @param xryKey
* @param name
* @return
*/
public static boolean contains(String name) {
@ -125,7 +125,7 @@ final class XRYMessagesFileParser implements XRYFileParser {
* IllegalArgumentException is thrown. Test all membership with
* contains() before hand.
*
* @param xryKey
* @param name
* @return
*/
public static XryKey fromDisplayName(String name) {
@ -217,7 +217,7 @@ final class XRYMessagesFileParser implements XRYFileParser {
/**
* Indicates if the display name of the XRY key is a recognized type.
*
* @param xryKey
* @param name
* @return
*/
public static boolean contains(String name) {
@ -236,7 +236,7 @@ final class XRYMessagesFileParser implements XRYFileParser {
* IllegalArgumentException is thrown. Test all membership with
* contains() before hand.
*
* @param xryKey
* @param name
* @return
*/
public static XryMetaKey fromDisplayName(String name) {

View File

@ -41,7 +41,6 @@ import org.sleuthkit.autopsy.actions.DeleteFileBlackboardArtifactTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFilePropertyType;
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.DataModelActionsFactory;
@ -259,12 +258,17 @@ public class DataResultFilterNode extends FilterNode {
@Override
protected Node[] createNodes(Node key) {
// filter out all non-message artifacts, if displaying the results from the Data Source tree
// if displaying the results from the Data Source tree
// filter out artifacts
// In older versions of Autopsy, attachments were children of email/message artifacts
// and hence email/messages with attachments are shown in the tree data source tree,
BlackboardArtifact art = key.getLookup().lookup(BlackboardArtifact.class);
if (art != null
&& filterArtifacts
if (art != null && filterArtifacts
&& ((FilterNodeUtils.showMessagesInDatasourceTree() == false)
|| (FilterNodeUtils.showMessagesInDatasourceTree()
&& art.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()
&& art.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()) {
&& art.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID()))) {
return new Node[]{};
}

View File

@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.directorytree;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import javax.swing.Action;
@ -33,17 +32,12 @@ import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.AbstractContentNode;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.ingest.runIngestModuleWizard.RunIngestModulesAction;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Directory;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.VirtualDirectory;
import org.sleuthkit.datamodel.Volume;
/**
* A node filter (decorator) that sets the actions for a node in the tree view
@ -137,14 +131,21 @@ class DirectoryTreeFilterNode extends FilterNode {
numVisibleChildren--;
}
} else if (child instanceof BlackboardArtifact) {
BlackboardArtifact bba = (BlackboardArtifact) child;
if (FilterNodeUtils.showMessagesInDatasourceTree()) {
// In older versions of Autopsy, attachments were children of email/message artifacts
// and hence email/messages with attachments are shown in the directory tree.
BlackboardArtifact bba = (BlackboardArtifact) child;
// Only message type artifacts are displayed in the tree
if ((bba.getArtifactTypeID() != ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID())
&& (bba.getArtifactTypeID() != ARTIFACT_TYPE.TSK_MESSAGE.getTypeID())) {
numVisibleChildren--;
}
}
else {
numVisibleChildren--;
}
}
}
}

View File

@ -0,0 +1,66 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.directorytree;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber;
/**
* Utility class for Directory tree.
*
*/
final class FilterNodeUtils {
private static final int ATTACHMENT_CHILDOF_MSG_MAX_DB_MAJOR_VER = 8;
private static final int ATTACHMENT_CHILDOF_MSG_MAX_DB_MINOR_VER = 4;
/**
* Empty private constructor
*/
private FilterNodeUtils() {
}
/**
* Prior to schema version 8.4, attachments were children of messages and
* hence messages with any attachment children are shown in the directory
* tree.
*
* At 8.4 and later, attachments are tracked as an attribute, and the message
* artifacts don't need to be shown in the directory tree.
*
* This method may be used to check the schema version and behave
* accordingly, in order to maintain backward compatibility.
*
* @return True if messages with attachment children should be shown in
* directory tree.
*/
static boolean showMessagesInDatasourceTree() {
boolean showMessagesInDatasourceTree = true;
if (Case.isCaseOpen()) {
CaseDbSchemaVersionNumber version = Case.getCurrentCase().getSleuthkitCase().getDBSchemaCreationVersion();
showMessagesInDatasourceTree
= ((version.getMajor() < ATTACHMENT_CHILDOF_MSG_MAX_DB_MAJOR_VER)
|| (version.getMajor() == ATTACHMENT_CHILDOF_MSG_MAX_DB_MAJOR_VER && version.getMinor() < ATTACHMENT_CHILDOF_MSG_MAX_DB_MINOR_VER));
}
return showMessagesInDatasourceTree;
}
}

View File

@ -16,7 +16,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.coreutils;
package org.sleuthkit.autopsy.exceptions;
import java.util.logging.Filter;
import java.util.logging.Handler;
@ -26,6 +26,9 @@ import java.util.logging.SimpleFormatter;
import javax.swing.JOptionPane;
import org.openide.util.lookup.ServiceProvider;
import org.netbeans.core.NbErrorManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.Version;
/**
* Replaces default NetBeans exception handler. Displays messages in a dialog.

View File

@ -44,7 +44,7 @@ FileSearchPanel.hashSetCheckbox.text=Hash Set:
FileSearchPanel.tagsCheckbox.text=Tag:
FileSearchPanel.interestingItemsCheckbox.text=Interesting Item:
FileSearchPanel.scoreCheckbox.text=Has Score:
FileSearchPanel.exifCheckbox.text=Must contain EXIF data
FileSearchPanel.exifCheckbox.text=Possibly User Created
FileSearchPanel.notableCheckbox.text=Must have been tagged as notable
FileSearchPanel.objectsCheckbox.text=Object Detected:
ResultsPanel.currentPageLabel.text=Page: -

View File

@ -150,7 +150,7 @@ FileSearchPanel.hashSetCheckbox.text=Hash Set:
FileSearchPanel.tagsCheckbox.text=Tag:
FileSearchPanel.interestingItemsCheckbox.text=Interesting Item:
FileSearchPanel.scoreCheckbox.text=Has Score:
FileSearchPanel.exifCheckbox.text=Must contain EXIF data
FileSearchPanel.exifCheckbox.text=Possibly User Created
FileSearchPanel.notableCheckbox.text=Must have been tagged as notable
FileSearchPanel.objectsCheckbox.text=Object Detected:
FileSorter.SortingMethod.datasource.displayName=Data Source

View File

@ -47,7 +47,7 @@ final class FileSearchData {
UNIQUE(0, 1, Bundle.FileSearchData_Frequency_unique_displayName()),
RARE(1, 10, Bundle.FileSearchData_Frequency_rare_displayName()),
COMMON(2, 100, Bundle.FileSearchData_Frequency_common_displayName()),
VERY_COMMON(3, 0, Bundle.FileSearchData_Frequency_common_displayName()),
VERY_COMMON(3, 0, Bundle.FileSearchData_Frequency_verycommon_displayName()),
KNOWN(4, 0, Bundle.FileSearchData_Frequency_known_displayName()),
UNKNOWN(5, 0, Bundle.FileSearchData_Frequency_unknown_displayName());

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Copyright 2019-2020 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -22,21 +22,17 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeIns
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileSize;
import org.sleuthkit.autopsy.filequery.FileSearchData.FileType;
import org.sleuthkit.autopsy.filequery.FileSearchData.Frequency;
import org.sleuthkit.autopsy.filequery.FileSearchData.Score;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.DataSource;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.stream.Collectors;
import org.openide.util.NbBundle;
import org.sleuthkit.datamodel.BlackboardArtifact;
@ -48,8 +44,6 @@ import org.sleuthkit.datamodel.TskData;
*/
class FileSearchFiltering {
private final static Logger logger = Logger.getLogger(FileSearchFiltering.class.getName());
/**
* Run the given filters to get a list of matching files.
*
@ -61,18 +55,9 @@ class FileSearchFiltering {
* @return
*/
static List<ResultFile> runQueries(List<FileFilter> filters, SleuthkitCase caseDb, EamDb centralRepoDb) throws FileSearchException {
if (caseDb == null) {
throw new FileSearchException("Case DB parameter is null"); // NON-NLS
}
// Record the selected filters
String filterStr = "";
for (FileFilter filter : filters) {
filterStr += " " + filter.getDesc() + "\n";
}
logger.log(Level.INFO, "Running filters:\n{0}", filterStr);
// Combine all the SQL queries from the filters into one query
String combinedQuery = "";
for (FileFilter filter : filters) {
@ -112,8 +97,6 @@ class FileSearchFiltering {
private static List<ResultFile> getResultList(List<FileFilter> filters, String combinedQuery, SleuthkitCase caseDb, EamDb centralRepoDb) throws TskCoreException, FileSearchException {
// Get all matching abstract files
List<ResultFile> resultList = new ArrayList<>();
logger.log(Level.INFO, "Running SQL query: {0}", combinedQuery);
List<AbstractFile> sqlResults = caseDb.findAllFilesWhere(combinedQuery);
// If there are no results, return now

View File

@ -404,15 +404,6 @@
<Connection code="new DefaultListModel&lt;ParentSearchTerm&gt;()" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="null"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 30]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 30]"/>
</Property>
<Property name="visibleRowCount" type="int" value="4"/>
</Properties>
<Events>
@ -457,12 +448,6 @@
<Connection code="new DefaultListModel&lt;String&gt;()" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 30]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 30]"/>
</Property>
<Property name="visibleRowCount" type="int" value="3"/>
</Properties>
<AuxValues>
@ -573,12 +558,6 @@
<Connection code="new DefaultListModel&lt;String&gt;()" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 30]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 30]"/>
</Property>
<Property name="visibleRowCount" type="int" value="2"/>
</Properties>
<AuxValues>
@ -631,12 +610,6 @@
<Connection code="new DefaultListModel&lt;String&gt;()" type="code"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 30]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 30]"/>
</Property>
<Property name="visibleRowCount" type="int" value="2"/>
</Properties>
<AuxValues>

View File

@ -1328,9 +1328,6 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener
parentList.setModel(new DefaultListModel<ParentSearchTerm>());
parentList.setEnabled(false);
parentList.setMaximumSize(null);
parentList.setMinimumSize(new java.awt.Dimension(0, 30));
parentList.setPreferredSize(new java.awt.Dimension(0, 30));
parentList.setVisibleRowCount(4);
parentList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
@ -1366,8 +1363,6 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener
hashSetList.setModel(new DefaultListModel<String>());
hashSetList.setEnabled(false);
hashSetList.setMinimumSize(new java.awt.Dimension(0, 30));
hashSetList.setPreferredSize(new java.awt.Dimension(0, 30));
hashSetList.setVisibleRowCount(3);
hashSetScrollPane.setViewportView(hashSetList);
@ -1454,8 +1449,6 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener
objectsList.setModel(new DefaultListModel<String>());
objectsList.setEnabled(false);
objectsList.setMinimumSize(new java.awt.Dimension(0, 30));
objectsList.setPreferredSize(new java.awt.Dimension(0, 30));
objectsList.setVisibleRowCount(2);
objectsScrollPane.setViewportView(objectsList);
@ -1487,8 +1480,6 @@ final class FileSearchPanel extends javax.swing.JPanel implements ActionListener
interestingItemsList.setModel(new DefaultListModel<String>());
interestingItemsList.setEnabled(false);
interestingItemsList.setMinimumSize(new java.awt.Dimension(0, 30));
interestingItemsList.setPreferredSize(new java.awt.Dimension(0, 30));
interestingItemsList.setVisibleRowCount(2);
interestingItemsScrollPane.setViewportView(interestingItemsList);

View File

@ -290,11 +290,11 @@
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="221" max="32767" attributes="0"/>
<EmptySpace min="0" pref="68" max="32767" attributes="0"/>
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
<Component id="instancesScrollPane" pref="221" max="32767" attributes="0"/>
<Component id="instancesScrollPane" max="32767" attributes="0"/>
</Group>
</Group>
</Group>
@ -331,9 +331,6 @@
<Property name="cellRenderer" type="javax.swing.ListCellRenderer" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new InstancesCellRenderer()" type="code"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[0, 50]"/>
</Property>
<Property name="visibleRowCount" type="int" value="2"/>
</Properties>
<AuxValues>

View File

@ -146,15 +146,23 @@ public class ResultsPanel extends javax.swing.JPanel {
*/
synchronized void populateInstancesList() {
SwingUtilities.invokeLater(() -> {
List<AbstractFile> files = getInstancesForSelected();
if (files.isEmpty()) {
//if there are no files currently remove the current items without removing listener to cause content viewer to reset
instancesListModel.removeAllElements();
} else {
//remove listener so content viewer node is not set multiple times
instancesList.removeListSelectionListener(listener);
instancesListModel.removeAllElements();
for (AbstractFile file : getInstancesForSelected()) {
for (AbstractFile file : files) {
instancesListModel.addElement(file);
}
//add listener back to allow selection of first index to cause content viewer node to be set
instancesList.addListSelectionListener(listener);
if (!instancesListModel.isEmpty()) {
instancesList.setSelectedIndex(0);
}
}
});
}
@ -488,7 +496,6 @@ public class ResultsPanel extends javax.swing.JPanel {
instancesList.setModel(instancesListModel);
instancesList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
instancesList.setCellRenderer(new InstancesCellRenderer());
instancesList.setPreferredSize(new java.awt.Dimension(0, 50));
instancesList.setVisibleRowCount(2);
instancesScrollPane.setViewportView(instancesList);
@ -502,11 +509,11 @@ public class ResultsPanel extends javax.swing.JPanel {
);
instancesPanelLayout.setVerticalGroup(
instancesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 221, Short.MAX_VALUE)
.addGap(0, 68, Short.MAX_VALUE)
.addGroup(instancesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, instancesPanelLayout.createSequentialGroup()
.addGap(0, 0, 0)
.addComponent(instancesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 221, Short.MAX_VALUE)))
.addComponent(instancesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
);
resultsSplitPane.setRightComponent(instancesPanel);

View File

@ -86,6 +86,8 @@ public final class GeolocationTopComponent extends TopComponent {
// This is the hardcoded report name from KMLReport.java
private static final String REPORT_KML = "ReportKML.kml";
private boolean mapInitalized = false;
@Messages({
"GLTopComponent_name=Geolocation",
"GLTopComponent_initilzation_error=An error occurred during waypoint initilization. Geolocation data maybe incomplete."
@ -194,10 +196,15 @@ public final class GeolocationTopComponent extends TopComponent {
@Override
public void open() {
super.open();
mapPanel.clearWaypoints();
geoFilterPanel.clearDataSourceList();
geoFilterPanel.updateDataSourceList();
// Let's make sure we only do this on the first open
if (!mapInitalized) {
try {
mapPanel.initMap();
mapInitalized = true;
} catch (GeoLocationDataException ex) {
JOptionPane.showMessageDialog(this,
Bundle.GeolocationTC_connection_failure_message(),
@ -209,6 +216,7 @@ public final class GeolocationTopComponent extends TopComponent {
logger.log(Level.SEVERE, ex.getMessage(), ex);
return; // Doen't set the waypoints.
}
}
mapPanel.setWaypoints(new ArrayList<>());
updateWaypoints();
}
@ -288,7 +296,7 @@ public final class GeolocationTopComponent extends TopComponent {
DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss", Locale.US);
Date date = new Date();
String dateNoTime = dateFormat.format(date);
String reportPath = String.format(REPORT_PATH_FMT_STR, currentCase.getReportDirectory(), currentCase.getDisplayName(), "Goggle Earth KML", dateNoTime);
String reportPath = String.format(REPORT_PATH_FMT_STR, currentCase.getReportDirectory(), currentCase.getDisplayName(), "Google Earth KML", dateNoTime);
// Create the root reports directory.
try {
FileUtil.createFolder(new File(reportPath));
@ -431,6 +439,8 @@ public final class GeolocationTopComponent extends TopComponent {
Bundle.GeoTopComponent_filter_exception_Title(),
Bundle.GeoTopComponent_filter_exception_msg(),
JOptionPane.ERROR_MESSAGE);
setWaypointLoading(false);
}
});
}
@ -444,7 +454,7 @@ public final class GeolocationTopComponent extends TopComponent {
private class WaypointCallBack implements WaypointFilterQueryCallBack {
@Override
public void process(List<Waypoint> waypoints) {
public void process(final List<Waypoint> waypoints) {
// Make sure that the waypoints are added to the map panel in
// the correct thread.
SwingUtilities.invokeLater(new Runnable() {
@ -453,13 +463,16 @@ public final class GeolocationTopComponent extends TopComponent {
// If the list is empty, tell the user and do not change
// the visible waypoints.
if (waypoints == null || waypoints.isEmpty()) {
mapPanel.clearWaypoints();
JOptionPane.showMessageDialog(GeolocationTopComponent.this,
Bundle.GeoTopComponent_no_waypoints_returned_Title(),
Bundle.GeoTopComponent_no_waypoints_returned_mgs(),
JOptionPane.INFORMATION_MESSAGE);
setWaypointLoading(false);
geoFilterPanel.setEnabled(true);
return;
}
mapPanel.clearWaypoints();
mapPanel.setWaypoints(MapWaypoint.getWaypoints(waypoints));
setWaypointLoading(false);
geoFilterPanel.setEnabled(true);

View File

@ -417,8 +417,6 @@ public class KdTree<T extends KdTree.XYZPoint> implements Iterable<T> {
}
Double nodeDistance = node.id.euclideanDistance(value);
if (nodeDistance.compareTo(lastDistance) < 0) {
if (results.size() == K && lastNode != null)
results.remove(lastNode);
results.add(node);
} else if (nodeDistance.equals(lastDistance)) {
results.add(node);

View File

@ -256,7 +256,7 @@ final class MBTilesTileFactory extends TileFactory {
/**
* An inner class which actually loads the tiles. Used by the thread queue.
* Subclasses can override this via {@link #createTileRunner(Tile)} if
* Subclasses can override this via createTileRunner(Tile) if
* necessary.
*/
private class TileRunner implements Runnable {

View File

@ -0,0 +1,115 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.geolocation;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputAdapter;
import org.jxmapviewer.JXMapViewer;
/**
* MouseInputListener for panning a JXMapViewer
*
* This class is adapted from org.jxmapviewer.input.PanMouseInputListener.
*/
final class MapPanMouseInputListener extends MouseInputAdapter {
private Point prev;
private final JXMapViewer viewer;
private Cursor priorCursor;
private boolean dragging = false;
/**
* Construct a new listener.
*
* @param viewer
*/
MapPanMouseInputListener(JXMapViewer viewer) {
this.viewer = viewer;
}
@Override
public void mousePressed(MouseEvent evt) {
if (!SwingUtilities.isLeftMouseButton(evt)) {
return;
}
if (!viewer.isPanningEnabled()) {
return;
}
// Store the current click point and current cursor
prev = evt.getPoint();
priorCursor = viewer.getCursor();
}
@Override
public void mouseDragged(MouseEvent evt) {
if (!SwingUtilities.isLeftMouseButton(evt)) {
return;
}
if (!viewer.isPanningEnabled()) {
return;
}
// If the map wasn't previously being dragged, set the cursor
if (!dragging) {
viewer.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
dragging = true;
}
// Figure out the new map center
Point current = evt.getPoint();
double x = viewer.getCenter().getX();
double y = viewer.getCenter().getY();
if (prev != null) {
x += prev.x - current.x;
y += prev.y - current.y;
}
int maxHeight = (int) (viewer.getTileFactory().getMapSize(viewer.getZoom()).getHeight() * viewer
.getTileFactory().getTileSize(viewer.getZoom()));
if (y > maxHeight) {
y = maxHeight;
}
prev = current;
viewer.setCenter(new Point2D.Double(x, y));
viewer.repaint();
}
@Override
public void mouseReleased(MouseEvent evt) {
if (!SwingUtilities.isLeftMouseButton(evt)) {
return;
}
prev = null;
// If we were dragging set the cursor back
if (dragging) {
viewer.setCursor(priorCursor);
dragging = false;
}
}
}

View File

@ -26,7 +26,6 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
@ -54,7 +53,6 @@ import org.jxmapviewer.JXMapViewer;
import org.jxmapviewer.OSMTileFactoryInfo;
import org.jxmapviewer.VirtualEarthTileFactoryInfo;
import org.jxmapviewer.input.CenterMapListener;
import org.jxmapviewer.input.PanMouseInputListener;
import org.jxmapviewer.input.ZoomMouseWheelListenerCursor;
import org.jxmapviewer.viewer.DefaultTileFactory;
import org.jxmapviewer.viewer.GeoPosition;
@ -70,6 +68,7 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.geolocation.datamodel.GeoLocationDataException;
import org.sleuthkit.datamodel.TskCoreException;
import javax.imageio.ImageIO;
import javax.swing.SwingUtilities;
import org.jxmapviewer.viewer.DefaultWaypointRenderer;
/**
@ -139,6 +138,8 @@ final public class MapPanel extends javax.swing.JPanel {
}
}
});
}
/**
@ -171,7 +172,7 @@ final public class MapPanel extends javax.swing.JPanel {
mapViewer.setTileFactory(tileFactory);
// Add Mouse interactions
MouseInputListener mia = new PanMouseInputListener(mapViewer);
MouseInputListener mia = new MapPanMouseInputListener(mapViewer);
mapViewer.addMouseListener(mia);
mapViewer.addMouseMotionListener(mia);
@ -204,13 +205,12 @@ final public class MapPanel extends javax.swing.JPanel {
Iterator<MapWaypoint> iterator = waypointTree.iterator();
while (iterator.hasNext()) {
MapWaypoint point = iterator.next();
if (point != currentlySelectedWaypoint) {
set.add(point);
}
}
// Add the currentlySelectedWaypoint to the end so that
// it will be painted last.
if (currentlySelectedWaypoint != null) {
set.remove(currentlySelectedWaypoint);
set.add(currentlySelectedWaypoint);
}
}
@ -279,7 +279,7 @@ final public class MapPanel extends javax.swing.JPanel {
/**
* Create the TileFactoryInfo for OSM zip File
*
* @param zipPath Path to zip file.
* @param path Path to zip file.
*
* @return TileFactoryInfo for zip file.
*
@ -332,6 +332,11 @@ final public class MapPanel extends javax.swing.JPanel {
*/
void clearWaypoints() {
waypointTree = null;
currentlySelectedWaypoint = null;
if (currentPopup != null) {
currentPopup.hide();
}
mapViewer.repaint();
}
/**
@ -342,7 +347,11 @@ final public class MapPanel extends javax.swing.JPanel {
*/
private void showPopupMenu(Point point) {
try {
MapWaypoint waypoint = findClosestWaypoint(point);
List<MapWaypoint> waypoints = findClosestWaypoint(point);
MapWaypoint waypoint = null;
if(waypoints.size() > 0) {
waypoint = waypoints.get(0);
}
showPopupMenu(waypoint, point);
// Change the details popup to the currently selected point only if
// it the popup is currently visible
@ -410,6 +419,7 @@ final public class MapPanel extends javax.swing.JPanel {
currentPopup = popupFactory.getPopup(this, detailPane, popupLocation.x, popupLocation.y);
currentPopup.show();
mapViewer.revalidate();
mapViewer.repaint();
}
}
@ -437,7 +447,7 @@ final public class MapPanel extends javax.swing.JPanel {
* @return A waypoint that is within 10 pixels of the given point, or null
* if none was found.
*/
private MapWaypoint findClosestWaypoint(Point mouseClickPoint) {
private List<MapWaypoint> findClosestWaypoint(Point mouseClickPoint) {
if (waypointTree == null) {
return null;
}
@ -446,7 +456,7 @@ final public class MapPanel extends javax.swing.JPanel {
GeoPosition geopos = mapViewer.getTileFactory().pixelToGeo(mouseClickPoint, mapViewer.getZoom());
// Get the 5 nearest neightbors to the point
Collection<MapWaypoint> waypoints = waypointTree.nearestNeighbourSearch(20, MapWaypoint.getDummyWaypoint(geopos));
Collection<MapWaypoint> waypoints = waypointTree.nearestNeighbourSearch(10, MapWaypoint.getDummyWaypoint(geopos));
if (waypoints == null || waypoints.isEmpty()) {
return null;
@ -456,6 +466,7 @@ final public class MapPanel extends javax.swing.JPanel {
// These maybe the points closest to lat/log was clicked but
// that doesn't mean they are close in terms of pixles.
List<MapWaypoint> closestPoints = new ArrayList<>();
while (iterator.hasNext()) {
MapWaypoint nextWaypoint = iterator.next();
@ -466,11 +477,11 @@ final public class MapPanel extends javax.swing.JPanel {
(int) point.getY() - rect.y);
if (converted_gp_pt.distance(mouseClickPoint) < 10) {
return nextWaypoint;
closestPoints.add(nextWaypoint);
}
}
return null;
return closestPoints;
}
/**
@ -519,7 +530,7 @@ final public class MapPanel extends javax.swing.JPanel {
}
/**
* Called when the resize event has completed\timed out
* Called when the resize event has completed or timed out
*/
public abstract void resizeTimedOut();
}
@ -629,8 +640,14 @@ final public class MapPanel extends javax.swing.JPanel {
}//GEN-LAST:event_mapViewerMouseMoved
private void mapViewerMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_mapViewerMouseClicked
if(!evt.isPopupTrigger() && (evt.getButton() == MouseEvent.BUTTON1)) {
currentlySelectedWaypoint = findClosestWaypoint(evt.getPoint());
if(!evt.isPopupTrigger() && SwingUtilities.isLeftMouseButton(evt)) {
List<MapWaypoint> waypoints = findClosestWaypoint(evt.getPoint());
if(waypoints.size() > 0) {
currentlySelectedWaypoint = waypoints.get(0);
}
// currentlySelectedWaypoint = findClosestWaypoint(evt.getPoint());
showDetailsPopup();
}
}//GEN-LAST:event_mapViewerMouseClicked

View File

@ -0,0 +1,79 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2019 Basis Technology Corp.
* contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.geolocation.datamodel;
import java.util.Map;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
/**
* Class wraps any artifact that is not one of the known types, but have the
* TSK_GEO_LONGITUDE and TSK_GEO_LATITUDE attributes.
*
*/
final class CustomArtifactWaypoint extends Waypoint {
/**
* Constructs a new waypoint from the given artifact.
*
* @param artifact BlackboardArtifact for this waypoint
*
* @throws GeoLocationDataException
*/
CustomArtifactWaypoint(BlackboardArtifact artifact) throws GeoLocationDataException {
this(artifact, getAttributesFromArtifactAsMap(artifact));
}
/**
* Constructs a new CustomArtifactWaypoint.
*
* @param artifact BlackboardArtifact for this waypoint
* @param attributeMap A Map of the BlackboardAttributes for the given
* artifact.
*
* @throws GeoLocationDataException
*/
private CustomArtifactWaypoint(BlackboardArtifact artifact, Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) throws GeoLocationDataException {
super(artifact,
getLabelFromArtifact(attributeMap),
attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME) != null ? attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME).getValueLong() : null,
attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE) != null ? attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE).getValueDouble() : null,
attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE) != null ? attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE).getValueDouble() : null,
attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE) != null ? attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE).getValueDouble() : null,
null, attributeMap, null);
}
/**
* Gets the label for this waypoint.
*
* @param artifact BlackboardArtifact for waypoint
*
* @return Returns a label for the waypoint, or empty string if no label was
* found.
*/
private static String getLabelFromArtifact(Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) {
BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
if (attribute != null) {
return attribute.getDisplayString();
}
return "";
}
}

View File

@ -71,7 +71,7 @@ final class LastKnownWaypoint extends Waypoint {
"LastKnownWaypoint_Label=Last Known Location",})
private static String getLabelFromArtifact(Map<BlackboardAttribute.ATTRIBUTE_TYPE, BlackboardAttribute> attributeMap) throws GeoLocationDataException {
BlackboardAttribute attribute = attributeMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME);
String label = attribute.getDisplayString();
String label = attribute != null ? attribute.getDisplayString() : Bundle.LastKnownWaypoint_Label();
if (label == null || label.isEmpty()) {
label = Bundle.LastKnownWaypoint_Label();

View File

@ -125,6 +125,7 @@ public final class Route {
/**
* Get the route start point.
*
* @param artifact
* @param attributeMap Map of artifact attributes for this waypoint.
*
* An exception will be thrown if longitude or latitude is null.

View File

@ -187,7 +187,7 @@ public class Waypoint {
/**
* Gets the label for this waypoint.
*
* @param artifact BlackboardArtifact for waypoint
* @param attributeMap Attributes for waypoint
*
* @return Returns a label for the waypoint, or empty string if no label was
* found.
@ -232,7 +232,7 @@ public class Waypoint {
* will not include attributes that the Waypoint interfact has get functions
* for.
*
* @param artifact Blackboard artifact to get attributes\properties from
* @param attributeMap Attributes for the given artifact
*
* @return A List of Waypoint.Property objects
*

View File

@ -56,7 +56,8 @@ public final class WaypointBuilder {
final static String GEO_ARTIFACT_WITH_DATA_SOURCES_QUERY
= "SELECT blackboard_attributes.artifact_id "
+ "FROM blackboard_attributes, blackboard_artifacts "
+ "WHERE blackboard_attributes.attribute_type_id IN(%d, %d) "
+ "WHERE blackboard_attributes.artifact_id = blackboard_artifacts.artifact_id "
+ "AND blackboard_attributes.attribute_type_id IN(%d, %d) "
+ "AND data_source_obj_id IN (%s)"; //NON-NLS
// Select will return the "most recent" timestamp from all waypoings
@ -469,6 +470,18 @@ public final class WaypointBuilder {
* @return SQL SELECT statement
*/
static private String buildQueryForWaypointsWOTimeStamps(List<DataSource> dataSources) {
// SELECT_WO_TIMESTAMP
// SELECT DISTINCT artifact_id, artifact_type_id
// FROM blackboard_attributes
// WHERE artifact_id NOT IN (%s)
// AND artifact_id IN (%s)
// GEO_ARTIFACT_QUERY_ID_ONLY
// SELECT artifact_id
// FROM blackboard_attributes
// WHERE attribute_type_id IN (%d, %d)
return String.format(SELECT_WO_TIMESTAMP,
String.format(GEO_ARTIFACT_QUERY_ID_ONLY,
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(),
@ -502,6 +515,13 @@ public final class WaypointBuilder {
String mostRecentQuery = "";
if (!showAll && cntDaysFromRecent > 0) {
// MOST_RECENT_TIME
// SELECT MAX(value_int64) - (%d * 86400)
// FROM blackboard_attributes
// WHERE attribute_type_id IN(%d, %d)
// AND artifact_id
// IN ( %s )
//
mostRecentQuery = String.format("AND value_int64 > (%s)", //NON-NLS
String.format(MOST_RECENT_TIME,
cntDaysFromRecent,
@ -511,7 +531,10 @@ public final class WaypointBuilder {
));
}
// This givens us all artifact_ID that have time stamp
// GEO_ARTIFACT_QUERY
// SELECT artifact_id, artifact_type_id
// FROM blackboard_attributes
// WHERE attribute_type_id IN (%d, %d)
String query = String.format(GEO_ARTIFACT_QUERY,
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(),
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID());
@ -542,6 +565,10 @@ public final class WaypointBuilder {
static private String getWaypointListQuery(List<DataSource> dataSources) {
if (dataSources == null || dataSources.isEmpty()) {
// GEO_ARTIFACT_QUERY
// SELECT artifact_id, artifact_type_id
// FROM blackboard_attributes
// WHERE attribute_type_id IN (%d, %d)
return String.format(GEO_ARTIFACT_QUERY,
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID(),
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START.getTypeID());
@ -592,8 +619,11 @@ public final class WaypointBuilder {
Route route = new Route(artifact);
waypoints.addAll(route.getRoute());
break;
case TSK_GPS_LAST_KNOWN_LOCATION:
waypoints.add(new LastKnownWaypoint(artifact));
break;
default:
throw new GeoLocationDataException(String.format("Unable to create waypoint for artifact of type %s", type.toString()));
waypoints.add(new CustomArtifactWaypoint(artifact));
}
return waypoints;

View File

@ -16,7 +16,6 @@ EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnMsg=Possib
EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnDetails=Compression ratio is {0}, skipping items in {1}.
EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnMsg.zipBomb=Possible ZIP bomb detected: {0}
EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnDetails.zipBomb=The archive is {0} levels deep, skipping processing of {1}
EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.unknownPath.msg=Unknown item path in archive: {0}, will use: {1}
EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.msg=Not enough disk space to unpack archive item: {0}, {1}
EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.details=The archive item is too large to unpack, skipping unpacking this item.
EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.msg=Error unpacking {0}

View File

@ -28,7 +28,6 @@ EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnMsg=\u30a2
EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnDetails=\u5727\u7e2e\u7387\u306f {0} \u3067\u3059\u3002{1} \u306e\u9805\u76ee\u3092\u30b9\u30ad\u30c3\u30d7\u3057\u307e\u3059\u3002
EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnMsg.zipBomb=ZIP\u7206\u5f3e\u304c\u691c\u51fa\u3055\u308c\u305f\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059: {0}
EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnDetails.zipBomb=\u30a2\u30fc\u30ab\u30a4\u30d6\u306f {0} \u30ec\u30d9\u30eb\u306e\u6df1\u3055\u3067\u3059\u3002{1} \u306e\u51e6\u7406\u3092\u30b9\u30ad\u30c3\u30d7\u3057\u307e\u3059
EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.unknownPath.msg=\u30a2\u30fc\u30ab\u30a4\u30d6\u306e\u4e0d\u660e\u306a\u9805\u76ee\u30d1\u30b9: {0}\u3001\u6b21\u3092\u4f7f\u7528\u3057\u307e\u3059: {1}
EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.msg=\u30a2\u30fc\u30ab\u30a4\u30d6\u9805\u76ee\u3092\u958b\u5c01\u3059\u308b\u305f\u3081\u306e\u5341\u5206\u306a\u30c7\u30a3\u30b9\u30af\u9818\u57df\u304c\u3042\u308a\u307e\u305b\u3093: {0}\u3001{1}
EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.details=\u30a2\u30fc\u30ab\u30a4\u30d6\u9805\u76ee\u304c\u5927\u304d\u3059\u304e\u3067\u958b\u5c01\u3067\u304d\u307e\u305b\u3093\u3002\u3053\u306e\u9805\u76ee\u306e\u958b\u5c01\u3092\u30b9\u30ad\u30c3\u30d7\u3057\u307e\u3059\u3002
EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.msg={0} \u306e\u958b\u5c01\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f

View File

@ -449,10 +449,6 @@ class SevenZipExtractor {
} else {
pathInArchive = "/" + useName;
}
String msg = NbBundle.getMessage(SevenZipExtractor.class,
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.unknownPath.msg",
getArchiveFilePath(archiveFile), pathInArchive);
logger.log(Level.WARNING, msg);
}
return pathInArchive;
}
@ -1196,6 +1192,7 @@ class SevenZipExtractor {
*
* @param parent
* @param tokenPath
* @param tokenPathBytes
*
* @return
*/

View File

@ -1,5 +1,6 @@
CannotRunFileTypeDetection=Cannot run file type detection.
ExifParserFileIngestModule.indexError.message=Failed to post EXIF Metadata artifact(s).
ExifParserFileIngestModule.userContent.description=EXIF metadata exists for this file.
OpenIDE-Module-Display-Category=Ingest Module
OpenIDE-Module-Long-Description=Exif metadata ingest module. \n\nThe ingest module analyzes image files, extracts Exif information and posts the Exif data as results.
OpenIDE-Module-Name=ExifParser

View File

@ -49,6 +49,7 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Blackboard;
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_USER_CONTENT_SUSPECTED;
import org.sleuthkit.datamodel.BlackboardAttribute;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_CREATED;
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_MAKE;
@ -130,6 +131,7 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
return processFile(content);
}
@Messages({"ExifParserFileIngestModule.userContent.description=EXIF metadata exists for this file."})
private ProcessResult processFile(AbstractFile file) {
try (BufferedInputStream bin = new BufferedInputStream(new ReadContentInputStream(file));) {
@ -193,11 +195,13 @@ public final class ExifParserFileIngestModule implements FileIngestModule {
// Create artifact if it doesn't already exist.
if (!blackboard.artifactExists(file, TSK_METADATA_EXIF, attributes)) {
BlackboardArtifact bba = file.newArtifact(TSK_METADATA_EXIF);
BlackboardArtifact bba2 = file.newArtifact(TSK_USER_CONTENT_SUSPECTED);
bba.addAttributes(attributes);
bba2.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION, MODULE_NAME, Bundle.ExifParserFileIngestModule_userContent_description()));
try {
// index the artifact for keyword search
blackboard.postArtifact(bba, MODULE_NAME);
blackboard.postArtifact(bba2, MODULE_NAME);
} catch (Blackboard.BlackboardException ex) {
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS
MessageNotifyUtil.Notify.error(

View File

@ -254,10 +254,10 @@ public class FileTypeDetector {
} else {
/*
* If the file was marked as an octet stream and the extension is .txt, try to detect a text
* encoding with Decodetect.
* encoding
*/
if (file.getNameExtension().equals("txt")) {
Charset detectedCharset = TextFileExtractor.getEncoding(file);
Charset detectedCharset = new TextFileExtractor(file).getEncoding();
if (detectedCharset != TextFileExtractor.UNKNOWN_CHARSET) {
mimeType = MimeTypes.PLAIN_TEXT;
}

View File

@ -3,7 +3,7 @@ PlasoIngestModule.artifact.progress=Adding events to case: {0}
PlasoIngestModule.bad.imageFile=Cannot find image file name and path
PlasoIngestModule.completed=Plaso Processing Completed
PlasoIngestModule.create.artifacts.cancelled=Cancelled Plaso Artifact Creation
PlasoIngestModule.dataSource.not.an.image=Datasource is not an Image.
PlasoIngestModule.dataSource.not.an.image=Skipping non-disk image datasource
PlasoIngestModule.error.creating.output.dir=Error creating Plaso module output directory.
PlasoIngestModule.error.running.log2timeline=Error running log2timeline, see log file.
PlasoIngestModule.error.running.psort=Error running Psort, see log file.
@ -11,7 +11,7 @@ PlasoIngestModule.event.datetime=Event Date Time
PlasoIngestModule.event.description=Event Description
PlasoIngestModule.exception.posting.artifact=Exception Posting artifact.
PlasoIngestModule.executable.not.found=Plaso Executable Not Found.
PlasoIngestModule.has.run=Plaso Plugin has been run.
PlasoIngestModule.has.run=Plaso
PlasoIngestModule.info.empty.database=Plaso database was empty.
PlasoIngestModule.log2timeline.cancelled=Log2timeline run was canceled
PlasoIngestModule.psort.cancelled=psort run was canceled

View File

@ -117,6 +117,7 @@ public final class KMLReport implements GeneralReportModule {
*
* @param baseReportDir path to save the report
* @param progressPanel panel to update the report's progress
* @param waypointList
*/
@Messages({
"KMLReport.unableToExtractPhotos=Could not extract photo information.",
@ -524,10 +525,8 @@ public final class KMLReport implements GeneralReportModule {
*
* @param startLatitude Starting latitude
* @param startLongitude Starting longitude
* @param startAltitude Starting altitude. Currently ignored.
* @param stopLatitude Ending latitude
* @param stopLongitude Ending longitude
* @param stopAltitude Ending altitude. Currently ignored.
*
* @return the Line as an Element
*/

View File

@ -85,14 +85,14 @@ public class TextExtractorFactory {
* @param content AbstractFile content
* @param context Lookup containing extractor configurations
*
* @return
* @return List of all extractors in priority order. Not all will support the passed in content. @@@ PERHAPS ONLY SUPPORTED SHOULD BE RETURNED
*/
private static List<TextExtractor> getFileExtractors(AbstractFile content, Lookup context) {
List<TextExtractor> fileExtractors = Arrays.asList(
new TextFileExtractor(content),
new HtmlTextExtractor(content),
new SqliteTextExtractor(content),
new TikaTextExtractor(content));
new TikaTextExtractor(content)); /// This should go last to ensure the more specific ones are picked first.
fileExtractors.forEach((fileExtractor) -> {
fileExtractor.setExtractionSettings(context);

View File

@ -31,17 +31,24 @@ import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
import java.util.List;
import java.util.logging.Level;
import org.apache.tika.parser.txt.CharsetDetector;
import org.apache.tika.parser.txt.CharsetMatch;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.TskCoreException;
/**
* Extract text from text files
* A TextExtractor that is used to extract text from a text file.
*/
public final class TextFileExtractor implements TextExtractor {
public static Charset UNKNOWN_CHARSET = new Charset("unknown", null) {
/*
* The char set returned if a text file extractor fails to detect the
* encoding of the file from which it is extracting text.
*/
public static final Charset UNKNOWN_CHARSET = new Charset("unknown", null) {
@Override
public boolean contains(Charset cs) {
return false;
@ -59,33 +66,45 @@ public final class TextFileExtractor implements TextExtractor {
};
// This value will be used as a threshold for determining which encoding
// detection library to use. If Tika's own confidence is at least
// MIN_MATCH_CONFIDENCE, Tika's result will be used for decoding.
// detection library to use. If CharsetDetector's own confidence is at least
// MIN_MATCH_CONFIDENCE, CharsetDetector's result will be used for decoding.
// Otherwise, Decodetect will be used.
static final private int MIN_TIKA_MATCH_CONFIDENCE = 35;
//
// Note: We initially used a confidence of 35, but it was causing some
// Chrome Cache files to get flagged as UTF-16 with confidence 40.
// These files had a small amount of binary data and then ASCII.
static final private int MIN_CHARSETDETECT_MATCH_CONFIDENCE = 41;
// This value determines whether we will consider Decodetect's top-scoring
// result a legitimate match or if we will disregard its findings
// result a legitimate match or if we will disregard its findings.
//
// Possible values are 0 to 1, inclusive
// Possible values are 0 to 1, inclusive.
static final private double MIN_DECODETECT_MATCH_CONFIDENCE = 0.4;
private static final Logger logger = Logger.getLogger(SqliteTextExtractor.class.getName());
private final AbstractFile file;
private Charset encoding = null;
/**
* Constructs a TextExtractor that is used to extract text from a text file.
*
* @param file The file.
*/
public TextFileExtractor(AbstractFile file) {
this.file = file;
}
@Override
public Reader getReader() {
Charset encoding = getEncoding(file);
if (encoding.equals(UNKNOWN_CHARSET)) {
encoding = StandardCharsets.UTF_8;
Charset enc = getEncoding();
if (enc.equals(UNKNOWN_CHARSET)) {
enc = StandardCharsets.UTF_8;
}
return getReader(encoding);
return getReader(enc);
}
public Reader getReader(Charset encoding) {
private Reader getReader(Charset encoding) {
return new InputStreamReader(new BufferedInputStream(new ReadContentInputStream(file)), encoding);
}
@ -94,42 +113,60 @@ public final class TextFileExtractor implements TextExtractor {
return file.getMIMEType().equals("text/plain");
}
public class TextFileExtractorException extends Exception {
public TextFileExtractorException(String msg, Throwable ex) {
super(msg, ex);
}
public TextFileExtractorException(String msg) {
super(msg);
}
/**
* Returns the encoding of the file.
*
* @return Detected encoding or UNKNOWN_CHARSET.
*/
public Charset getEncoding() {
if (encoding != null) {
return encoding;
}
public static Charset getEncoding(Content content) {
try (InputStream stream = new BufferedInputStream(new ReadContentInputStream(content))) {
// Tika first
// Encoding detection is hard. We use several libraries since the data passed in is often messy.
// First try CharsetDetector (from Tika / ICU4J).
// It is a rule-based detection approach.
try (InputStream stream = new BufferedInputStream(new ReadContentInputStream(file))) {
CharsetDetector detector = new CharsetDetector();
detector.setText(stream);
CharsetMatch tikaResult = detector.detect();
if (tikaResult != null && tikaResult.getConfidence() >= MIN_TIKA_MATCH_CONFIDENCE) {
if (tikaResult != null && tikaResult.getConfidence() >= MIN_CHARSETDETECT_MATCH_CONFIDENCE) {
try {
return Charset.forName(tikaResult.getName());
} catch (UnsupportedCharsetException ignored) {
encoding = Charset.forName(tikaResult.getName());
return encoding;
} catch (UnsupportedCharsetException ex) {
logger.log(Level.WARNING, String.format("Error converting CharsetDetector result for %s (objID=%d)", file.getName(), file.getId()), ex);
}
}
} catch (IOException ex) {
logger.log(Level.WARNING, String.format("Error setting CharsetDetector stream for %s (objID=%d)", file.getName(), file.getId()), ex);
}
// Decodetect if Tika fails or falls below confidence threshold
// If that did not work, then use DecoDetect, which is stastical
// We needed this for some Japanese text files that were incorrectly detected by CharsetDetector (with low confidence)
// This will not always work with messy data that combines some binary and some ASCII.
try {
int maxBytes = 100000;
int numBytes = Math.min(stream.available(), maxBytes);
int numBytes = maxBytes;
if (file.getSize() < maxBytes) {
numBytes = (int) file.getSize();
}
byte[] targetArray = new byte[numBytes];
stream.read(targetArray);
file.read(targetArray, 0, numBytes);
List<DecodetectResult> results = Decodetect.DECODETECT.getResults(targetArray);
if (!results.isEmpty()) {
DecodetectResult topResult = results.get(0);
if (topResult.getConfidence() >= MIN_DECODETECT_MATCH_CONFIDENCE) {
return topResult.getEncoding();
encoding = topResult.getEncoding();
return encoding;
}
}
} catch (IOException ignored) {
} catch (TskCoreException ex) {
logger.log(Level.WARNING, String.format("Error reading content from %s (objID=%d)", file.getName(), file.getId()), ex);
}
return UNKNOWN_CHARSET;
encoding = UNKNOWN_CHARSET;
return encoding;
}
}

View File

@ -135,7 +135,7 @@
<compile-dependency/>
<run-dependency>
<release-version>10</release-version>
<specification-version>10.17</specification-version>
<specification-version>10.18</specification-version>
</run-dependency>
</dependency>
<dependency>

View File

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

View File

@ -2150,10 +2150,15 @@ public final class DrawableDB {
public void deleteDataSource(long dataSourceID) throws SQLException, TskCoreException {
dbWriteLock();
DrawableTransaction trans = null;
String whereClause = "WHERE data_source_obj_id = " + dataSourceID;
String tableName = "image_gallery_groups";
try {
trans = beginTransaction();
deleteDataSourceStmt.setLong(1, dataSourceID);
deleteDataSourceStmt.executeUpdate();
if (caseDb.getCaseDbAccessManager().tableExists(tableName)) {
caseDb.getCaseDbAccessManager().delete(tableName, whereClause);
}
commitTransaction(trans, true);
} catch (SQLException | TskCoreException ex) {
if (null != trans) {

View File

@ -126,6 +126,7 @@ class TextMessageAnalyzer(general.AndroidComponentAnalyzer):
artifact.addAttributes(attributes)
if address is not None:
# Create an account
msgAccountInstance = Case.getCurrentCase().getSleuthkitCase().getCommunicationsManager().createAccountFileInstance(Account.Type.PHONE, address, general.MODULE_NAME, abstractFile);

View File

@ -119,7 +119,7 @@
<compile-dependency/>
<run-dependency>
<release-version>10</release-version>
<specification-version>10.17</specification-version>
<specification-version>10.18</specification-version>
</run-dependency>
</dependency>
<dependency>

View File

@ -680,7 +680,6 @@ public final class KeywordSearchIngestModule implements FileIngestModule {
* Returns true if indexing was successful and false otherwise.
*
* @param aFile Text file to analyze
* @param detectedCharset the encoding of the file
*/
private boolean indexTextFile(AbstractFile aFile) {
try {

View File

@ -1,3 +1,36 @@
---------------- VERSION 4.14.0 --------------
Specialized UIs:
- New File Discovery UI that allows you to search and filter for certain types of files.
- New Map viewer that uses either Bing (when online) or offline map tiles.
- Communications UI shows country names for phone numbers and fixed bug in summary panel.
- Fixed bugs in timeline filtering.
- Refactored backend timeline filtering code based on The Sleuth Kit datamodel changes to remove JavaFX dependency.
Data Sources:
- Added limited support for APFS disk images. Does not include encrypted volumes or ones that span multiple disks. Uses contribution to The Sleuth Kit from Blackbag Technologies.
- New data source processor that parses “XRY File Exports”.
Content Viewers:
- Added a new “Context” viewer to show where a file came from. Currently shows what message a file was attached to or what URL a file was downloaded from.
- Added support to seek and change playback speed for videos in “Application” viewer.
- Improved support for Unicode HTML files in “Application” viewer.
- Added support for webp image files in “Application” viewer.
Ingest Modules:
- Keyword Search module uses Decodetect statistical encoding detection for plain text files. Fixes issues with incorrect detection of Japanese files.
- Embedded File Extractor module uses statistical analysis to determine encoding of file names in ZIP files. Fixes issues with ZIP files created on Windows Japanese computers.
- Solr (Keyword Search module) now uses Japanese-specific tokenization using Kuromoji.
- Fixed Shellbags module in RegRipper (used by Autopsy Recent Activity module) to fix parsing errors.
- Plaso module no longer generates an error if enabled for non-disk image data sources.
- Added support for message attachments that are stored as an external file system file. Expanded Email and Android modules to use this technique.
General:
- Fixed crashes by gstreamer when a video is selected.
- Added initial capability to delete a data source from a case (excludes data in the CR).
- Changed behavior of portable case menu item to automatically open the case and warn if it was already unpacked.
- Fixed bug that caused issues when case metadata had Unicode values.
- Added new Attachment APIs to the CommunicationsArtifactHelper class to support attachments stored as external file system files.
---------------- VERSION 4.13.0 --------------
General:
- Switch from Oracle JDK to OpenJDK.

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
<hr/>
<p><i>Copyright &#169; 2012-2019 Basis Technology. Generated on $date<br/>
<p><i>Copyright &#169; 2012-2020 Basis Technology. Generated on $date<br/>
This work is licensed under a
<a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/">Creative Commons Attribution-Share Alike 3.0 United States License</a>.
</i></p>

View File

@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy User Documentation"
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 4.13.0
PROJECT_NUMBER = 4.14.0
# 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
@ -1025,7 +1025,7 @@ GENERATE_HTML = YES
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = 4.13.0
HTML_OUTPUT = 4.14.0
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).

View File

@ -52,14 +52,10 @@ There are no runtime ingest settings required.
Seeing Results
------
The results show up in the tree under "Results", "Extracted Content".
The results show up in the tree under "Results", "Extracted Content". The exact data extracted will vary but can include contacts, call logs, messages, and GPS entries.
\image html android_analyzer_output.PNG
Messages can also be seen by browsing to the source file in the Data Sources tree, which will display the messages in the Results Viewer to the right. Any messages with attachments will be shown under the source file in the tree, and the attachments can be seen in the Result Viewer.
\image html messages_datasource_tree.png
*/

View File

@ -54,6 +54,10 @@ It will display most image types, which can be scaled and rotated:
\image html content_viewer_app_image.png
It displays video files, allowing you to move play/pause, move forward or backward 30 seconds, adjust the volume, and change the playback speed.
\image html content_viewer_video.png
It also allows you to browse SQLite tables and export their contents as CSV:
\image html content_viewer_app_sqlite.png
@ -82,6 +86,12 @@ The File Metadata tab displays basic information about the file, such as type, s
\image html content_viewer_metadata.png
\section cv_context Context
The Context tab shows the the source of attached files and allows you to view the original result. In the image below you can see the context for an image that was sent as an email attachment.
\image html content_viewer_context.png
\section cv_results Results
The Results tab is active when selecting items with associated results such as keyword hits, call logs, and messages. The exact fields displayed depend on the type of result. The two images below show the Results tab for a call log and a web bookmark.

View File

@ -3,12 +3,13 @@
A data source is the thing you want to analyze. It can be a disk image, some logical files, a local disk, etc. You must open a case prior to adding a data source to Autopsy.
Autopsy supports four types of data sources:
Autopsy supports multiple types of data sources:
- Disk Image or VM File: A file (or set of files) that is a byte-for-byte copy of a hard drive or media card, or a virtual machine image. (see \ref ds_img)
- Local Disk: Local storage device (local drive, USB-attached drive, etc.). (see \ref ds_local)
- Logical Files: Local files or folders. (see \ref ds_log)
- Unallocated Space Image Files: Any type of file that does not contain a file system but you want to run through ingest (see \ref ds_unalloc)
- Autopsy Logical Imager Results: The results from running the logical imager. (see \ref ds_logical_imager)
- XRY Text Export: The results from exporting text files from XRY. (see \ref ds_xry)
\section ds_add Adding a Data Source
@ -41,7 +42,7 @@ NOTE: If you are adding a data source to a multi-user case, ensure that all Auto
6) After the ingest modules have been configured and the basic examination of the data source is complete, the ingest modules will begin to analyze the file contents.
You cannot remove a data source from a case.
Data sources can be removed from cases created with Autopsy 4.14.0 and later. See the section \ref data_source_deletion "below".
\section ds_img Adding a Disk Image
@ -116,4 +117,23 @@ To add unallocated space image files:
This option allows you to add the results of a logical imager collection. See the \ref logical_imager_page page for details.
\section ds_xry Adding XRY Text Export Data
An XRY text export folder is expected to look similar to this:
\image html xry_folder.png
To add exported text files:
-# Choose "XRY Text Export" from the data source types.
-# Browse to the folder containing the text files.
\image html xry_dsp.png
\section data_source_deletion Deleting Data Sources
As of Autopsy 4.14.0, data sources can be removed from cases. Removing a data source will delete all files associate with the data source, as well as all results from running ingest modules, tags, and timeline data. \ref reporting_page "Reports" will not be deleted, as most are not associated with a specific data source. If a new data source was created while processing another (from the \ref vm_extractor_page for example), this new data source will also be deleted if its parent is deleted.
To delete a data source, right click it in either the \ref tree_viewer_page or the \ref result_viewer_page and select "Remove Data Source". If the case was originally created with a version of Autopsy earlier than 4.14.0 then this option will be disabled. After a confirmation dialog, the case will close and then reopen after the data source has been removed.
\image html data_source_delete.png
*/

View File

@ -23,12 +23,14 @@ There are no runtime ingest settings required.
Seeing Results
------
The results of this show up in the "Results", "E-Mail Messages" portion of the tree.
The results of this show up in the "Results", "E-Mail Messages" portion of the \ref tree_viewer_page.
\image html email_results.PNG
The results can also be seen by browsing to the source file in the Data Sources tree, which will display the messages in the Results Viewer to the right. Any messages with attachments will be shown under the source file, and the attachments can be seen in the Result Viewer by selecting the message.
If an e-email has an attachment, the "Attachments" tab in the \ref content_viewer_page will be active.
\image html email_datasource_tree.png
\image html email_attachments.png
You can right click and select "View File in Directory" to navigate to the attached file. You can also switch to the "Thumbnails" tab to see a preview of any image attachments.
*/

View File

@ -14,6 +14,10 @@ One can add and remove MIME types in the "Tools", "Options", "File Extension Mis
\image html extension-mismatch-detected-configuration.PNG
<br>
If you'd like to contribute your changes back to the community, then you'll need to upload your updated %APPDATA%\autopsy\dev\config\mismatch_config.xml file by either:
- Make a fork of the Github Autopsy repository, copy the new file into the src\org\sleuthkit\autopsy\fileextmismatch folder and submit a pull request
- Attach the entire mismatch_config.xml file to a github issue.
Using the Module
======
Note that you can get a lot of false positives with this module. You can add your own rules to Autopsy to reduce unwanted hits.

View File

@ -0,0 +1,189 @@
/*! \page file_discovery_page File Discovery
\section file_disc_overview Overview
The file discovery tool shows images or videos that match a set of filters configured by the user. You can choose how to group and order your results in order to see the most relevant data first.
\section file_disc_prereq Prerequisites
We suggest running all \ref ingest_page "ingest modules" before launching file discovery, but if time is a factor the following are the modules that are the most important. You will see a warning if you open file discovery without running the \ref file_type_identification_page and \ref EXIF_parser_page.
Required ingest modules:
<ul>
<li>\ref file_type_identification_page
</ul>
Optional ingest modules:
<ul>
<li>\ref cr_ingest_module - Needed to use the \ref file_disc_occur_filter
<li> \ref EXIF_parser_page - Needed to use the \ref file_disc_user_filter
<li>\ref hash_db_page - Needed to use the \ref file_disc_hash_filter and to de-duplicate files
<li>\ref interesting_files_identifier_page - Needed to use the \ref file_disc_int_filter
<li>\ref object_detection_page - Needed to use the \ref file_disc_obj_filter
</ul>
\section file_disc_run Running File Discovery
To launch file discovery, either click the "File Discovery" icon near the top of the Autopsy UI or go to "Tools", "File Discovery". There are three steps when setting up file discovery, which flow from the top of the panel to the bottom:
<ol>
<li>\ref file_disc_type "Choose the file type"
<li>\ref file_disc_filtering "Set up filters"
<li>\ref file_disc_grouping "Choose how to group and sort the results
</ol>
Once everything is set up, use the "Show" button at the bottom of the left panel to display your results. If you want to cancel a search in progress you can use the "Cancel" button.
\image html FileDiscovery/fd_main.png
\subsection file_disc_type File Type
The first step is choosing whether you want to display images or videos. The file type is determined by the MIME type of the file, which is why the file_type_identification_page must be run to see any results. Switching between the file types will clear any results being displayed and reset the filters.
\image html FileDiscovery/fd_fileType.png
\subsection file_disc_filtering Filtering
The second step is to select and configure your filters. For most filters, you enable them using the checkbox on the left and then select your options. Multiple options can be selected by using CTRL + left click. Files must pass all enabled filters to be displayed.
\subsubsection file_disc_size_filter File Size Filter
The file size filter lets you restrict the size of your results. The options are different for images and videos - an extra small image might be under 16 KB while an extra small video is anything under 500 KB.
\image html FileDiscovery/fd_fileSizeFilter.png
\subsubsection file_disc_ds_filter Data Source Filter
The data source filter lets you restrict which data sources in your case to include in the results.
\image html FileDiscovery/fd_dataSourceFilter.png
\subsubsection file_disc_occur_filter Past Occurrences Filter
The past occurrences filter uses the \ref central_repo_page "central repository" and \ref hash_db_page "known hash sets" to restrict how commom/rare a file must be to be included in the results. By default, the "Known Files" option is disabled, meaning that any file matching the NSRL or other white-listed hash set will not be displayed.
\image html FileDiscovery/fd_pastOccur.png
The counts for the rest of the options are based on how many data sources in your central repository contain a copy of this file (based on hash). If a file only appears in one data source in the current case, then it will match "Unique(1)". If it has only been seen in a few other data source, it will match "Rare(2-10)". Note that it doesn't matter how many times a file appears in each data source - a file could have twenty copies in one data source and still be "unique".
\subsubsection file_disc_user_filter Possibly User Created
The possibly user created filter restricts the results to files that suspected to be raw images or videos.
\image html FileDiscovery/fd_userCreatedFilter.png
This means the image or video must have a "User Content Suspected" result associated with it. These primarily come from the \ref EXIF_parser_page "Exif parser module".
\image html FileDiscovery/fd_userContentArtifact.png
\subsubsection file_disc_hash_filter Hash Set Filter
The hash set filter restricts the results to files found in the selected hash sets. Only notable hash sets that have hits in the current case are listed (though those hits may not be images or videos). See the \ref hash_db_page page for more information on creating and using hash sets.
\image html FileDiscovery/fd_hashSetFilter.png
\subsubsection file_disc_int_filter Interesting Item Filter
The interesting item filter restricts the results to files found in the selected interesting item rule sets. Only interesting file rule sets that have results in the current case are listed (though those matches may not be images or videos). See the \ref interesting_files_identifier_page page for more information on creating and using interesting item rule sets.
\image html FileDiscovery/fd_interestingItemsFilter.png
\subsubsection file_disc_obj_filter Object Detected Filter
The object detected filter restricts the results to files that matched the selected classifiers. Only classifiers that have results in the current case are listed. Note that currently the built-in \ref object_detection_page ingest module only works on images, so you should generally not use this filter with videos. See the \ref object_detection_page page for more information on setting up classifiers.
\image html FileDiscovery/fd_objectFilter.png
\subsubsection file_disc_parent_filter Parent Folder Filter
The parent folder filter either restricts the path the files can be on. This filter works differently than the others in that the individual options do not have to be selected - every rule that has been entered will be applied.
\image html FileDiscovery/fd_parentFilter.png
You can enter paths that should be included and paths that should be ignored. For both you then specify whether the path string you entered is a full path or a substring. For full path matches you'll need to include the leading and trailing slashes. Full path matches are also case-sensitive.
The default options, shown above, will exclude any file that has a "Windows" folder or a "Program Files" folder in its path. It would exclude files like "/Windows/System32/image1.jpg" but would not exclude "/My Pictures/Bay Windows/image2.jpg" because the slashes around "Windows" force it to match the exact folder name.
Here is another example. This rule was created with "Full" and "Include" selected.
\image html FileDiscovery/fd_parentEx2.png
This matches the file "/LogicalFileSet2/File Discovery/bird1.tif" but not any images in subfolders under "File Discovery".
When there are multiple path options in the filter, they will be applied as follows:
<ul>
<li>The file path must match every "exclude" rule to pass
<li>If any "include" rules exist, the file path must match at least one "include" rule to pass
</ul>
This allows you to, for example, make rules to include both the "My Documents" and the "My Pictures" folders.
\subsection file_disc_grouping Grouping and Sorting
The final options are for how you want to group and sort your results.
\image html FileDiscovery/fd_grouping.png
The first option lets you choose the top level grouping for your results and the second option lets you choose how to sort them. The groups appear in the middle column of the file discovery panel. Note that some of the grouping options may not always appear - for example, grouping by past occurrences will only be present if the \ref central_repo_page is enabled, and grouping by hash set will only be present if there are hash set hits in your current case. The example below shows the groups created using the default options (group by file size, order groups by group name):
\image html FileDiscovery/fd_groupingSize.png
In the case of file size and past occurrences, ordering by group name is based on the natural ordering of the group (largest to smallest or most rare to most common). For the other groups it will be alphabetical. Ordering groups by size will sort them based on how many files each group contains, going largest to smallest. For example, here we've grouped by interesting item set and ordered the groups by their size.
\image html FileDiscovery/fd_groupingInt.png
The interesting items filter was not enabled so most images ended up in the "None" group, meaning they have no interesting file result associated with them. The final group in the list contains a file that matched both interesting item rule sets.
The last grouping and sorting option is choosing how to sort the results within a group. This is the order of the results in the top right panel after selecting a group from the middle column. Note that due to the merging of results with the same hash in that panel, ordering by file name, path, or data source can vary. See the \ref file_disc_dedupe section below for more information.
\section file_disc_results Viewing Results
\subsection file_disc_results_overview Overview
Once you select your options and click "Show", you'll see a list of groups in the middle panel. Selecting one of these groups will display the results from that group in the right panel. If your results are images, you'll see thumbnails for each image in the top area of the right panel.
\image html FileDiscovery/fd_resultGroups.png
If your results are videos, each result will display four thumbnails from the video.
\image html FileDiscovery/fd_videos.png
When you select a result from the top of the right panel, you'll see the path to the corresponding file(s) in the "Instances" panel below the thumbnails. There may be more than one file instance associated with a result - see the \ref file_disc_dedupe section below. You can right-click on files in the instances panel to use most of options available in the normal \ref result_viewer_page.
\image html FileDiscovery/fd_instanceContext.png
The bottom section of the panel is identical to the standard \ref content_viewer_page and displays data corresponding to the file instance selected in the middle of the panel.
\subsection file_disc_dedupe De-duplication
Assuming the \ref hash_db_page module has been run, all files in a result group with the same hash will be merged together under a single instance. You can see the number of instances of each file under the thumbnail, and each file instance will be displayed in the middle section of the panel.
\image html FileDiscovery/fd_dupeEx.png
Clicking on a particular instance will load data for that file in the content viewer area at the bottom.
Note that files in different groups will not be merged together or appear under the instances list of each other. For example, if you choose to group by parent folder and have two instances of a file with the same hash but in different folders, each will appear once under its parent folder. Grouping by file size (the default) will always merge every instance of the same file.
\subsection file_disc_icons Status Icons
A number of icons may be displayed in the bottom right of the thumbnails to help point out notable results. Hovering over the icon will display a message explaining why the icon is present. In the image below, the yellow icon is present because the file is associated with an interesting item set.
\image html FileDiscovery/fd_icon.png
Most of the icons match what would be displayed in the "S" column of the normal \ref result_viewer_page.
| Icon | Usage |
|-------|------|
\image html FileDiscovery/yellow-circle-yield.png "" | \ref interesting_files_identifier_page "Interesting file set match" or normal \ref tagging_page "file tag"
\image html FileDiscovery/red-circle-exclamation.png "" | Notable \ref hash_db_page "hash set hit" or notable \ref tagging_page "file tag"
\image html FileDiscovery/file-icon-deleted.png "" | Deleted file (every instance is deleted)
\subsection file_disc_paging Paging
If the group you select has many results, the results will be split up into pages. You can use the left and right arrows to move between pages or type in the page number you wish to go to. You can adjust the number of results per page using the drop down box in the upper right.
\image html FileDiscovery/fd_paging.png
*/

View File

@ -1,5 +1,5 @@
<hr/>
<p><i>Copyright &#169; 2012-2019 Basis Technology. Generated on $date<br/>
<p><i>Copyright &#169; 2012-2020 Basis Technology. Generated on $date<br/>
This work is licensed under a
<a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/us/">Creative Commons Attribution-Share Alike 3.0 United States License</a>.
</i></p>

View File

@ -0,0 +1,137 @@
/*! \page geolocation_page Geolocation
\section geo_overview Overview
The Geolocation window shows artifacts that have longitude and latitude attributes as waypoints on a map. In the field, when access to online map tile servers may not be available, the Geolocation window provides support for offline map tile data sources.
\image html geo_main.png
\section geo_usage Usage
To open the Geolocation window, go to "Tools" and then select "Geolocation".
\subsection geo_navigation General Usage
You can move the map by clicking and dragging, and zoom using either the mouse wheel or the slider in the bottom left of the map. If a map tile is not available the tile will appear grey but the waypoints will still be displayed. This is more likely to happen when changing the default \ref geo_map_options.
You can left click on a waypoint to highlight that waypoint and show a details pop-up in the upper right corner of the map. The details pop-up will be updated as you click on different waypoints. The data displayed will vary depending on the type of waypoint. For example, this is the endpoint of a GPS Route:
\image html geo_details_route.png
While this is an image with GPS coordinates found by the \ref EXIF_parser_page :
\image html geo_details.png
You can also right click on a waypoint to bring up a similar menu to what you'd see in the \ref result_viewer_page.
\image html geo_context_menu.png
\subsection geo_filter Filtering
The filters are displayed on the left side of the screen. The top filter lets you filter the waypoints based on timestamp. If enabled, you will only see waypoints with a timestamp within N days of the most recent waypoint (not the current date). When using this filter you can also choose whether you want to see waypoints with no timestamp. The second filter allows you to show waypoints only for the selected data sources.
\image html geo_filter_panel.png
If desired, the filter panel can be hidden by clicking on the vertical "Filters" tab on the top right edge of the filter panel. Clicking on that tab a second time will restore the filters panel.
\subsection geo_report Generating a Report
You can generate a KML report using the "KML Report" button in the bottom right corner of the window. The report will include only the currently visible waypoints and can be found in the "Reports" folder of your case.
\image html geo_report.png
As with other \ref reporting_page "report modules", the generated report will appear under "Reports" in the \ref tree_viewer_page. Note that you can also use the \ref report_kml report module to generate a report containing all geolocation data in the case.
\section geo_map_options Map Tile Options
<p>The Autopsy Geolocation window supports several map tile data source options. The map tile data source can be changed
on the Geolocation panel in the Options dialog. There are four options for geolocation tile data, two of which can be used offline.
<ul>
<li><b>Default online tile server</b>
<ul>
<li>The default Geolocation window tile data source is the Microsoft Virtual Earth server https://www.bing.com/maps.
</ul>
<li><b>OpenStreetMap server</b>
<ul>
<li>You can specify the address of a OSM tile server. A list of online tile servers can be found here: https://wiki.openstreetmap.org/wiki/Tile_servers.
Tile servers may have restrictions on them that prevent Autopsy from accessing their tiles. If the tiles URL is something of the form "http://tiles.example.org/${z}/${x}/${y}.png",
then you'll need to enter "http://tiles.example.org" in the options panel.
\image html geo_openstreetmap.png
</ul>
<li><b>OpenStreetMap zip file</b>
<ul>
<li>Allows offline use of zip file of OSM tile images
<li>Details on how to generate tile zip files are \ref geo_generate_zip "below".
</ul>
<li><b>MBTiles file</b>
<ul>
<li>Allows offline use of MBTiles file containing raster tiles.
<li>MBTiles raster tiles files can be downloaded from <a href="https://openmaptiles.com/downloads/planet/">OpenMapTiles</a>.
<li>OpenMapTiles provides downloads of MBTile files for areas as large as the whole planet to as small as regions of countries.
<li>For each of these regions there are at least four MBTiles available for download, please be sure to download one of the "Raster Tile" files,
not the "Vector Tiles".
</ul>
</ul>
\subsection geo_generate_zip Using Maperative to Generate Tile Image Zip Files
Maperative is a tool for drawing maps, however it can also be used to create tile images. Maperative download and documentations can be found at http://maperitive.net/ .
By default Maperative uses an online tile server to generate the map. For offline use, users can supply an OpenStreetMap raw data extract.
\subsubsection geo_generate_tile_image Generating tile image zip files using any map data source:
<ol>
<li>Download and run Maperative.
<li>Center and zoom in on area of interest. The larger the area, the more tiles that will be generated. Tiles will be generated for the area visible in the map panel.
<li>Choose whether you want to use the default zoom levels or custom ones. Zoom levels in Mapertive start at 1. As the zoom level increases so will the quantity of tiles generated as well as the detail of each tile. Generating tiles, especially for heavily populated areas, may take time, please be patient with either method.
<ul>
<li>To generate tiles using the default zoom levels, select Tools->Generate Tiles
\image html geo_gen_tiles.png
Maperative will generate tiles for zoom levels depending on the area of interest and the zoom level. For example, if you start all the way zoomed out, you will likely see levels 1 through 10 generated. If you start zoomed in, you might see levels 10 through 14.
<li>Maperative provides a command interface which allows you to generate tiles for specific zoom levels. Commands can be run in the Command prompt text field at the bottom of the Maperative window. For a full list of commands see the Maperative documentation or <a href="http://maperitive.net/docs/">http://maperitive.net/docs/</a>. The <tt>generate-tiles</tt> command can be used to generate tiles for the area visible in the map panel area. For full details on generate-tiles see the documentation included with Maperative or <a href="http://maperitive.net/docs/Commands/GenerateTiles.html">http://maperitive.net/docs/Commands/GenerateTiles.html</a>. The following is a sample command to generate tiles for zoom level 2 to 3 into the folder Tiles:
\verbatim generate-tiles minzoom=2 maxzoom=3 tilesdir=C:\Tiles \endverbatim
\image html geo_command_line.png
</ul>
<li>For use in autopsy, the generated tile images need to be in a zip file. To create a zip of tiles for use in Autopsy, zip up all of the folders in the tile file output directory. Do not include the parent directory, just the numbered folders contained within. If you use the menu bar option or did not specify a folder in your command the generated tiles will be located in &lt;Maperative Install Location&gt;\\Tiles.
\image html geo_tile_folder.png
Be sure to zip only the contents of the folder, not the top level folder.
</ol>
\subsubsection geo_add_ds Adding a data source to Maperative
Maperative can be used to generate tiles using raw data extracts from OpenStreetMaps. Data extracts (*.osm or *.osm.pbf) files can be downloaded from various locations. See https://wiki.openstreetmap.org/wiki/Planet.osm for a list of locations. Geofabrik's free download server has open OpenStreetMap data extracts for many regions. When using OSM raw data extracts in Maperative, the recommendation is to use smaller (.osm) files.
To add a data source to Maperative:
<ol>
<li>Select from the menu bar File->Open Map Source...
\image html geo_add_ds.png
<li>The new data source will appear in the bottom right corner of the window in the "Map Sources" list.
<li>To disable a Map Source, select the Map Source from the list and click the X button.
</ol>
\subsubsection geo_merge_osm Merging OSM raw data extracts
For ease of use, users may want to merge OSM raw data extracts. OSMConvert is a tool that can be used to merge OSM raw data extracts.
To merge two OSM raw data extracts country1.osm.pbf and country2.osm.pbf use the following commands. Note that this assumes that osmcovert and the files are in the same directory; if they are not be sure to use full paths.
\verbatim
osmconvert country1.osm.pbf -o=country1.o5m
osmconvert country2.osm.pbf -o=country2.o5m
osmconvert country1.o5m country2.o5m -o=together.o5m
osmconvert together.o5m -o=together.osm.pbf
\endverbatim
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Some files were not shown because too many files have changed in this diff Show More