mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
Merge https://github.com/sleuthkit/autopsy into manynodesfix
Conflicts: Core/src/org/sleuthkit/autopsy/corecomponents/DataResultPanel.java Core/src/org/sleuthkit/autopsy/datamodel/FileTypeChildren.java
This commit is contained in:
commit
c81669ca61
16
Core/autopsy-updates.xml
Normal file
16
Core/autopsy-updates.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<!DOCTYPE module_updates PUBLIC "-//NetBeans//DTD Autoupdate Catalog 2.5//EN" "http://www.netbeans.org/dtds/autoupdate-catalog-2_7.dtd">
|
||||
|
||||
<module_updates timestamp="03/01/21/12/03/2008">
|
||||
|
||||
<!--notification element goes here for user pop-up. Attribute url is the URL to display along with the message contained between notification xml elements.
|
||||
-->
|
||||
|
||||
<notification url="http://sleuthkit.org/autopsy">
|
||||
Visit http://sleuthkit.org/autopsy to download the latest version of Autopsy.
|
||||
</notification>
|
||||
|
||||
|
||||
|
||||
</module_updates>
|
@ -19,6 +19,7 @@
|
||||
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import org.sleuthkit.autopsy.ingest.IngestConfigurator;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dialog;
|
||||
import java.awt.event.ActionEvent;
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import org.sleuthkit.autopsy.ingest.IngestConfigurator;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.EventQueue;
|
||||
@ -28,6 +29,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JProgressBar;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
@ -39,6 +41,7 @@ import org.sleuthkit.autopsy.casemodule.ContentTypePanel.ContentType;
|
||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
import org.sleuthkit.autopsy.ingest.IngestDialog;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
@ -86,7 +89,14 @@ class AddImageWizardPanel3 implements WizardDescriptor.Panel<WizardDescriptor> {
|
||||
this.action = action;
|
||||
this.wizPanel = wizPanel;
|
||||
ingestConfig = Lookup.getDefault().lookup(IngestConfigurator.class);
|
||||
ingestConfig.setContext(AddImageWizardPanel3.class.getCanonicalName());
|
||||
List<String> messages = ingestConfig.setContext(AddImageWizardPanel3.class.getCanonicalName());
|
||||
if (messages.isEmpty() == false) {
|
||||
StringBuilder warning = new StringBuilder();
|
||||
for (String message : messages) {
|
||||
warning.append(message).append("\n");
|
||||
}
|
||||
JOptionPane.showMessageDialog(null, warning.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -236,7 +236,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
* @param configFilePath the path of the configuration file that's opened
|
||||
* @throws CaseActionException
|
||||
*/
|
||||
static void open(String configFilePath) throws CaseActionException {
|
||||
public static void open(String configFilePath) throws CaseActionException {
|
||||
logger.log(Level.INFO, "Opening case.\nconfigFilePath: {0}", configFilePath);
|
||||
|
||||
try {
|
||||
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2013 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.casemodule;
|
||||
|
||||
import java.util.List;
|
||||
import javax.swing.JPanel;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
|
||||
/**
|
||||
* Lookup interface for ingest configuration dialog
|
||||
*/
|
||||
public interface IngestConfigurator {
|
||||
/**
|
||||
* get JPanel container with the configurator
|
||||
* @return
|
||||
*/
|
||||
JPanel getIngestConfigPanel();
|
||||
|
||||
/**
|
||||
* set input Content to be configured for ingest
|
||||
* @param inputContent content to be configured for ingest
|
||||
*/
|
||||
void setContent(List<Content> inputContent);
|
||||
|
||||
/**
|
||||
* start ingest enqueing previously set image
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* save configuration of lastly selected service
|
||||
*/
|
||||
void save();
|
||||
|
||||
/**
|
||||
* reload the simple panel
|
||||
*/
|
||||
void reload();
|
||||
|
||||
/**
|
||||
* find out if ingest is currently running
|
||||
*
|
||||
* @return true if ingest process is running, false otherwise
|
||||
*/
|
||||
boolean isIngestRunning();
|
||||
|
||||
/**
|
||||
* Set the context for the configuration.
|
||||
* @param context
|
||||
*/
|
||||
public void setContext(String context);
|
||||
|
||||
}
|
@ -144,6 +144,8 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer
|
||||
}
|
||||
addRow(sb, "MD5", md5);
|
||||
|
||||
addRow(sb, "Internal ID", new Long(file.getId()).toString());
|
||||
|
||||
endTable(sb);
|
||||
setText(sb.toString());
|
||||
}
|
||||
|
@ -8,3 +8,5 @@ OpenIDE-Module-Long-Description=\
|
||||
For more information, see http://www.sleuthkit.org/autopsy/
|
||||
OpenIDE-Module-Name=Autopsy-Core
|
||||
OpenIDE-Module-Short-Description=Autopsy Core Module
|
||||
org_sleuthkit_autopsy_core_update_center=http://sleuthkit.org/autopsy/updates.xml
|
||||
Services/AutoupdateType/org_sleuthkit_autopsy_core_update_center.settings=Autopsy Update Center
|
||||
|
@ -270,6 +270,13 @@
|
||||
Services
|
||||
====================================================== -->
|
||||
<folder name="Services">
|
||||
<folder name="AutoupdateType">
|
||||
<file name="org_sleuthkit_autopsy_core_update_center.settings" url="org_sleuthkit_autopsy_core_update_centerSettings.xml">
|
||||
<attr name="displayName" bundlevalue="org.sleuthkit.autopsy.core.Bundle#Services/AutoupdateType/org_sleuthkit_autopsy_core_update_center.settings"/>
|
||||
<attr name="enabled" boolvalue="true"/>
|
||||
<attr name="url" bundlevalue="org.sleuthkit.autopsy.core.Bundle#org_sleuthkit_autopsy_core_update_center"/>
|
||||
</file>
|
||||
</folder>
|
||||
<file name="org-sleuthkit-autopsy-corecomponents-DataContentTopComponent.instance">
|
||||
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.corecomponentinterfaces.DataContent"/>
|
||||
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.corecomponents.DataContentTopComponent.getDefault"/>
|
||||
|
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
To change this template, choose Tools | Templates
|
||||
and open the template in the editor.
|
||||
-->
|
||||
<!DOCTYPE settings PUBLIC "-//NetBeans//DTD Session settings 1.0//EN" "http://www.netbeans.org/dtds/sessionsettings-1_0.dtd">
|
||||
<settings version="1.0">
|
||||
<module name="org.sleuthkit.autopsy.core/8"/>
|
||||
<instanceof class="org.openide.ServiceType"/>
|
||||
<instanceof class="org.netbeans.modules.autoupdate.AutoupdateType"/>
|
||||
<instanceof class="org.netbeans.modules.autoupdate.XMLAutoupdateType"/>
|
||||
<instance class="org.netbeans.modules.autoupdate.XMLAutoupdateType" method="createXMLAutoupdateType"/>
|
||||
</settings>
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011-2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -32,8 +32,6 @@ import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||
import org.sleuthkit.autopsy.datamodel.DataConversion;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.FsContent;
|
||||
import org.sleuthkit.datamodel.LayoutFile;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
|
||||
/**
|
||||
@ -41,11 +39,10 @@ import org.sleuthkit.datamodel.TskException;
|
||||
*/
|
||||
@ServiceProvider(service = DataContentViewer.class, position = 1)
|
||||
public class DataContentViewerHex extends javax.swing.JPanel implements DataContentViewer {
|
||||
|
||||
private static long currentOffset = 0;
|
||||
private static final long pageLength = 16384;
|
||||
private final byte[] data = new byte[(int) pageLength];
|
||||
private static int currentPage = 1;
|
||||
private int totalPages;
|
||||
private Content dataSource;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DataContentViewerHex.class.getName());
|
||||
@ -243,39 +240,28 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void prevPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_prevPageButtonActionPerformed
|
||||
//@@@ this is part of the code dealing with the data viewer. could be copied/removed to implement the scrollbar
|
||||
currentOffset -= pageLength;
|
||||
currentPage = currentPage - 1;
|
||||
currentPageLabel.setText(Integer.toString(currentPage));
|
||||
setDataView(dataSource, currentOffset);
|
||||
setDataView(currentPage - 1);
|
||||
}//GEN-LAST:event_prevPageButtonActionPerformed
|
||||
|
||||
private void nextPageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextPageButtonActionPerformed
|
||||
//@@@ this is part of the code dealing with the data viewer. could be copied/removed to implement the scrollbar
|
||||
currentOffset += pageLength;
|
||||
currentPage = currentPage + 1;
|
||||
currentPageLabel.setText(Integer.toString(currentPage));
|
||||
setDataView(dataSource, currentOffset);
|
||||
setDataView(currentPage + 1);
|
||||
}//GEN-LAST:event_nextPageButtonActionPerformed
|
||||
|
||||
private void goToPageTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_goToPageTextFieldActionPerformed
|
||||
String pageNumberStr = goToPageTextField.getText();
|
||||
int pageNumber = 0;
|
||||
int maxPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1;
|
||||
|
||||
try {
|
||||
pageNumber = Integer.parseInt(pageNumberStr);
|
||||
} catch (NumberFormatException ex) {
|
||||
pageNumber = maxPage + 1;
|
||||
pageNumber = totalPages + 1;
|
||||
}
|
||||
if (pageNumber > maxPage || pageNumber < 1) {
|
||||
JOptionPane.showMessageDialog(this, "Please enter a valid page number between 1 and " + maxPage,
|
||||
if (pageNumber > totalPages || pageNumber < 1) {
|
||||
JOptionPane.showMessageDialog(this, "Please enter a valid page number between 1 and " + totalPages,
|
||||
"Invalid page number", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
currentOffset = (pageNumber - 1) * pageLength;
|
||||
currentPage = pageNumber;
|
||||
currentPageLabel.setText(Integer.toString(currentPage));
|
||||
setDataView(dataSource, currentOffset);
|
||||
setDataView(pageNumber);
|
||||
}//GEN-LAST:event_goToPageTextFieldActionPerformed
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JMenuItem copyMenuItem;
|
||||
@ -296,30 +282,27 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
|
||||
@Deprecated
|
||||
public void setDataView(Content dataSource, long offset, boolean reset) {
|
||||
if (reset) {
|
||||
resetComponent();
|
||||
return;
|
||||
}
|
||||
setDataView(dataSource, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the DataView (The tabbed panel)
|
||||
*
|
||||
* @param dataSource the content that want to be shown
|
||||
* @param offset the starting offset
|
||||
* @param page Page to display (1-based counting)
|
||||
*/
|
||||
private void setDataView(Content dataSource, long offset) {
|
||||
if (dataSource == null) {
|
||||
private void setDataView(int page) {
|
||||
if (this.dataSource == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (page == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentPage = page;
|
||||
long offset = (currentPage - 1) * pageLength;
|
||||
|
||||
|
||||
// change the cursor to "waiting cursor" for this operation
|
||||
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
|
||||
this.dataSource = dataSource;
|
||||
String errorText = null;
|
||||
|
||||
int bytesRead = 0;
|
||||
@ -327,7 +310,7 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
|
||||
try {
|
||||
bytesRead = dataSource.read(data, offset, pageLength); // read the data
|
||||
} catch (TskException ex) {
|
||||
errorText = "(offset " + currentOffset + "-" + (currentOffset + pageLength)
|
||||
errorText = "(offset " + offset + "-" + (offset + pageLength)
|
||||
+ " could not be read)";
|
||||
logger.log(Level.WARNING, "Error while trying to show the hex content.", ex);
|
||||
}
|
||||
@ -335,27 +318,26 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
|
||||
|
||||
// set the data on the bottom and show it
|
||||
if (bytesRead <= 0) {
|
||||
errorText = "(offset " + currentOffset + "-" + (currentOffset + pageLength)
|
||||
errorText = "(offset " + offset + "-" + (offset + pageLength)
|
||||
+ " could not be read)";
|
||||
}
|
||||
|
||||
|
||||
// disable or enable the next button
|
||||
if ((errorText != null) && (offset + pageLength < dataSource.getSize())) {
|
||||
if ((errorText == null) && (currentPage < totalPages)) {
|
||||
nextPageButton.setEnabled(true);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
nextPageButton.setEnabled(false);
|
||||
}
|
||||
|
||||
if ((offset == 0) || (errorText == null)) {
|
||||
prevPageButton.setEnabled(false);
|
||||
currentPage = 1; // reset the page number
|
||||
} else {
|
||||
if ((errorText == null) && (currentPage > 1)) {
|
||||
prevPageButton.setEnabled(true);
|
||||
}
|
||||
else {
|
||||
prevPageButton.setEnabled(false);
|
||||
}
|
||||
|
||||
int totalPage = Math.round((dataSource.getSize() - 1) / pageLength) + 1;
|
||||
totalPageLabel.setText(Integer.toString(totalPage));
|
||||
|
||||
currentPageLabel.setText(Integer.toString(currentPage));
|
||||
setComponentsVisibility(true); // shows the components that not needed
|
||||
|
||||
@ -384,8 +366,15 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
|
||||
resetComponent();
|
||||
return;
|
||||
}
|
||||
|
||||
dataSource = content;
|
||||
totalPages = 0;
|
||||
if (dataSource.getSize() > 0) {
|
||||
totalPages = Math.round((dataSource.getSize() - 1) / pageLength) + 1;
|
||||
}
|
||||
totalPageLabel.setText(Integer.toString(totalPages));
|
||||
|
||||
this.setDataView(content, 0);
|
||||
this.setDataView(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -408,7 +397,6 @@ public class DataContentViewerHex extends javax.swing.JPanel implements DataCont
|
||||
public void resetComponent() {
|
||||
// clear / reset the fields
|
||||
currentPage = 1;
|
||||
currentOffset = 0;
|
||||
this.dataSource = null;
|
||||
currentPageLabel.setText("");
|
||||
totalPageLabel.setText("");
|
||||
|
@ -25,9 +25,7 @@ import java.util.Arrays;
|
||||
import java.util.logging.Level;
|
||||
import javax.imageio.ImageIO;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.openide.util.lookup.ServiceProviders;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||
@ -41,16 +39,15 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
|
||||
@ServiceProvider(service = DataContentViewer.class, position = 5)
|
||||
})
|
||||
public class DataContentViewerMedia extends javax.swing.JPanel implements DataContentViewer {
|
||||
|
||||
private String[] IMAGES; // use javafx supported
|
||||
private static final String[] VIDEOS = new String[]{".swf", ".mov", ".m4v", ".flv", ".mp4", ".3gp", ".avi", ".mpg", ".mpeg", ".wmv"};
|
||||
private static final String[] AUDIOS = new String[]{".mp3", ".wav", ".wma"};
|
||||
private static final String[] AUDIO_EXTENSIONS = new String[]{".mp3", ".wav", ".wma"};
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DataContentViewerMedia.class.getName());
|
||||
|
||||
private AbstractFile lastFile;
|
||||
//UI
|
||||
private final MediaViewVideoPanel videoPanel;
|
||||
private final String[] videoExtensions; // get them from the panel
|
||||
private String[] imageExtensions; // use javafx supported
|
||||
private final MediaViewImagePanel imagePanel;
|
||||
private boolean videoPanelInited;
|
||||
private boolean imagePanelInited;
|
||||
@ -72,6 +69,8 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
||||
videoPanelInited = videoPanel.isInited();
|
||||
imagePanelInited = imagePanel.isInited();
|
||||
|
||||
videoExtensions = videoPanel.getExtensions();
|
||||
|
||||
customizeComponents();
|
||||
logger.log(Level.INFO, "Created MediaView instance: " + this);
|
||||
}
|
||||
@ -80,12 +79,12 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
||||
//initialize supported image types
|
||||
//TODO use mime-types instead once we have support
|
||||
String[] fxSupportedImagesSuffixes = ImageIO.getReaderFileSuffixes();
|
||||
IMAGES = new String[fxSupportedImagesSuffixes.length];
|
||||
imageExtensions = new String[fxSupportedImagesSuffixes.length];
|
||||
//logger.log(Level.INFO, "Supported image formats by javafx image viewer: ");
|
||||
for (int i = 0; i < fxSupportedImagesSuffixes.length; ++i) {
|
||||
String suffix = fxSupportedImagesSuffixes[i];
|
||||
//logger.log(Level.INFO, "suffix: " + suffix);
|
||||
IMAGES[i] = "." + suffix;
|
||||
imageExtensions[i] = "." + suffix;
|
||||
}
|
||||
|
||||
add(imagePanel, IMAGE_VIEWER_LAYER);
|
||||
@ -132,11 +131,11 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
||||
|
||||
final Dimension dims = DataContentViewerMedia.this.getSize();
|
||||
|
||||
if (imagePanelInited && containsExt(file.getName(), IMAGES)) {
|
||||
if (imagePanelInited && containsExt(file.getName(), imageExtensions)) {
|
||||
imagePanel.showImageFx(file, dims);
|
||||
this.switchPanels(false);
|
||||
} else if (videoPanelInited
|
||||
&& (containsExt(file.getName(), VIDEOS) || containsExt(file.getName(), AUDIOS))) {
|
||||
&& (containsExt(file.getName(), videoExtensions) || containsExt(file.getName(), AUDIO_EXTENSIONS))) {
|
||||
videoPanel.setupVideo(file, dims);
|
||||
switchPanels(true);
|
||||
}
|
||||
@ -182,8 +181,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
||||
|
||||
@Override
|
||||
public void resetComponent() {
|
||||
// No need to reset the video panel. It resets itself when a node is
|
||||
// set.
|
||||
videoPanel.reset();
|
||||
lastFile = null;
|
||||
}
|
||||
|
||||
@ -203,13 +201,13 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
||||
}
|
||||
|
||||
String name = file.getName().toLowerCase();
|
||||
if (imagePanelInited && containsExt(name, IMAGES)) {
|
||||
if (imagePanelInited && containsExt(name, imageExtensions)) {
|
||||
return true;
|
||||
} //for gstreamer formats, check if initialized first, then
|
||||
//support audio formats, and video formats
|
||||
else if (videoPanelInited && videoPanel.isInited()
|
||||
&& (containsExt(name, AUDIOS)
|
||||
|| (containsExt(name, VIDEOS)))) {
|
||||
&& (containsExt(name, AUDIO_EXTENSIONS)
|
||||
|| (containsExt(name, videoExtensions)))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -227,7 +225,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
||||
String name = file.getName().toLowerCase();
|
||||
|
||||
boolean deleted = file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC);
|
||||
if (containsExt(name, VIDEOS) && deleted) {
|
||||
if (containsExt(name, videoExtensions) && deleted) {
|
||||
return 0;
|
||||
} else {
|
||||
return 7;
|
||||
|
@ -194,7 +194,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
// as DataResultViewer service providers when DataResultViewers are updated
|
||||
// to better handle the ExplorerManager sharing implemented to support actions that operate on
|
||||
// multiple selected nodes.
|
||||
addDataResultViewer(new DataResultViewerTable(this.explorerManager));
|
||||
addDataResultViewer(new DataResultViewerTable(this.explorerManager));
|
||||
addDataResultViewer(new DataResultViewerThumbnail(this.explorerManager));
|
||||
|
||||
// Find all DataResultViewer service providers and add them to the tabbed pane.
|
||||
@ -305,9 +305,8 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
int childrenCount = selectedNode.getChildren().getNodesCount();
|
||||
this.numberMatchLabel.setText(Integer.toString(childrenCount));
|
||||
}
|
||||
|
||||
this.numberMatchLabel.setVisible(true);
|
||||
this.numberMatchLabel.setVisible(true);
|
||||
|
||||
|
||||
resetTabs(selectedNode);
|
||||
|
||||
@ -331,6 +330,28 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
}
|
||||
++drvC;
|
||||
}
|
||||
|
||||
// if the current tab is no longer enabled, then find one that is
|
||||
boolean hasViewerEnabled = true;
|
||||
int currentActiveTab = this.dataResultTabbedPanel.getSelectedIndex();
|
||||
if ((currentActiveTab == -1) || (dataResultTabbedPanel.isEnabledAt(currentActiveTab) == false)) {
|
||||
hasViewerEnabled = false;
|
||||
for (int i = 0; i < dataResultTabbedPanel.getTabCount(); i++) {
|
||||
if (dataResultTabbedPanel.isEnabledAt(i)) {
|
||||
currentActiveTab = i;
|
||||
hasViewerEnabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasViewerEnabled) {
|
||||
dataResultTabbedPanel.setSelectedIndex(currentActiveTab);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasViewerEnabled) {
|
||||
viewers.get(currentActiveTab).setNode(selectedNode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -387,6 +408,10 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
}
|
||||
|
||||
/**
|
||||
* why does this take a Node as parameter and then ignore it?
|
||||
*
|
||||
*
|
||||
*
|
||||
* Resets the tabs based on the selected Node. If the selected node is null
|
||||
* or not supported, disable that tab as well.
|
||||
*
|
||||
|
@ -86,7 +86,6 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
ov.setAllowedDragActions(DnDConstants.ACTION_NONE);
|
||||
ov.setAllowedDropActions(DnDConstants.ACTION_NONE);
|
||||
|
||||
// only allow one item to be selected at a time
|
||||
ov.getOutline().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||
|
||||
// don't show the root node
|
||||
|
@ -85,7 +85,6 @@ public final class DataResultViewerThumbnail extends AbstractDataResultViewer {
|
||||
private void initialize() {
|
||||
initComponents();
|
||||
|
||||
// only allow one item to be selected at a time
|
||||
((IconView) thumbnailScrollPanel).setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||
|
||||
curPage = -1;
|
||||
|
@ -80,6 +80,7 @@ import org.sleuthkit.autopsy.core.Installer;
|
||||
})
|
||||
public class FXVideoPanel extends MediaViewVideoPanel {
|
||||
|
||||
private static final String[] EXTENSIONS = new String[]{".swf", ".mov", ".m4v", ".flv", ".mp4", ".3gp", ".avi", ".mpg", ".mpeg", ".wmv"};
|
||||
private static final Logger logger = Logger.getLogger(MediaViewVideoPanel.class.getName());
|
||||
private boolean fxInited = false;
|
||||
// FX Components
|
||||
@ -794,4 +795,9 @@ public class FXVideoPanel extends MediaViewVideoPanel {
|
||||
// return frames;
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
public String[] getExtensions() {
|
||||
return EXTENSIONS;
|
||||
}
|
||||
}
|
||||
|
@ -67,6 +67,8 @@ import org.sleuthkit.datamodel.TskData;
|
||||
})
|
||||
public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
|
||||
private static final String[] EXTENSIONS = new String[]{".mov", ".m4v", ".flv", ".mp4", ".3gp", ".avi", ".mpg", ".mpeg", ".wmv"};
|
||||
|
||||
private static final Logger logger = Logger.getLogger(GstVideoPanel.class.getName());
|
||||
private boolean gstInited;
|
||||
private static final long MIN_FRAME_INTERVAL_MILLIS = 500;
|
||||
@ -179,6 +181,7 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
|
||||
@Override
|
||||
void setupVideo(final AbstractFile file, final Dimension dims) {
|
||||
reset();
|
||||
infoLabel.setText("");
|
||||
currentFile = file;
|
||||
final boolean deleted = file.isDirNameFlagSet(TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC);
|
||||
@ -437,7 +440,7 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">
|
||||
private void initComponents() {
|
||||
|
||||
videoPanel = new javax.swing.JPanel();
|
||||
@ -769,4 +772,9 @@ public class GstVideoPanel extends MediaViewVideoPanel {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getExtensions() {
|
||||
return EXTENSIONS;
|
||||
}
|
||||
}
|
||||
|
@ -115,4 +115,9 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture
|
||||
* @param dims dimension of the parent window
|
||||
*/
|
||||
abstract void setupVideo(final AbstractFile file, final Dimension dims);
|
||||
|
||||
/**
|
||||
* Return the extensions supported by this video panel.
|
||||
*/
|
||||
abstract public String[] getExtensions();
|
||||
}
|
||||
|
@ -122,8 +122,8 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(SearchFilters sf) {
|
||||
return new SearchFiltersNode(sf.getSleuthkitCase(), null);
|
||||
public AbstractNode visit(FileTypeExtensionFilters sf) {
|
||||
return new FileTypesNode(sf.getSleuthkitCase(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -57,7 +57,7 @@ public abstract class AbstractContentNode<T extends Content> extends ContentNode
|
||||
* Return the content data associated with this node
|
||||
* @return the content object wrapped by this node
|
||||
*/
|
||||
public Content getContent() {
|
||||
public T getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
|
@ -26,13 +26,13 @@ public interface AutopsyItemVisitor<T> {
|
||||
|
||||
T visit(ExtractedContent ec);
|
||||
|
||||
T visit(SearchFilters sf);
|
||||
T visit(FileTypeExtensionFilters sf);
|
||||
|
||||
T visit(SearchFilters.FileSearchFilter fsf);
|
||||
T visit(FileTypeExtensionFilters.RootFilter fsf);
|
||||
|
||||
T visit(SearchFilters.DocumentFilter df);
|
||||
T visit(FileTypeExtensionFilters.DocumentFilter df);
|
||||
|
||||
T visit(SearchFilters.ExecutableFilter ef);
|
||||
T visit(FileTypeExtensionFilters.ExecutableFilter ef);
|
||||
|
||||
T visit(RecentFiles rf);
|
||||
|
||||
@ -70,22 +70,22 @@ public interface AutopsyItemVisitor<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(SearchFilters sf) {
|
||||
public T visit(FileTypeExtensionFilters sf) {
|
||||
return defaultVisit(sf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(SearchFilters.FileSearchFilter fsf) {
|
||||
public T visit(FileTypeExtensionFilters.RootFilter fsf) {
|
||||
return defaultVisit(fsf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(SearchFilters.DocumentFilter df) {
|
||||
public T visit(FileTypeExtensionFilters.DocumentFilter df) {
|
||||
return defaultVisit(df);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(SearchFilters.ExecutableFilter ef) {
|
||||
public T visit(FileTypeExtensionFilters.ExecutableFilter ef) {
|
||||
return defaultVisit(ef);
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
|
||||
T visit(ExtractedContentNode ecn);
|
||||
|
||||
T visit(FileSearchFilterNode fsfn);
|
||||
T visit(FileTypeNode fsfn);
|
||||
|
||||
T visit(DeletedContentNode dcn);
|
||||
|
||||
@ -63,7 +63,7 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
|
||||
T visit(FileSizeNode fsn);
|
||||
|
||||
T visit(SearchFiltersNode sfn);
|
||||
T visit(FileTypesNode sfn);
|
||||
|
||||
T visit(RecentFilesNode rfn);
|
||||
|
||||
@ -155,7 +155,7 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(FileSearchFilterNode fsfn) {
|
||||
public T visit(FileTypeNode fsfn) {
|
||||
return defaultVisit(fsfn);
|
||||
}
|
||||
|
||||
@ -180,7 +180,7 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(SearchFiltersNode sfn) {
|
||||
public T visit(FileTypesNode sfn) {
|
||||
return defaultVisit(sfn);
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.datamodel.ContentVisitor;
|
||||
import org.sleuthkit.datamodel.DerivedFile;
|
||||
@ -37,16 +38,16 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* Children factory for the file by type view in dir tree
|
||||
* Children factory for a specific file type - does the database query.
|
||||
*/
|
||||
class FileSearchFilterChildren extends ChildFactory<Content> {
|
||||
class FileTypeChildren extends ChildFactory<Content> {
|
||||
|
||||
private SleuthkitCase skCase;
|
||||
private SearchFilters.SearchFilterInterface filter;
|
||||
private static final Logger logger = Logger.getLogger(FileSearchFilterChildren.class.getName());
|
||||
// private final static int MAX_OBJECTS = 2000;
|
||||
private FileTypeExtensionFilters.SearchFilterInterface filter;
|
||||
private static final Logger logger = Logger.getLogger(FileTypeChildren.class.getName());
|
||||
//private final static int MAX_OBJECTS = 2000;
|
||||
|
||||
public FileSearchFilterChildren(SearchFilters.SearchFilterInterface filter, SleuthkitCase skCase) {
|
||||
public FileTypeChildren(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase) {
|
||||
this.filter = filter;
|
||||
this.skCase = skCase;
|
||||
}
|
||||
@ -59,7 +60,7 @@ class FileSearchFilterChildren extends ChildFactory<Content> {
|
||||
|
||||
private String createQuery(){
|
||||
String query = "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
|
||||
+ " AND (known IS NULL OR known != 1) AND (0";
|
||||
+ " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ") AND (0";
|
||||
for(String s : filter.getFilter()){
|
||||
query += " OR name LIKE '%" + s + "'";
|
||||
}
|
||||
@ -69,8 +70,8 @@ class FileSearchFilterChildren extends ChildFactory<Content> {
|
||||
}
|
||||
|
||||
|
||||
private List<? extends Content> runQuery(){
|
||||
List<? extends Content> list = new ArrayList<>();
|
||||
private List<AbstractFile> runQuery(){
|
||||
List<AbstractFile> list = new ArrayList<>();
|
||||
try {
|
||||
list = skCase.findAllFilesWhere(createQuery());
|
||||
} catch (TskCoreException ex) {
|
@ -25,11 +25,12 @@ import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
/**
|
||||
* Filters database results by file extension.
|
||||
*/
|
||||
public class SearchFilters implements AutopsyVisitableItem {
|
||||
public class FileTypeExtensionFilters implements AutopsyVisitableItem {
|
||||
|
||||
private SleuthkitCase skCase;
|
||||
|
||||
public enum FileSearchFilter implements AutopsyVisitableItem,SearchFilterInterface {
|
||||
// root node filters
|
||||
public enum RootFilter implements AutopsyVisitableItem,SearchFilterInterface {
|
||||
TSK_IMAGE_FILTER(0, "TSK_IMAGE_FILTER", "Images", FileTypeExtensions.getImageExtensions()),
|
||||
TSK_VIDEO_FILTER(1, "TSK_VIDEO_FILTER", "Videos", FileTypeExtensions.getVideoExtensions()),
|
||||
TSK_AUDIO_FILTER(2, "TSK_AUDIO_FILTER", "Audio", FileTypeExtensions.getAudioExtensions()),
|
||||
@ -42,7 +43,7 @@ public class SearchFilters implements AutopsyVisitableItem {
|
||||
private String displayName;
|
||||
private List<String> filter;
|
||||
|
||||
private FileSearchFilter(int id, String name, String displayName, List<String> filter){
|
||||
private RootFilter(int id, String name, String displayName, List<String> filter){
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.displayName = displayName;
|
||||
@ -75,6 +76,7 @@ public class SearchFilters implements AutopsyVisitableItem {
|
||||
}
|
||||
}
|
||||
|
||||
// document sub-node filters
|
||||
public enum DocumentFilter implements AutopsyVisitableItem,SearchFilterInterface {
|
||||
AUT_DOC_HTML(0, "AUT_DOC_HTML", "HTML", Arrays.asList(".htm", ".html")),
|
||||
AUT_DOC_OFFICE(1, "AUT_DOC_OFFICE", "Office", Arrays.asList(".doc", ".docx",
|
||||
@ -122,6 +124,7 @@ public class SearchFilters implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
|
||||
// executable sub-node filters
|
||||
public enum ExecutableFilter implements AutopsyVisitableItem,SearchFilterInterface {
|
||||
ExecutableFilter_EXE(0, "ExecutableFilter_EXE", ".exe", Arrays.asList(".exe")),
|
||||
ExecutableFilter_DLL(1, "ExecutableFilter_DLL", ".dll", Arrays.asList(".dll")),
|
||||
@ -167,7 +170,7 @@ public class SearchFilters implements AutopsyVisitableItem {
|
||||
}
|
||||
}
|
||||
|
||||
public SearchFilters(SleuthkitCase skCase){
|
||||
public FileTypeExtensionFilters(SleuthkitCase skCase){
|
||||
this.skCase = skCase;
|
||||
}
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2013 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.datamodel;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
@ -24,15 +24,15 @@ import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
|
||||
/**
|
||||
* Node for the file search filter
|
||||
* Node for a specific file type / extension
|
||||
*/
|
||||
public class FileSearchFilterNode extends DisplayableItemNode {
|
||||
public class FileTypeNode extends DisplayableItemNode {
|
||||
|
||||
SearchFilters.SearchFilterInterface filter;
|
||||
FileTypeExtensionFilters.SearchFilterInterface filter;
|
||||
SleuthkitCase skCase;
|
||||
|
||||
FileSearchFilterNode(SearchFilters.SearchFilterInterface filter, SleuthkitCase skCase) {
|
||||
super(Children.create(new FileSearchFilterChildren(filter, skCase), true), Lookups.singleton(filter.getDisplayName()));
|
||||
FileTypeNode(FileTypeExtensionFilters.SearchFilterInterface filter, SleuthkitCase skCase) {
|
||||
super(Children.create(new FileTypeChildren(filter, skCase), true), Lookups.singleton(filter.getDisplayName()));
|
||||
|
||||
this.filter = filter;
|
||||
this.skCase = skCase;
|
||||
@ -40,7 +40,7 @@ public class FileSearchFilterNode extends DisplayableItemNode {
|
||||
super.setName(filter.getName());
|
||||
|
||||
//get count of children without preloading all children nodes
|
||||
final long count = new FileSearchFilterChildren(filter, skCase).calculateItems();
|
||||
final long count = new FileTypeChildren(filter, skCase).calculateItems();
|
||||
//final long count = getChildren().getNodesCount(true);
|
||||
super.setDisplayName(filter.getDisplayName() + " (" + count + ")");
|
||||
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 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.datamodel;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypeExtensionFilters.RootFilter;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class FileTypesChildren extends ChildFactory<FileTypeExtensionFilters.SearchFilterInterface> {
|
||||
|
||||
private SleuthkitCase skCase;
|
||||
private FileTypeExtensionFilters.RootFilter filter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param skCase
|
||||
* @param filter Is null for root node
|
||||
*/
|
||||
public FileTypesChildren(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter) {
|
||||
this.skCase = skCase;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<FileTypeExtensionFilters.SearchFilterInterface> list) {
|
||||
// root node
|
||||
if (filter == null) {
|
||||
list.addAll(Arrays.asList(RootFilter.values()));
|
||||
}
|
||||
// document and executable has another level of nodes
|
||||
else if (filter.equals(RootFilter.TSK_DOCUMENT_FILTER) ){
|
||||
list.addAll(Arrays.asList(FileTypeExtensionFilters.DocumentFilter.values()));
|
||||
}
|
||||
else if (filter.equals(RootFilter.TSK_EXECUTABLE_FILTER) ){
|
||||
list.addAll(Arrays.asList(FileTypeExtensionFilters.ExecutableFilter.values()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(FileTypeExtensionFilters.SearchFilterInterface key){
|
||||
// make new nodes for the sub-nodes
|
||||
if(key.getName().equals(FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER.getName())){
|
||||
return new FileTypesNode(skCase, FileTypeExtensionFilters.RootFilter.TSK_DOCUMENT_FILTER);
|
||||
}
|
||||
else if(key.getName().equals(FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER.getName())){
|
||||
return new FileTypesNode(skCase, FileTypeExtensionFilters.RootFilter.TSK_EXECUTABLE_FILTER);
|
||||
}
|
||||
else {
|
||||
return new FileTypeNode(key, skCase);
|
||||
}
|
||||
}
|
||||
}
|
@ -24,19 +24,27 @@ import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
|
||||
/**
|
||||
* Node for search filter
|
||||
* Node for extension/file type filter view
|
||||
*/
|
||||
public class SearchFiltersNode extends DisplayableItemNode {
|
||||
public class FileTypesNode extends DisplayableItemNode {
|
||||
|
||||
private static final String FNAME = "File Types";
|
||||
private SleuthkitCase skCase;
|
||||
|
||||
SearchFiltersNode(SleuthkitCase skCase, SearchFilters.FileSearchFilter filter) {
|
||||
super(Children.create(new SearchFiltersChildren(skCase, filter), true), Lookups.singleton(filter == null ? FNAME : filter.getName()));
|
||||
/**
|
||||
*
|
||||
* @param skCase
|
||||
* @param filter null to display root node of file type tree, pass in something to provide a sub-node.
|
||||
*/
|
||||
FileTypesNode(SleuthkitCase skCase, FileTypeExtensionFilters.RootFilter filter) {
|
||||
super(Children.create(new FileTypesChildren(skCase, filter), true), Lookups.singleton(filter == null ? FNAME : filter.getName()));
|
||||
// root node of tree
|
||||
if (filter == null) {
|
||||
super.setName(FNAME);
|
||||
super.setDisplayName(FNAME);
|
||||
} else {
|
||||
}
|
||||
// sub-node in file tree (i.e. documents, exec, etc.)
|
||||
else {
|
||||
super.setName(filter.getName());
|
||||
super.setDisplayName(filter.getDisplayName());
|
||||
}
|
@ -30,7 +30,7 @@ public class NodeProperty extends PropertySupport.ReadOnly {
|
||||
private Object value;
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
NodeProperty(String name, String displayName, String desc, Object value) {
|
||||
public NodeProperty(String name, String displayName, String desc, Object value) {
|
||||
super(name, value.getClass(), displayName, desc);
|
||||
setValue("suppressCustomEditor", Boolean.TRUE); // remove the "..." (editing) button
|
||||
this.value = value;
|
||||
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 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.datamodel;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.datamodel.SearchFilters.FileSearchFilter;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class SearchFiltersChildren extends ChildFactory<SearchFilters.SearchFilterInterface> {
|
||||
|
||||
private SleuthkitCase skCase;
|
||||
private SearchFilters.FileSearchFilter filter;
|
||||
|
||||
public SearchFiltersChildren(SleuthkitCase skCase, SearchFilters.FileSearchFilter filter) {
|
||||
this.skCase = skCase;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<SearchFilters.SearchFilterInterface> list) {
|
||||
if (filter == null) {
|
||||
list.addAll(Arrays.asList(FileSearchFilter.values()));
|
||||
}
|
||||
else if (filter.equals(FileSearchFilter.TSK_DOCUMENT_FILTER) ){
|
||||
list.addAll(Arrays.asList(SearchFilters.DocumentFilter.values()));
|
||||
}
|
||||
else if (filter.equals(FileSearchFilter.TSK_EXECUTABLE_FILTER) ){
|
||||
list.addAll(Arrays.asList(SearchFilters.ExecutableFilter.values()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(SearchFilters.SearchFilterInterface key){
|
||||
if(key.getName().equals(SearchFilters.FileSearchFilter.TSK_DOCUMENT_FILTER.getName())){
|
||||
return new SearchFiltersNode(skCase, SearchFilters.FileSearchFilter.TSK_DOCUMENT_FILTER);
|
||||
}
|
||||
else if(key.getName().equals(SearchFilters.FileSearchFilter.TSK_EXECUTABLE_FILTER.getName())){
|
||||
return new SearchFiltersNode(skCase, SearchFilters.FileSearchFilter.TSK_EXECUTABLE_FILTER);
|
||||
}
|
||||
else {
|
||||
return new FileSearchFilterNode(key, skCase);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -34,7 +34,7 @@ public class ViewsNode extends DisplayableItemNode {
|
||||
|
||||
public ViewsNode(SleuthkitCase sleuthkitCase) {
|
||||
super(new RootContentChildren(Arrays.asList(
|
||||
new SearchFilters(sleuthkitCase),
|
||||
new FileTypeExtensionFilters(sleuthkitCase),
|
||||
new RecentFiles(sleuthkitCase),
|
||||
new DeletedContent(sleuthkitCase),
|
||||
new FileSize(sleuthkitCase)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -219,10 +219,16 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
private void backButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backButtonActionPerformed
|
||||
// change the cursor to "waiting cursor" for this operation
|
||||
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
// update the back and forward List
|
||||
|
||||
// the end is the current place,
|
||||
String[] currentNodePath = backList.pollLast();
|
||||
String[] newCurrentNodePath = backList.peekLast();
|
||||
forwardList.addLast(currentNodePath);
|
||||
forwardButton.setEnabled(true);
|
||||
|
||||
/* We peek instead of poll because we use its existence
|
||||
* in the list later on so that we do not reset the forward list
|
||||
* after the selection occurs. */
|
||||
String[] newCurrentNodePath = backList.peekLast();
|
||||
|
||||
// enable / disable the back and forward button
|
||||
if (backList.size() > 1) {
|
||||
@ -230,39 +236,31 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
} else {
|
||||
backButton.setEnabled(false);
|
||||
}
|
||||
this.forwardButton.setEnabled(true);
|
||||
|
||||
|
||||
// update the selection on directory tree
|
||||
setSelectedNode(newCurrentNodePath, null);
|
||||
|
||||
|
||||
this.setCursor(null);
|
||||
|
||||
}//GEN-LAST:event_backButtonActionPerformed
|
||||
|
||||
private void forwardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_forwardButtonActionPerformed
|
||||
// change the cursor to "waiting cursor" for this operation
|
||||
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||
// try {
|
||||
// update the back and forward List
|
||||
//int newCurrentIndex = forwardList.size() - 1;
|
||||
String[] newCurrentNodePath = forwardList.pollLast();
|
||||
//forwardList.remove(newCurrentIndex);
|
||||
backList.addLast(newCurrentNodePath);
|
||||
|
||||
// enable / disable the back and forward button
|
||||
String[] newCurrentNodePath = forwardList.pollLast();
|
||||
if (!forwardList.isEmpty()) {
|
||||
forwardButton.setEnabled(true);
|
||||
} else {
|
||||
forwardButton.setEnabled(false);
|
||||
}
|
||||
this.backButton.setEnabled(true);
|
||||
|
||||
|
||||
backList.addLast(newCurrentNodePath);
|
||||
backButton.setEnabled(true);
|
||||
|
||||
// update the selection on directory tree
|
||||
setSelectedNode(newCurrentNodePath, null);
|
||||
|
||||
this.setCursor(null);
|
||||
|
||||
}//GEN-LAST:event_forwardButtonActionPerformed
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton backButton;
|
||||
@ -337,7 +335,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
((BeanTreeView) this.jScrollPane1).setRootVisible(false); // hide the root
|
||||
} else {
|
||||
// if there's at least one image, load the image and open the top component
|
||||
List<Object> items = new ArrayList<Object>();
|
||||
List<Object> items = new ArrayList<>();
|
||||
final SleuthkitCase tskCase = currentCase.getSleuthkitCase();
|
||||
items.add(new DataSources(tskCase));
|
||||
items.add(new Views(tskCase));
|
||||
@ -375,7 +373,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
((BeanTreeView) this.jScrollPane1).setRootVisible(false); // hide the root
|
||||
|
||||
// Reset the forward and back lists because we're resetting the root context
|
||||
resetHistoryListAndButtons();
|
||||
resetHistory();
|
||||
|
||||
Children childNodes = em.getRootContext().getChildren();
|
||||
TreeView tree = getTree();
|
||||
@ -533,7 +531,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
|
||||
// case opened
|
||||
if (newValue != null) {
|
||||
resetHistoryListAndButtons();
|
||||
resetHistory();
|
||||
}
|
||||
} // if the image is added to the case
|
||||
else if (changed.equals(Case.CASE_ADD_DATA_SOURCE)) {
|
||||
@ -671,31 +669,53 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
});
|
||||
|
||||
// update the back and forward list
|
||||
Node[] selectedNode = em.getSelectedNodes();
|
||||
if (selectedNode.length > 0) {
|
||||
Node selectedContext = selectedNode[0];
|
||||
|
||||
final String[] selectedPath = NodeOp.createPath(selectedContext, em.getRootContext());
|
||||
String[] currentLast = backList.peekLast();
|
||||
String lastNodeName = null;
|
||||
if (currentLast != null) {
|
||||
lastNodeName = currentLast[currentLast.length - 1];
|
||||
}
|
||||
String selectedNodeName = selectedContext.getName();
|
||||
if (currentLast == null || !selectedNodeName.equals(lastNodeName)) {
|
||||
//add to the list if the last if not the same as current
|
||||
|
||||
backList.addLast(selectedPath); // add the node to the "backList"
|
||||
if (backList.size() > 1) {
|
||||
backButton.setEnabled(true);
|
||||
} else {
|
||||
backButton.setEnabled(false);
|
||||
}
|
||||
|
||||
forwardList.clear(); // clear the "forwardList"
|
||||
forwardButton.setEnabled(false); // disable the forward Button
|
||||
}
|
||||
updateHistory(em.getSelectedNodes());
|
||||
}
|
||||
|
||||
private void updateHistory(Node[] selectedNodes) {
|
||||
if (selectedNodes.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Node selectedNode = selectedNodes[0];
|
||||
String selectedNodeName = selectedNode.getName();
|
||||
|
||||
/* get the previous entry to make sure we don't duplicate it.
|
||||
* Motivation for this is also that if we used the back button,
|
||||
* then we already added the 'current' node to 'back' and we will
|
||||
* detect that and not reset the forward list.
|
||||
*/
|
||||
String[] currentLast = backList.peekLast();
|
||||
String lastNodeName = null;
|
||||
if (currentLast != null) {
|
||||
lastNodeName = currentLast[currentLast.length - 1];
|
||||
}
|
||||
|
||||
if (currentLast == null || !selectedNodeName.equals(lastNodeName)) {
|
||||
//add to the list if the last if not the same as current
|
||||
final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
|
||||
backList.addLast(selectedPath); // add the node to the "backList"
|
||||
if (backList.size() > 1) {
|
||||
backButton.setEnabled(true);
|
||||
} else {
|
||||
backButton.setEnabled(false);
|
||||
}
|
||||
|
||||
forwardList.clear(); // clear the "forwardList"
|
||||
forwardButton.setEnabled(false); // disable the forward Button
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the back and forward list, and also disable the back and forward
|
||||
* buttons.
|
||||
*/
|
||||
private void resetHistory() {
|
||||
// clear the back and forward list
|
||||
backList.clear();
|
||||
forwardList.clear();
|
||||
backButton.setEnabled(false);
|
||||
forwardButton.setEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -708,17 +728,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
pcs.removePropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the back and forward list, and also disable the back and forward
|
||||
* buttons.
|
||||
*/
|
||||
private void resetHistoryListAndButtons() {
|
||||
// clear the back and forward list
|
||||
backList.clear();
|
||||
forwardList.clear();
|
||||
backButton.setEnabled(false);
|
||||
forwardButton.setEnabled(false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the tree on this DirectoryTreeTopComponent.
|
||||
@ -845,19 +855,17 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
||||
|
||||
if (path.length > 0 && (rootNodeName == null || path[0].equals(rootNodeName))) {
|
||||
try {
|
||||
final TreeView tree = getTree();
|
||||
Node newSelection = NodeOp.findPath(em.getRootContext(), path);
|
||||
//resetHistoryListAndButtons();
|
||||
|
||||
if (newSelection != null) {
|
||||
if (rootNodeName != null) {
|
||||
//called from tree auto refresh context
|
||||
//remove last from backlist, because auto select will result in duplication
|
||||
backList.pollLast();
|
||||
}
|
||||
//select
|
||||
//tree.expandNode(newSelection);
|
||||
em.setExploredContextAndSelection(newSelection, new Node[]{newSelection});
|
||||
}
|
||||
|
||||
// We need to set the selection, which will refresh dataresult and get rid of the oob exception
|
||||
} catch (NodeNotFoundException ex) {
|
||||
logger.log(Level.WARNING, "Node not found", ex);
|
||||
|
@ -164,7 +164,10 @@ public final class ExtractUnallocAction extends AbstractAction {
|
||||
private List<LayoutFile> getUnallocFiles(Content c) {
|
||||
UnallocVisitor uv = new UnallocVisitor();
|
||||
try {
|
||||
return c.getChildren().get(0).accept(uv); //Launching it on the root directory
|
||||
List<Content> unallocFiles = c.getChildren();
|
||||
if (null != unallocFiles && unallocFiles.isEmpty() == false) {
|
||||
return unallocFiles.get(0).accept(uv); //Launching it on the root directory
|
||||
}
|
||||
} catch (TskCoreException tce) {
|
||||
logger.log(Level.WARNING, "Couldn't get a list of Unallocated Files, failed at sending out the visitor ", tce);
|
||||
}
|
||||
|
@ -16,96 +16,108 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
package org.sleuthkit.autopsy.ingest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.JPanel;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||
import org.sleuthkit.autopsy.ingest.IngestDialogPanel;
|
||||
import static org.sleuthkit.autopsy.ingest.IngestDialogPanel.DISABLED_MOD;
|
||||
import static org.sleuthkit.autopsy.ingest.IngestDialogPanel.PARSE_UNALLOC;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.ingest.IngestModuleAbstract;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
|
||||
@ServiceProvider(service = IngestConfigurator.class)
|
||||
public class GeneralIngestConfigurator implements IngestConfigurator {
|
||||
public class GeneralIngestConfigurator implements IngestConfigurator {
|
||||
|
||||
public static final String ENABLED_INGEST_MODULES_KEY = "Enabled_Ingest_Modules";
|
||||
public static final String PARSE_UNALLOC_SPACE_KEY = "Process_Unallocated_Space";
|
||||
private List<Content> contentToIngest;
|
||||
private IngestManager manager;
|
||||
private IngestDialogPanel ingestDialogPanel;
|
||||
private String moduleContext;
|
||||
|
||||
public GeneralIngestConfigurator() {
|
||||
this.moduleContext = IngestManager.MODULE_PROPERTIES; // Hard-code this for now.
|
||||
this.moduleContext = IngestManager.MODULE_PROPERTIES;
|
||||
ingestDialogPanel = new IngestDialogPanel();
|
||||
ingestDialogPanel.setContext(moduleContext);
|
||||
manager = IngestManager.getDefault();
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContext(String context) {
|
||||
public List<String> setContext(String context) {
|
||||
moduleContext = context;
|
||||
ingestDialogPanel.setContext(moduleContext);
|
||||
reload();
|
||||
return loadSettingsForContext();
|
||||
}
|
||||
|
||||
private List<String> loadSettingsForContext() {
|
||||
List<String> messages = new ArrayList<>();
|
||||
|
||||
// If there is no enabled ingest modules setting for this user, default to enabling all
|
||||
// of the ingest modules the IngestManager has loaded.
|
||||
if (ModuleSettings.settingExists(moduleContext, ENABLED_INGEST_MODULES_KEY) == false) {
|
||||
String defaultSetting = moduleListToCsv(IngestManager.getDefault().enumerateAllModules());
|
||||
ModuleSettings.setConfigSetting(moduleContext, ENABLED_INGEST_MODULES_KEY, defaultSetting);
|
||||
}
|
||||
|
||||
// Get the enabled ingest modules setting, check for missing modules, and pass the setting to
|
||||
// the UI component.
|
||||
List<IngestModuleAbstract> allModules = IngestManager.getDefault().enumerateAllModules();
|
||||
String[] enabledModuleNames = ModuleSettings.getConfigSetting(moduleContext, ENABLED_INGEST_MODULES_KEY).split(", ");
|
||||
List<IngestModuleAbstract> enabledModules = new ArrayList<>();
|
||||
for (String moduleName : enabledModuleNames) {
|
||||
IngestModuleAbstract moduleFound = null;
|
||||
for (IngestModuleAbstract module : allModules) {
|
||||
if (moduleName.equals(module.getName())) {
|
||||
moduleFound = module;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (moduleFound != null) {
|
||||
enabledModules.add(moduleFound);
|
||||
}
|
||||
else {
|
||||
messages.add("Unable to load " + moduleName + " module");
|
||||
}
|
||||
}
|
||||
ingestDialogPanel.setEnabledIngestModules(enabledModules);
|
||||
|
||||
// If there is no process unallocated space flag setting, default it to false.
|
||||
if (ModuleSettings.settingExists(moduleContext, PARSE_UNALLOC_SPACE_KEY) == false) {
|
||||
ModuleSettings.setConfigSetting(moduleContext, PARSE_UNALLOC_SPACE_KEY, "false");
|
||||
}
|
||||
|
||||
// Get the process unallocated space flag setting and pass it to the UI component.
|
||||
boolean processUnalloc = Boolean.parseBoolean(ModuleSettings.getConfigSetting(moduleContext, PARSE_UNALLOC_SPACE_KEY));
|
||||
ingestDialogPanel.setProcessUnallocSpaceEnabled(processUnalloc);
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getIngestConfigPanel() {
|
||||
// Note that this panel allows for selecting modules for the ingest process,
|
||||
// specifying the process unallocated space flag, and also specifying settings
|
||||
// for a selected ingest module.
|
||||
return ingestDialogPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPanel getIngestConfigPanel() {
|
||||
return ingestDialogPanel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContent(List<Content> inputContent) {
|
||||
this.contentToIngest = inputContent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
// Get the list of ingest modules selected by the user.
|
||||
List<IngestModuleAbstract> modulesToStart = ingestDialogPanel.getModulesToStart();
|
||||
public void save() {
|
||||
// Save the user's configuration of the set of enabled ingest modules.
|
||||
String enabledModulesCsvList = moduleListToCsv(ingestDialogPanel.getModulesToStart());
|
||||
ModuleSettings.setConfigSetting(moduleContext, ENABLED_INGEST_MODULES_KEY, enabledModulesCsvList);
|
||||
|
||||
// Get the user's selection of whether or not to process unallocated space.
|
||||
manager.setProcessUnallocSpace(ingestDialogPanel.processUnallocSpaceEnabled());
|
||||
|
||||
// Start the ingest.
|
||||
if (!modulesToStart.isEmpty()) {
|
||||
manager.execute(modulesToStart, contentToIngest);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
// Save the user's configuration of the currently selected module.
|
||||
// Save the user's setting for the process unallocated space flag.
|
||||
String processUnalloc = Boolean.toString(ingestDialogPanel.processUnallocSpaceEnabled());
|
||||
ModuleSettings.setConfigSetting(moduleContext, PARSE_UNALLOC_SPACE_KEY, processUnalloc);
|
||||
|
||||
// Save the user's configuration of the currently selected ingest module.
|
||||
IngestModuleAbstract currentModule = ingestDialogPanel.getCurrentIngestModule();
|
||||
if (currentModule != null && currentModule.hasSimpleConfiguration()) {
|
||||
currentModule.saveSimpleConfiguration();
|
||||
}
|
||||
|
||||
// Create a list of the modules the user wants to be disabled.
|
||||
List<IngestModuleAbstract> disabledModules = IngestManager.getDefault().enumerateAllModules();
|
||||
disabledModules.removeAll(ingestDialogPanel.getModulesToStart());
|
||||
String disabledModulesCsv = moduleListToCsv(disabledModules);
|
||||
|
||||
// Save the user's general ingest configuration.
|
||||
ModuleSettings.setConfigSetting(moduleContext, DISABLED_MOD, disabledModulesCsv);
|
||||
String processUnalloc = Boolean.toString(ingestDialogPanel.processUnallocSpaceEnabled());
|
||||
ModuleSettings.setConfigSetting(moduleContext, PARSE_UNALLOC, processUnalloc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIngestRunning() {
|
||||
return manager.isIngestRunning();
|
||||
}
|
||||
|
||||
private static String moduleListToCsv(List<IngestModuleAbstract> lst) {
|
||||
if (lst == null || lst.isEmpty()) {
|
||||
return "";
|
||||
@ -121,39 +133,28 @@ public class GeneralIngestConfigurator implements IngestConfigurator {
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static List<IngestModuleAbstract> csvToModuleList(String csv) {
|
||||
List<IngestModuleAbstract> modules = new ArrayList<>();
|
||||
|
||||
if (csv == null || csv.isEmpty()) {
|
||||
return modules;
|
||||
}
|
||||
|
||||
String[] moduleNames = csv.split(", ");
|
||||
List<IngestModuleAbstract> allModules = IngestManager.getDefault().enumerateAllModules();
|
||||
for (String moduleName : moduleNames) {
|
||||
for (IngestModuleAbstract module : allModules) {
|
||||
if (moduleName.equals(module.getName())) {
|
||||
modules.add(module);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return modules;
|
||||
@Override
|
||||
public void setContent(List<Content> inputContent) {
|
||||
this.contentToIngest = inputContent;
|
||||
}
|
||||
|
||||
private void loadSettings() {
|
||||
// get the csv list of disabled modules
|
||||
String disabledModulesCsv = ModuleSettings.getConfigSetting(moduleContext, DISABLED_MOD);
|
||||
@Override
|
||||
public void start() {
|
||||
// Get the list of ingest modules selected by the user.
|
||||
List<IngestModuleAbstract> modulesToStart = ingestDialogPanel.getModulesToStart();
|
||||
|
||||
// create a list of modules from it
|
||||
List<IngestModuleAbstract> disabledModules = csvToModuleList(disabledModulesCsv);
|
||||
|
||||
// tell the ingestDialogPanel to unselect these modules
|
||||
ingestDialogPanel.setDisabledModules(disabledModules);
|
||||
|
||||
boolean processUnalloc = Boolean.parseBoolean(ModuleSettings.getConfigSetting(moduleContext, PARSE_UNALLOC));
|
||||
ingestDialogPanel.setProcessUnallocSpaceEnabled(processUnalloc);
|
||||
// Get the user's selection of whether or not to process unallocated space.
|
||||
manager.setProcessUnallocSpace(ingestDialogPanel.processUnallocSpaceEnabled());
|
||||
|
||||
if (!modulesToStart.isEmpty() && contentToIngest != null) {
|
||||
// Queue the ingest process.
|
||||
manager.execute(modulesToStart, contentToIngest);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIngestRunning() {
|
||||
return manager.isIngestRunning();
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2013 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.ingest;
|
||||
|
||||
import java.util.List;
|
||||
import javax.swing.JPanel;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
|
||||
/**
|
||||
* Instances of this class provide the following services:
|
||||
* 1. A way to save and load the ingest process configuration settings for a
|
||||
* given ingest process context.
|
||||
* 2. A UI component for configuring ingest process settings.
|
||||
* 3. A way to specify input content and start the ingest process for a
|
||||
* given ingest process context.
|
||||
*/
|
||||
// @@@ This interface needs to be re-designed. An interface for allowing the
|
||||
// authors of ingest modules to expose context sensitive module configuration
|
||||
// settings needs to be provided; there also needs to be a way for users to
|
||||
// configure the ingest process that uses those modules. These are separate
|
||||
// concerns; likewise, kicking off an ingest process for particular content in
|
||||
// a particular context is a separate concern.
|
||||
public interface IngestConfigurator {
|
||||
/**
|
||||
* Specifies the ingest process context for the purpose of choosing, saving,
|
||||
* and loading ingest process configuration settings; also determines what
|
||||
* configuration settings will be in effect if the setContent() and start()
|
||||
* methods are called to start the ingest process for some content specified
|
||||
* using the setContent() method.
|
||||
* @return A list, possibly empty, of messages describing errors that
|
||||
* occurred when loading the configuration settings.
|
||||
*/
|
||||
public List<String> setContext(String contextName);
|
||||
|
||||
/**
|
||||
* Provides a UI component for choosing ingest process configuration
|
||||
* settings for the ingest process context specified using the setContext()
|
||||
* method.
|
||||
*/
|
||||
JPanel getIngestConfigPanel();
|
||||
|
||||
/**
|
||||
* Saves the ingest process configuration settings for the ingest process
|
||||
* context specified using the setContext() method.
|
||||
*/
|
||||
void save();
|
||||
|
||||
/**
|
||||
* Sets the input content for an ingest process prior to calling start() to
|
||||
* run the process using the process configuration settings for the context
|
||||
* specified using setContext().
|
||||
*/
|
||||
void setContent(List<Content> inputContent);
|
||||
|
||||
/**
|
||||
* Starts (queues) the ingest process for the content specified using the
|
||||
* setContent() method, using the configuration settings corresponding to
|
||||
* the ingest process context specified using the setContext() method.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Returns true if any ingest process is running, false otherwise.
|
||||
* Note that the running process may or may not be the process started
|
||||
* (queued) by an invocation of the start() method.
|
||||
*/
|
||||
boolean isIngestRunning();
|
||||
}
|
@ -30,11 +30,9 @@ import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import org.openide.util.Lookup;
|
||||
import org.sleuthkit.autopsy.casemodule.GeneralIngestConfigurator;
|
||||
import org.sleuthkit.datamodel.Content;
|
||||
import org.sleuthkit.autopsy.casemodule.IngestConfigurator;
|
||||
|
||||
/**
|
||||
* Dialog box that allows ingest modules to be run on an image.
|
||||
@ -49,8 +47,14 @@ public class IngestDialog extends JDialog {
|
||||
public IngestDialog(JFrame frame, String title, boolean modal) {
|
||||
super(frame, title, modal);
|
||||
ingestConfigurator = new GeneralIngestConfigurator();
|
||||
ingestConfigurator.setContext(IngestDialog.class.getCanonicalName());
|
||||
ingestConfigurator.reload();
|
||||
List<String> messages = ingestConfigurator.setContext(IngestDialog.class.getCanonicalName());
|
||||
if (messages.isEmpty() == false) {
|
||||
StringBuilder warning = new StringBuilder();
|
||||
for (String message : messages) {
|
||||
warning.append(message).append("\n");
|
||||
}
|
||||
JOptionPane.showMessageDialog(null, warning.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public IngestDialog(){
|
||||
|
@ -44,8 +44,6 @@ public class IngestDialogPanel extends javax.swing.JPanel {
|
||||
|
||||
private IngestModuleAbstract currentModule;
|
||||
private ModulesTableModel tableModel;
|
||||
public static final String DISABLED_MOD = "Disabled_Ingest_Modules";
|
||||
public static final String PARSE_UNALLOC = "Process_Unallocated_Space";
|
||||
private String context;
|
||||
|
||||
/**
|
||||
@ -123,8 +121,8 @@ public class IngestDialogPanel extends javax.swing.JPanel {
|
||||
processUnallocCheckbox.setSelected(enabled);
|
||||
}
|
||||
|
||||
public void setDisabledModules(List<IngestModuleAbstract> disabledModules) {
|
||||
tableModel.setUnselectedModules(disabledModules);
|
||||
public void setEnabledIngestModules(List<IngestModuleAbstract> enabledModules) {
|
||||
tableModel.setSelectedModules(enabledModules);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -407,7 +405,7 @@ public class IngestDialogPanel extends javax.swing.JPanel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom cell renderer for tooltips with module description
|
||||
* Custom cell renderer for tool tips with module description
|
||||
*/
|
||||
private class ModulesTableRenderer extends DefaultTableCellRenderer {
|
||||
|
||||
|
@ -475,6 +475,9 @@ public final class IngestModuleLoader {
|
||||
|
||||
for (final ModuleInfo moduleInfo : moduleInfos) {
|
||||
if (moduleInfo.isEnabled()) {
|
||||
/* NOTE: We have an assumption here that the modules in an NBM will
|
||||
* have the same package name as the NBM name. This means that
|
||||
* an NBM can have only one package with modules in it. */
|
||||
String basePackageName = moduleInfo.getCodeNameBase();
|
||||
|
||||
// skip the standard ones
|
||||
|
@ -19,6 +19,7 @@
|
||||
package org.sleuthkit.autopsy.hashdatabase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -375,4 +376,14 @@ public class HashDbIngestModule extends IngestModuleAbstractFile {
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public ArrayList<String> getKnownBadSetNames() {
|
||||
ArrayList<String> knownBadSetNames = new ArrayList<>();
|
||||
HashDbXML hdbxml = HashDbXML.getCurrent();
|
||||
for (HashDb db : hdbxml.getKnownBadSets()) {
|
||||
knownBadSetNames.add(db.getName());
|
||||
}
|
||||
return knownBadSetNames;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -59,8 +59,10 @@ public class AbstractFileHtmlExtract implements AbstractFileExtract {
|
||||
"text/javascript" //"application/xml",
|
||||
//"application/xml-dtd",
|
||||
);
|
||||
private final TikaLanguageIdentifier tikaLanguageIdentifier;
|
||||
|
||||
AbstractFileHtmlExtract() {
|
||||
tikaLanguageIdentifier = new TikaLanguageIdentifier();
|
||||
this.module = KeywordSearchIngestModule.getDefault();
|
||||
ingester = Server.getIngester();
|
||||
}
|
||||
@ -148,6 +150,7 @@ public class AbstractFileHtmlExtract implements AbstractFileExtract {
|
||||
//logger.log(Level.INFO, "TOTAL READ SIZE: " + totalRead + " file: " + sourceFile.getName());
|
||||
//encode to bytes to index as byte stream
|
||||
String extracted;
|
||||
|
||||
//add BOM and trim the 0 bytes
|
||||
//set initial size to chars read + bom - try to prevent from resizing
|
||||
StringBuilder sb = new StringBuilder((int) totalRead + 1000);
|
||||
@ -163,6 +166,11 @@ public class AbstractFileHtmlExtract implements AbstractFileExtract {
|
||||
totalRead = 0;
|
||||
extracted = sb.toString();
|
||||
|
||||
|
||||
//attempt to identify language of extracted text and post it to the blackboard
|
||||
tikaLanguageIdentifier.addLanguageToBlackBoard(extracted, sourceFile);
|
||||
|
||||
|
||||
//converts BOM automatically to charSet encoding
|
||||
byte[] encodedBytes = extracted.getBytes(outCharset);
|
||||
AbstractFileChunk chunk = new AbstractFileChunk(this, this.numChunks + 1);
|
||||
@ -216,13 +224,11 @@ public class AbstractFileHtmlExtract implements AbstractFileExtract {
|
||||
public boolean isSupported(AbstractFile file, String detectedFormat) {
|
||||
if (detectedFormat == null) {
|
||||
return false;
|
||||
}
|
||||
else if (WEB_MIME_TYPES.contains(detectedFormat) ) {
|
||||
} else if (WEB_MIME_TYPES.contains(detectedFormat)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -39,11 +39,16 @@ import org.sleuthkit.autopsy.ingest.IngestModuleAbstractFile;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||
import org.apache.tika.Tika;
|
||||
import org.apache.tika.language.LanguageIdentifier;
|
||||
import org.apache.tika.metadata.Metadata;
|
||||
import org.apache.tika.mime.MediaType;
|
||||
import org.apache.tika.parser.ParseContext;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.StringExtract;
|
||||
import org.sleuthkit.autopsy.keywordsearch.Ingester.IngesterException;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Extractor of text from TIKA supported AbstractFile content. Extracted text is
|
||||
@ -71,8 +76,10 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
|
||||
//private static final String UTF16BOM = "\uFEFF"; disabled prepending of BOM
|
||||
private final ExecutorService tikaParseExecutor = Executors.newSingleThreadExecutor();
|
||||
private final List<String> TIKA_SUPPORTED_TYPES = new ArrayList<String>();
|
||||
private final TikaLanguageIdentifier tikaLanguageIdentifier;
|
||||
|
||||
AbstractFileTikaTextExtract() {
|
||||
tikaLanguageIdentifier = new TikaLanguageIdentifier();
|
||||
this.module = KeywordSearchIngestModule.getDefault();
|
||||
ingester = Server.getIngester();
|
||||
|
||||
@ -123,7 +130,7 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
|
||||
final InputStream stream = new ReadContentInputStream(sourceFile);
|
||||
try {
|
||||
Metadata meta = new Metadata();
|
||||
|
||||
|
||||
//Parse the file in a task
|
||||
Tika tika = new Tika(); //new tika instance for every file, to workaround tika memory issues
|
||||
ParseRequestTask parseTask = new ParseRequestTask(tika, stream, meta, sourceFile);
|
||||
@ -152,7 +159,7 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// break the results into chunks and index
|
||||
success = true;
|
||||
long readSize;
|
||||
@ -213,7 +220,10 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
|
||||
}
|
||||
|
||||
extracted = sb.toString();
|
||||
|
||||
|
||||
//attempt to identify language of extracted text and post it to the blackboard
|
||||
tikaLanguageIdentifier.addLanguageToBlackBoard(extracted, sourceFile);
|
||||
|
||||
//converts BOM automatically to charSet encoding
|
||||
byte[] encodedBytes = extracted.getBytes(OUTPUT_CHARSET);
|
||||
AbstractFileChunk chunk = new AbstractFileChunk(this, this.numChunks + 1);
|
||||
@ -272,7 +282,7 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
|
||||
if (detectedFormat == null) {
|
||||
return false;
|
||||
} else if (detectedFormat.equals("application/octet-stream")
|
||||
|| detectedFormat.equals("application/x-msdownload") ) {
|
||||
|| detectedFormat.equals("application/x-msdownload")) {
|
||||
//any binary unstructured blobs (string extraction will be used)
|
||||
return false;
|
||||
} else if (AbstractFileExtract.ARCHIVE_MIME_TYPES.contains(detectedFormat)) {
|
||||
@ -292,8 +302,8 @@ public class AbstractFileTikaTextExtract implements AbstractFileExtract {
|
||||
}
|
||||
|
||||
/**
|
||||
* Runnable task that calls tika to parse the content using
|
||||
* the input stream. Provides reader for results.
|
||||
* Runnable task that calls tika to parse the content using the input
|
||||
* stream. Provides reader for results.
|
||||
*/
|
||||
private static class ParseRequestTask implements Runnable {
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011-2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -21,9 +21,6 @@ package org.sleuthkit.autopsy.keywordsearch;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.apache.solr.client.solrj.SolrServerException;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||
import org.sleuthkit.autopsy.keywordsearch.KeywordSearch.QueryType;
|
||||
import org.sleuthkit.autopsy.keywordsearch.KeywordSearchQueryManager.Presentation;
|
||||
@ -35,7 +32,6 @@ import org.sleuthkit.autopsy.keywordsearch.KeywordSearchQueryManager.Presentatio
|
||||
abstract class AbstractKeywordSearchPerformer extends javax.swing.JPanel implements KeywordSearchPerformerInterface {
|
||||
|
||||
protected int filesIndexed;
|
||||
private static final Logger logger = Logger.getLogger(AbstractKeywordSearchPerformer.class.getName());
|
||||
|
||||
AbstractKeywordSearchPerformer() {
|
||||
initListeners();
|
||||
@ -47,7 +43,6 @@ abstract class AbstractKeywordSearchPerformer extends javax.swing.JPanel impleme
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
String changed = evt.getPropertyName();
|
||||
Object oldValue = evt.getOldValue();
|
||||
Object newValue = evt.getNewValue();
|
||||
|
||||
if (changed.equals(KeywordSearch.NUM_FILES_CHANGE_EVT)) {
|
||||
@ -114,7 +109,7 @@ abstract class AbstractKeywordSearchPerformer extends javax.swing.JPanel impleme
|
||||
KeywordSearchUtil.displayDialog("Keyword Search Error", "Keyword list is empty, please add at least one keyword to the list", KeywordSearchUtil.DIALOG_MESSAGE_TYPE.ERROR);
|
||||
return;
|
||||
}
|
||||
man = new KeywordSearchQueryManager(keywords, Presentation.COLLAPSE);
|
||||
man = new KeywordSearchQueryManager(keywords, Presentation.FLAT);
|
||||
}
|
||||
else {
|
||||
QueryType queryType = null;
|
||||
@ -128,7 +123,7 @@ abstract class AbstractKeywordSearchPerformer extends javax.swing.JPanel impleme
|
||||
KeywordSearchUtil.displayDialog("Keyword Search Error", "Please enter a keyword to search for", KeywordSearchUtil.DIALOG_MESSAGE_TYPE.ERROR);
|
||||
return;
|
||||
}
|
||||
man = new KeywordSearchQueryManager(getQueryText(), queryType, Presentation.COLLAPSE);
|
||||
man = new KeywordSearchQueryManager(getQueryText(), queryType, Presentation.FLAT);
|
||||
}
|
||||
|
||||
if (man.validate()) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011-2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -28,7 +28,6 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.windows.TopComponent;
|
||||
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
|
||||
import org.sleuthkit.autopsy.datamodel.KeyValue;
|
||||
import org.sleuthkit.autopsy.keywordsearch.KeywordSearch.QueryType;
|
||||
@ -41,7 +40,9 @@ public class KeywordSearchQueryManager {
|
||||
|
||||
// how to display the results
|
||||
public enum Presentation {
|
||||
COLLAPSE, DETAIL
|
||||
FLAT, // all results are in a single level (even if multiple keywords and reg-exps are used). We made this because we were having problems with multiple-levels of nodes and the thumbnail and table view sharing an ExplorerManager. IconView seemed to change EM so that it did not allow lower levels to be selected.
|
||||
COLLAPSE, // two levels. Keywords on top, files on bottom.
|
||||
DETAIL // not currently used, but seems like it has three levels of nodes
|
||||
};
|
||||
|
||||
private List<Keyword> keywords;
|
||||
@ -70,7 +71,7 @@ public class KeywordSearchQueryManager {
|
||||
* @param presentation Presentation Layout
|
||||
*/
|
||||
public KeywordSearchQueryManager(String query, QueryType qt, Presentation presentation) {
|
||||
keywords = new ArrayList<Keyword>();
|
||||
keywords = new ArrayList<>();
|
||||
keywords.add(new Keyword(query, qt == QueryType.REGEX ? false : true));
|
||||
this.presentation = presentation;
|
||||
queryType = qt;
|
||||
@ -84,7 +85,7 @@ public class KeywordSearchQueryManager {
|
||||
* @param presentation Presentation layout
|
||||
*/
|
||||
public KeywordSearchQueryManager(String query, boolean isLiteral, Presentation presentation) {
|
||||
keywords = new ArrayList<Keyword>();
|
||||
keywords = new ArrayList<>();
|
||||
keywords.add(new Keyword(query, isLiteral));
|
||||
this.presentation = presentation;
|
||||
queryType = isLiteral ? QueryType.WORD : QueryType.REGEX;
|
||||
@ -96,7 +97,7 @@ public class KeywordSearchQueryManager {
|
||||
* Create a list of queries to later run
|
||||
*/
|
||||
private void init() {
|
||||
queryDelegates = new ArrayList<KeywordSearchQuery>();
|
||||
queryDelegates = new ArrayList<>();
|
||||
for (Keyword keyword : keywords) {
|
||||
KeywordSearchQuery query = null;
|
||||
switch (queryType) {
|
||||
@ -137,18 +138,17 @@ public class KeywordSearchQueryManager {
|
||||
// } else {
|
||||
|
||||
//Collapsed view
|
||||
Collection<KeyValueQuery> things = new ArrayList<KeyValueQuery>();
|
||||
Collection<KeyValueQuery> things = new ArrayList<>();
|
||||
int queryID = 0;
|
||||
StringBuilder queryConcat = new StringBuilder(); // concatenation of all query strings
|
||||
for (KeywordSearchQuery q : queryDelegates) {
|
||||
Map<String, Object> kvs = new LinkedHashMap<String, Object>();
|
||||
Map<String, Object> kvs = new LinkedHashMap<>();
|
||||
final String queryStr = q.getQueryString();
|
||||
queryConcat.append(queryStr).append(" ");
|
||||
things.add(new KeyValueQuery(queryStr, kvs, ++queryID, q));
|
||||
}
|
||||
|
||||
Node rootNode = null;
|
||||
|
||||
Node rootNode;
|
||||
String queryConcatStr = queryConcat.toString();
|
||||
final int queryConcatStrLen = queryConcatStr.length();
|
||||
final String queryStrShort = queryConcatStrLen > 15 ? queryConcatStr.substring(0, 14) + "..." : queryConcatStr;
|
||||
@ -156,7 +156,7 @@ public class KeywordSearchQueryManager {
|
||||
DataResultTopComponent searchResultWin = DataResultTopComponent.createInstance(windowTitle);
|
||||
if (things.size() > 0) {
|
||||
Children childThingNodes =
|
||||
Children.create(new KeywordSearchResultFactory(keywords, things, Presentation.COLLAPSE, searchResultWin), true);
|
||||
Children.create(new KeywordSearchResultFactory(keywords, things, presentation, searchResultWin), true);
|
||||
|
||||
rootNode = new AbstractNode(childThingNodes);
|
||||
} else {
|
||||
@ -179,7 +179,7 @@ public class KeywordSearchQueryManager {
|
||||
boolean allValid = true;
|
||||
for (KeywordSearchQuery tcq : queryDelegates) {
|
||||
if (!tcq.validate()) {
|
||||
logger.log(Level.WARNING, "Query has invalid syntax: " + tcq.getQueryString());
|
||||
logger.log(Level.WARNING, "Query has invalid syntax: {0}", tcq.getQueryString());
|
||||
allValid = false;
|
||||
break;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011-2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -36,7 +36,6 @@ import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.util.Cancellable;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer;
|
||||
import org.sleuthkit.autopsy.corecomponents.DataResultTopComponent;
|
||||
@ -109,7 +108,7 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
}
|
||||
|
||||
KeywordSearchResultFactory(Keyword query, Collection<KeyValueQuery> things, Presentation presentation, DataResultTopComponent viewer) {
|
||||
queries = new ArrayList<Keyword>();
|
||||
queries = new ArrayList<>();
|
||||
queries.add(query);
|
||||
this.presentation = presentation;
|
||||
this.things = things;
|
||||
@ -134,7 +133,6 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
for (int i = 0; i < FS_PROPS_LEN; ++i) {
|
||||
toSet.put(fsTypes[i].toString(), "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void setCommonProperty(Map<String, Object> toSet, CommonPropertyTypes type, String value) {
|
||||
@ -150,10 +148,21 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
@Override
|
||||
protected boolean createKeys(List<KeyValueQuery> toPopulate) {
|
||||
int id = 0;
|
||||
if (presentation == Presentation.DETAIL) {
|
||||
if (presentation == Presentation.FLAT) {
|
||||
for (KeyValueQuery thing : things) {
|
||||
Map<String, Object> map = thing.getMap();
|
||||
initCommonProperties(map);
|
||||
final String query = thing.getName();
|
||||
setCommonProperty(map, CommonPropertyTypes.KEYWORD, query);
|
||||
setCommonProperty(map, CommonPropertyTypes.REGEX, Boolean.valueOf(!thing.getQuery().isEscaped()));
|
||||
ResultCollapsedChildFactory childFactory = new ResultCollapsedChildFactory(thing);
|
||||
childFactory.createKeysForFlatNodes(toPopulate);
|
||||
}
|
||||
}
|
||||
else if (presentation == Presentation.DETAIL) {
|
||||
Iterator<KeyValueQuery> it = things.iterator();
|
||||
for (Keyword keyword : queries) {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
final String query = keyword.getQuery();
|
||||
initCommonProperties(map);
|
||||
setCommonProperty(map, CommonPropertyTypes.KEYWORD, query);
|
||||
@ -166,25 +175,26 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
}
|
||||
} else {
|
||||
for (KeyValueQuery thing : things) {
|
||||
//Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
Map<String, Object> map = thing.getMap();
|
||||
initCommonProperties(map);
|
||||
final String query = thing.getName();
|
||||
setCommonProperty(map, CommonPropertyTypes.KEYWORD, query);
|
||||
setCommonProperty(map, CommonPropertyTypes.REGEX, Boolean.valueOf(!thing.getQuery().isEscaped()));
|
||||
//toPopulate.add(new KeyValue(query, map, ++id));
|
||||
toPopulate.add(thing);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(KeyValueQuery thing) {
|
||||
ChildFactory<KeyValueQuery> childFactory = null;
|
||||
|
||||
if (presentation == Presentation.COLLAPSE) {
|
||||
ChildFactory<KeyValueQuery> childFactory;
|
||||
if (presentation == Presentation.FLAT) {
|
||||
ResultCollapsedChildFactory factory = new ResultCollapsedChildFactory(thing);
|
||||
return factory.createFlatNodeForKey(thing);
|
||||
}
|
||||
else if (presentation == Presentation.COLLAPSE) {
|
||||
childFactory = new ResultCollapsedChildFactory(thing);
|
||||
final Node ret = new KeyValueNode(thing, Children.create(childFactory, true));
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@ -199,7 +209,6 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
});
|
||||
return ret;
|
||||
} else {
|
||||
|
||||
childFactory = new ResulTermsMatchesChildFactory(things);
|
||||
return new KeyValueNode(thing, Children.create(childFactory, true));
|
||||
}
|
||||
@ -218,9 +227,13 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
this.queryThing = queryThing;
|
||||
}
|
||||
|
||||
// @@@ This method is a workaround until we decide whether we need all three presentation modes or FLAT is sufficient.
|
||||
public boolean createKeysForFlatNodes(List<KeyValueQuery> toPopulate) {
|
||||
return createKeys(toPopulate);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<KeyValueQuery> toPopulate) {
|
||||
//final String origQuery = queryThing.getName();
|
||||
final KeyValueQuery queryThingQuery = queryThing;
|
||||
final KeywordSearchQuery tcq = queryThingQuery.getQuery();
|
||||
|
||||
@ -252,7 +265,7 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
for (final AbstractFile f : hitContents.keySet()) {
|
||||
final int previewChunk = hitContents.get(f);
|
||||
//get unique match result files
|
||||
Map<String, Object> resMap = new LinkedHashMap<String, Object>();
|
||||
Map<String, Object> resMap = new LinkedHashMap<>();
|
||||
setCommonProperty(resMap, CommonPropertyTypes.MATCH, f.getName());
|
||||
|
||||
try {
|
||||
@ -306,12 +319,11 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
//whereas in bb we write every hit per file separately
|
||||
new ResultWriter(tcqRes, tcq, listName).execute();
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private String getHighlightQuery(KeywordSearchQuery tcq, boolean literal_query, Map<String, List<ContentHit>> tcqRes, AbstractFile f) {
|
||||
String highlightQueryEscaped = null;
|
||||
String highlightQueryEscaped;
|
||||
if (literal_query) {
|
||||
//literal, treat as non-regex, non-term component query
|
||||
highlightQueryEscaped = tcq.getQueryString();
|
||||
@ -326,7 +338,7 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
highlightQuery.append(term);
|
||||
} else {
|
||||
//find terms for this file hit
|
||||
List<String> hitTerms = new ArrayList<String>();
|
||||
List<String> hitTerms = new ArrayList<>();
|
||||
for (String term : tcqRes.keySet()) {
|
||||
List<ContentHit> hitList = tcqRes.get(term);
|
||||
|
||||
@ -363,10 +375,13 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
return highlightQueryEscaped;
|
||||
}
|
||||
|
||||
// @@@ This method is a workaround until we decide whether we need all three presentation modes or FLAT is sufficient.
|
||||
public Node createFlatNodeForKey(KeyValueQuery thing) {
|
||||
return createNodeForKey(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node createNodeForKey(KeyValueQuery thing) {
|
||||
//return new KeyValueNode(thing, Children.LEAF);
|
||||
//return new KeyValueNode(thing, Children.create(new ResultFilesChildFactory(thing), true));
|
||||
final KeyValueQueryContent thingContent = (KeyValueQueryContent) thing;
|
||||
final Content content = thingContent.getContent();
|
||||
final String queryStr = thingContent.getQueryStr();
|
||||
@ -377,7 +392,6 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
//wrap in KeywordSearchFilterNode for the markup content, might need to override FilterNode for more customization
|
||||
HighlightedMatchesSource highlights = new HighlightedMatchesSource(content, queryStr, !thingContent.getQuery().isEscaped(), false, hits);
|
||||
return new KeywordSearchFilterNode(highlights, kvNode, queryStr, previewChunk);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -438,12 +452,11 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
|
||||
for (final AbstractFile f : uniqueMatches.keySet()) {
|
||||
final int previewChunkId = uniqueMatches.get(f);
|
||||
Map<String, Object> resMap = new LinkedHashMap<String, Object>();
|
||||
Map<String, Object> resMap = new LinkedHashMap<>();
|
||||
if (f.getType() == TSK_DB_FILES_TYPE_ENUM.FS) {
|
||||
AbstractFsContentNode.fillPropertyMap(resMap, (FsContent) f);
|
||||
}
|
||||
toPopulate.add(new KeyValueQueryContent(f.getName(), resMap, ++resID, f, keywordQuery, thing.getQuery(), previewChunkId, matchesRes));
|
||||
|
||||
}
|
||||
//write to bb
|
||||
new ResultWriter(matchesRes, origQuery, "").execute();
|
||||
@ -459,7 +472,6 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
final int previewChunk = thingContent.getPreviewChunk();
|
||||
final Map<String, List<ContentHit>> hits = thingContent.getHits();
|
||||
|
||||
|
||||
Node kvNode = new KeyValueNode(thingContent, Children.LEAF, Lookups.singleton(content));
|
||||
//wrap in KeywordSearchFilterNode for the markup content
|
||||
HighlightedMatchesSource highlights = new HighlightedMatchesSource(content, query, !thingContent.getQuery().isEscaped(), hits);
|
||||
@ -475,7 +487,6 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
|
||||
private Content content;
|
||||
private String queryStr;
|
||||
private KeywordSearchQuery query;
|
||||
private int previewChunk;
|
||||
private Map<String, List<ContentHit>> hits;
|
||||
|
||||
@ -510,7 +521,7 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
*/
|
||||
static class ResultWriter extends SwingWorker<Object, Void> {
|
||||
|
||||
private static List<ResultWriter> writers = new ArrayList<ResultWriter>();
|
||||
private static List<ResultWriter> writers = new ArrayList<>();
|
||||
//lock utilized to enqueue writers and limit execution to 1 at a time
|
||||
private static final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(true); //use fairness policy
|
||||
//private static final Lock writerLock = rwLock.writeLock();
|
||||
@ -518,14 +529,13 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
private KeywordSearchQuery query;
|
||||
private String listName;
|
||||
private Map<String, List<ContentHit>> hits;
|
||||
final Collection<BlackboardArtifact> na = new ArrayList<BlackboardArtifact>();
|
||||
final Collection<BlackboardArtifact> na = new ArrayList<>();
|
||||
private static final int QUERY_DISPLAY_LEN = 40;
|
||||
|
||||
ResultWriter(Map<String, List<ContentHit>> hits, KeywordSearchQuery query, String listName) {
|
||||
this.hits = hits;
|
||||
this.query = query;
|
||||
this.listName = listName;
|
||||
|
||||
}
|
||||
|
||||
protected void finalizeWorker() {
|
||||
@ -539,7 +549,6 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (!this.isCancelled() && !na.isEmpty()) {
|
||||
IngestServices.getDefault().fireModuleDataEvent(new ModuleDataEvent(KeywordSearchIngestModule.MODULE_NAME, ARTIFACT_TYPE.TSK_KEYWORD_HIT, na));
|
||||
}
|
||||
@ -573,7 +582,7 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
for (AbstractFile f : flattened.keySet()) {
|
||||
int chunkId = flattened.get(f);
|
||||
final String snippetQuery = KeywordSearchUtil.escapeLuceneQuery(hit);
|
||||
String snippet = null;
|
||||
String snippet;
|
||||
try {
|
||||
snippet = LuceneQuery.querySnippet(snippetQuery, f.getId(), chunkId, !query.isLiteral(), true);
|
||||
} catch (NoOpenCoreException e) {
|
||||
@ -591,15 +600,11 @@ public class KeywordSearchResultFactory extends ChildFactory<KeyValueQuery> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} finally {
|
||||
//writerLock.unlock();
|
||||
finalizeWorker();
|
||||
}
|
||||
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.keywordsearch;
|
||||
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public interface TextLanguageIdentifier {
|
||||
|
||||
/**
|
||||
* attempts to identify the language of the given String and add it to the
|
||||
* black board for the given {@code AbstractFile} as a TSK_TEXT_LANGUAGE
|
||||
* attribute on a TSK_GEN_INFO artifact.
|
||||
*
|
||||
* @param extracted the String whose language is to be identified
|
||||
* @param sourceFile the AbstractFile the string is extracted from.
|
||||
* @return
|
||||
*/
|
||||
public void addLanguageToBlackBoard(String extracted, AbstractFile sourceFile);
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 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.keywordsearch;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* TextLanguageIdentifier implementation based on a wrapped Tike
|
||||
* LanguageIdentifier
|
||||
*/
|
||||
public class TikaLanguageIdentifier implements TextLanguageIdentifier {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(TikaLanguageIdentifier.class.getName());
|
||||
private static final int MIN_STRING_LENGTH = 1000;
|
||||
|
||||
@Override
|
||||
public void addLanguageToBlackBoard(String extracted, AbstractFile sourceFile) {
|
||||
if (extracted.length() > MIN_STRING_LENGTH) {
|
||||
org.apache.tika.language.LanguageIdentifier li = new org.apache.tika.language.LanguageIdentifier(extracted);
|
||||
|
||||
logger.log(Level.INFO, sourceFile.getName() + " detected language: " + li.getLanguage()
|
||||
+ " with " + ((li.isReasonablyCertain()) ? "HIGH" : "LOW") + " confidence");
|
||||
|
||||
BlackboardArtifact genInfo;
|
||||
try {
|
||||
genInfo = sourceFile.getGenInfoArtifact();
|
||||
|
||||
BlackboardAttribute textLang = new BlackboardAttribute(
|
||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT_LANGUAGE.getTypeID(),
|
||||
KeywordSearchIngestModule.MODULE_NAME, li.getLanguage());
|
||||
|
||||
genInfo.addAttribute(textLang);
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "failed to add TSK_TEXT_LANGUAGE attribute to TSK_GEN_INFO artifact for file: " + sourceFile.getName(), ex);
|
||||
}
|
||||
|
||||
} else {
|
||||
logger.info("extracted text too short, skipping language detection on " + sourceFile.getName());
|
||||
}
|
||||
}
|
||||
}
|
@ -138,7 +138,7 @@ public class Chrome extends Extract {
|
||||
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<BlackboardAttribute>();
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL.getTypeID(), "Recent Activity", ((result.get("url").toString() != null) ? result.get("url").toString() : "")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
|
||||
//TODO Revisit usage of deprecated constructor per TSK-583
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "Recent Activity", "Last Visited", ((Long.valueOf(result.get("last_visit_time").toString())) / 10000000)));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID(), "Recent Activity", ((Long.valueOf(result.get("last_visit_time").toString())) / 10000000)));
|
||||
@ -232,7 +232,7 @@ public class Chrome extends Extract {
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "Recent Activity", "Last Visited", (date / 10000000)));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID(), "Recent Activity", (date / 10000000)));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL.getTypeID(), "Recent Activity", url));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", EscapeUtil.decodeURL(url)));
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", EscapeUtil.decodeURL(url)));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), "Recent Activity", name));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID(), "Recent Activity", "Chrome"));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN.getTypeID(), "Recent Activity", domain));
|
||||
@ -299,7 +299,7 @@ public class Chrome extends Extract {
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(), "Recent Activity", ((result.get("value").toString() != null) ? result.get("value").toString() : "")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID(), "Recent Activity", "Chrome"));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL.getTypeID(), "Recent Activity", ((result.get("host_key").toString() != null) ? result.get("host_key").toString() : "")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", ((result.get("host_key").toString() != null) ? EscapeUtil.decodeURL(result.get("host_key").toString()) : "")));
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", ((result.get("host_key").toString() != null) ? EscapeUtil.decodeURL(result.get("host_key").toString()) : "")));
|
||||
String domain = result.get("host_key").toString();
|
||||
domain = domain.replaceFirst("^\\.+(?!$)", "");
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN.getTypeID(), "Recent Activity", domain));
|
||||
@ -358,7 +358,7 @@ public class Chrome extends Extract {
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH.getTypeID(), "Recent Activity", (result.get("full_path").toString())));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID(), "Recent Activity", Util.findID(dataSource, (result.get("full_path").toString()))));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL.getTypeID(), "Recent Activity", ((result.get("url").toString() != null) ? result.get("url").toString() : "")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
|
||||
Long time = (Long.valueOf(result.get("start_time").toString()));
|
||||
String Tempdate = time.toString();
|
||||
time = Long.valueOf(Tempdate) / 10000000;
|
||||
@ -417,7 +417,7 @@ public class Chrome extends Extract {
|
||||
for (HashMap<String, Object> result : tempList) {
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<BlackboardAttribute>();
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL.getTypeID(), "Recent Activity", ((result.get("origin_url").toString() != null) ? result.get("origin_url").toString() : "")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", ((result.get("origin_url").toString() != null) ? EscapeUtil.decodeURL(result.get("origin_url").toString()) : "")));
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "Recent Activity", ((result.get("origin_url").toString() != null) ? EscapeUtil.decodeURL(result.get("origin_url").toString()) : "")));
|
||||
//TODO Revisit usage of deprecated constructor as per TSK-583
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID(), "Recent Activity", "Last Visited", ((Long.valueOf(result.get("last_visit_time").toString())) / 1000000)));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID(), "Recent Activity", ((Long.valueOf(result.get("last_visit_time").toString())) / 1000000)));
|
||||
|
@ -136,7 +136,7 @@ public class ExtractIE extends Extract {
|
||||
}
|
||||
|
||||
try {
|
||||
this.parsePascoResults(pascoResults);
|
||||
this.getHistory(pascoResults);
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Error parsing IE History", e);
|
||||
@ -189,7 +189,7 @@ public class ExtractIE extends Extract {
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "RecentActivity", "Last Visited", datetime));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID(), "RecentActivity", datetime));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL.getTypeID(), "RecentActivity", url));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", EscapeUtil.decodeURL(url)));
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", EscapeUtil.decodeURL(url)));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), "RecentActivity", name));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID(), "RecentActivity", "Internet Explorer"));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN.getTypeID(), "RecentActivity", domain));
|
||||
@ -238,7 +238,7 @@ public class ExtractIE extends Extract {
|
||||
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<BlackboardAttribute>();
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL.getTypeID(), "RecentActivity", url));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", EscapeUtil.decodeURL(url)));
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", EscapeUtil.decodeURL(url)));
|
||||
//TODO Revisit usage of deprecated Constructor as of TSK-583
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(), "RecentActivity", "Last Visited", datetime));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(), "RecentActivity", datetime));
|
||||
@ -394,7 +394,7 @@ public class ExtractIE extends Extract {
|
||||
execPasco.execute(writer, JAVA_PATH,
|
||||
"-cp", PASCO_LIB_PATH,
|
||||
"isi.pasco2.Main", "-T", "history", indexFilePath );
|
||||
|
||||
// @@@ Investigate use of history versus cache as type.
|
||||
} catch (IOException ex) {
|
||||
success = false;
|
||||
logger.log(Level.SEVERE, "Unable to execute Pasco to process Internet Explorer web history.", ex);
|
||||
@ -416,7 +416,7 @@ public class ExtractIE extends Extract {
|
||||
return success;
|
||||
}
|
||||
|
||||
private void parsePascoResults(List<String> filenames) {
|
||||
private void getHistory(List<String> filenames) {
|
||||
if (pascoFound == false) {
|
||||
return;
|
||||
}
|
||||
@ -451,6 +451,15 @@ public class ExtractIE extends Extract {
|
||||
|
||||
String line = fileScanner.nextLine();
|
||||
|
||||
// lines at end of file
|
||||
if ((line.startsWith("LEAK entries")) ||
|
||||
(line.startsWith("REDR entries")) ||
|
||||
(line.startsWith("URL entries")) ||
|
||||
(line.startsWith("ent entries")) ||
|
||||
(line.startsWith("unknown entries"))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.startsWith("URL")) {
|
||||
String[] lineBuff = line.split("\\t");
|
||||
|
||||
@ -466,6 +475,10 @@ public class ExtractIE extends Extract {
|
||||
String realurl = "";
|
||||
String domain = "";
|
||||
|
||||
/* We've seen two types of lines:
|
||||
* URL http://XYZ.com ....
|
||||
* URL Visited: Joe@http://XYZ.com ....
|
||||
*/
|
||||
if (lineBuff[1].contains("@")) {
|
||||
String url[] = lineBuff[1].split("@", 2);
|
||||
user = url[0];
|
||||
@ -505,7 +518,7 @@ public class ExtractIE extends Extract {
|
||||
BlackboardArtifact bbart = tskCase.getContentById(artObjId).newArtifact(ARTIFACT_TYPE.TSK_WEB_HISTORY);
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<BlackboardAttribute>();
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL.getTypeID(), "RecentActivity", realurl));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", EscapeUtil.decodeURL(realurl)));
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", EscapeUtil.decodeURL(realurl)));
|
||||
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID(), "RecentActivity", ftime));
|
||||
|
||||
|
@ -119,7 +119,7 @@ public class Firefox extends Extract {
|
||||
for (HashMap<String, Object> result : tempList) {
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<BlackboardAttribute>();
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL.getTypeID(), "RecentActivity", ((result.get("url").toString() != null) ? result.get("url").toString() : "")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
|
||||
//TODO Revisit usage of deprecated constructor as per TSK-583
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "RecentActivity", "Last Visited", (Long.valueOf(result.get("visit_date").toString()))));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID(), "RecentActivity", (Long.valueOf(result.get("visit_date").toString()))));
|
||||
@ -177,7 +177,7 @@ public class Firefox extends Extract {
|
||||
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<BlackboardAttribute>();
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL.getTypeID(), "RecentActivity", ((result.get("url").toString() != null) ? result.get("url").toString() : "")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("url").toString() != null) ? EscapeUtil.decodeURL(result.get("url").toString()) : "")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), "RecentActivity", ((result.get("title").toString() != null) ? result.get("title").toString() : "")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID(), "RecentActivity", "FireFox"));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DOMAIN.getTypeID(), "RecentActivity", (Util.extractDomain((result.get("url").toString() != null) ? result.get("url").toString() : ""))));
|
||||
@ -241,7 +241,7 @@ public class Firefox extends Extract {
|
||||
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<BlackboardAttribute>();
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL.getTypeID(), "RecentActivity", ((result.get("host").toString() != null) ? result.get("host").toString() : "")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("host").toString() != null) ? EscapeUtil.decodeURL(result.get("host").toString()) : "")));
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("host").toString() != null) ? EscapeUtil.decodeURL(result.get("host").toString()) : "")));
|
||||
//TODO Revisit usage of deprecated constructor as per TSK-583
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), "RecentActivity", "Title", ((result.get("name").toString() != null) ? result.get("name").toString() : "")));
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(), "RecentActivity", "Last Visited", (Long.valueOf(result.get("lastAccessed").toString()))));
|
||||
@ -312,7 +312,7 @@ public class Firefox extends Extract {
|
||||
Collection<BlackboardAttribute> bbattributes = new ArrayList<BlackboardAttribute>();
|
||||
String urldecodedtarget = URLDecoder.decode(result.get("source").toString().replaceAll("file:///", ""), "UTF-8");
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL.getTypeID(), "RecentActivity", ((result.get("source").toString() != null) ? result.get("source").toString() : "")));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("source").toString() != null) ? EscapeUtil.decodeURL(result.get("source").toString()) : "")));
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL_DECODED.getTypeID(), "RecentActivity", ((result.get("source").toString() != null) ? EscapeUtil.decodeURL(result.get("source").toString()) : "")));
|
||||
//TODO Revisit usage of deprecated constructor as per TSK-583
|
||||
//bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LAST_ACCESSED.getTypeID(), "RecentActivity", "Last Visited", (Long.valueOf(result.get("startTime").toString()))));
|
||||
bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID(), "RecentActivity", (Long.valueOf(result.get("startTime").toString()))));
|
||||
|
@ -5,4 +5,29 @@
|
||||
<project name="org.sleuthkit.autopsy.timeline" default="netbeans" basedir=".">
|
||||
<description>Builds, tests, and runs the project org.sleuthkit.autopsy.timeline.</description>
|
||||
<import file="nbproject/build-impl.xml"/>
|
||||
|
||||
<condition property="os.family.unix">
|
||||
<os family="unix"/>
|
||||
</condition>
|
||||
|
||||
<!-- Verify that the TSK_HOME env variable is set -->
|
||||
<target name="findTSK">
|
||||
<property environment="env"/>
|
||||
<condition property="tskFound">
|
||||
<isset property="env.TSK_HOME"/>
|
||||
</condition>
|
||||
<fail unless="tskFound" message="TSK_HOME must be set as an environment variable."/>
|
||||
<echo> TSK_HOME: ${env.TSK_HOME}</echo>
|
||||
</target>
|
||||
|
||||
<target name="getMacTime" depends="findTSK" if="os.family.unix">
|
||||
<property environment="env"/>
|
||||
<copy file="${env.TSK_HOME}/tools/timeline/mactime" tofile="${basedir}/release/mactime/mactime.pl"/>
|
||||
</target>
|
||||
|
||||
|
||||
<target name="init" depends="basic-init,files-init,build-init,-javac-init">
|
||||
<!-- get additional deps -->
|
||||
<!-- This should only be done on non-Windows systems. <antcall target="getMacTime" /> -->
|
||||
</target>
|
||||
</project>
|
||||
|
@ -1,938 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
my $VER="4.1.0";
|
||||
#
|
||||
# This program is based on the 'mactime' program by Dan Farmer and
|
||||
# and the 'mac_daddy' program by Rob Lee.
|
||||
#
|
||||
# It takes as input data from either 'ils -m' or 'fls -m' (from The Sleuth
|
||||
# Kit) or 'mac-robber'.
|
||||
# Based on the dates as arguments given, the data is sorted by and
|
||||
# printed.
|
||||
#
|
||||
# The Sleuth Kit
|
||||
# Brian Carrier [carrier <at> sleuthkit [dot] org]
|
||||
# Copyright (c) 2003-2012 Brian Carrier. All rights reserved
|
||||
#
|
||||
# TASK
|
||||
# Copyright (c) 2002 Brian Carrier, @stake Inc. All rights reserved
|
||||
#
|
||||
#
|
||||
# The modifications to the original mactime are distributed under
|
||||
# the Common Public License 1.0
|
||||
#
|
||||
#
|
||||
# Copyright 1999 by Dan Farmer. All rights reserved. Some individual
|
||||
# files may be covered by other copyrights (this will be noted in the
|
||||
# file itself.)
|
||||
#
|
||||
# Redistribution and use in source and binary forms are permitted
|
||||
# provided that this entire copyright notice is duplicated in all such
|
||||
# copies.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||
#
|
||||
# IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA, OR PROFITS OR
|
||||
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
use POSIX;
|
||||
use strict;
|
||||
|
||||
my $debug = 0;
|
||||
|
||||
# %month_to_digit = ("Jan", 1, "Feb", 2, "Mar", 3, "Apr", 4, "May", 5, "Jun", 6,
|
||||
# "Jul", 7, "Aug", 8, "Sep", 9, "Oct", 10, "Nov", 11, "Dec", 12);
|
||||
my %digit_to_month = (
|
||||
"01", "Jan", "02", "Feb", "03", "Mar", "04", "Apr",
|
||||
"05", "May", "06", "Jun", "07", "Jul", "08", "Aug",
|
||||
"09", "Sep", "10", "Oct", "11", "Nov", "12", "Dec"
|
||||
);
|
||||
my %digit_to_day = (
|
||||
"0", "Sun", "1", "Mon", "2", "Tue", "3", "Wed",
|
||||
"4", "Thu", "5", "Fri", "6", "Sat"
|
||||
);
|
||||
|
||||
sub usage {
|
||||
print <<EOF;
|
||||
mactime [-b body_file] [-p password_file] [-g group_file] [-i day|hour idx_file] [-d] [-h] [-V] [-y] [-z TIME_ZONE] [DATE]
|
||||
-b: Specifies the body file location, else STDIN is used
|
||||
-d: Output in comma delimited format
|
||||
-h: Display a header with session information
|
||||
-i [day | hour] file: Specifies the index file with a summary of results
|
||||
-y: Dates are displayed in ISO 8601 format
|
||||
-m: Dates have month as number instead of word (does not work with -y)
|
||||
-z: Specify the timezone the data came from (in the local system format) (does not work with -y)
|
||||
-g: Specifies the group file location, else GIDs are used
|
||||
-p: Specifies the password file location, else UIDs are used
|
||||
-V: Prints the version to STDOUT
|
||||
[DATE]: starting date (yyyy-mm-dd) or range (yyyy-mm-dd..yyyy-mm-dd)
|
||||
EOF
|
||||
exit(1);
|
||||
}
|
||||
|
||||
sub version {
|
||||
print "The Sleuth Kit ver $VER\n";
|
||||
}
|
||||
|
||||
my $BODY = "";
|
||||
my $GROUP = "";
|
||||
my $PASSWD = "";
|
||||
my $TIME = "";
|
||||
my $INDEX = ""; # File name of index
|
||||
my $INDEX_DAY = 1; # Daily index (for $INDEX_TYPE)
|
||||
my $INDEX_HOUR = 2;
|
||||
my $INDEX_TYPE = $INDEX_DAY; # Saved to type of index
|
||||
my $COMMA = 0; # Comma delimited output
|
||||
|
||||
my $iso8601 = 0;
|
||||
my $month_num = 0;
|
||||
my $header = 0;
|
||||
|
||||
my $in_seconds = 0;
|
||||
my $out_seconds = 0;
|
||||
my %timestr2macstr;
|
||||
my %file2other;
|
||||
|
||||
my %gid2names = ();
|
||||
my %uid2names = ();
|
||||
|
||||
my $_HAS_DATETIME_TIMEZONE = 0;
|
||||
|
||||
eval "use DateTime::TimeZone";
|
||||
if ($@) {
|
||||
$_HAS_DATETIME_TIMEZONE = 0;
|
||||
} else {
|
||||
$_HAS_DATETIME_TIMEZONE = 1;
|
||||
}
|
||||
|
||||
sub get_timezone_list() {
|
||||
my @t_list;
|
||||
if ( ! $_HAS_DATETIME_TIMEZONE ) {
|
||||
return @t_list;
|
||||
}
|
||||
|
||||
foreach ( DateTime::TimeZone->all_names() ) {
|
||||
push( @t_list, $_ );
|
||||
}
|
||||
foreach( keys( %{DateTime::TimeZone->links()}) ) {
|
||||
push( @t_list, $_ );
|
||||
}
|
||||
|
||||
return sort { $a cmp $b } @t_list;
|
||||
}
|
||||
|
||||
usage() if (scalar(@ARGV) == 0);
|
||||
|
||||
while ((scalar(@ARGV) > 0) && (($_ = $ARGV[0]) =~ /^-(.)(.*)/)) {
|
||||
|
||||
# Body File
|
||||
if (/^-b$/) {
|
||||
shift(@ARGV);
|
||||
if (defined $ARGV[0]) {
|
||||
$BODY = $ARGV[0];
|
||||
}
|
||||
else {
|
||||
print "-b requires body file argument\n";
|
||||
}
|
||||
}
|
||||
elsif (/^-d$/) {
|
||||
$COMMA = 1;
|
||||
}
|
||||
|
||||
# Group File
|
||||
elsif (/^-g$/) {
|
||||
shift(@ARGV);
|
||||
if (defined $ARGV[0]) {
|
||||
&'load_group_info($ARGV[0]);
|
||||
$GROUP = $ARGV[0];
|
||||
}
|
||||
else {
|
||||
print "-g requires group file argument\n";
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
# Password File
|
||||
elsif (/^-p$/) {
|
||||
shift(@ARGV);
|
||||
if (defined $ARGV[0]) {
|
||||
&'load_passwd_info($ARGV[0]);
|
||||
$PASSWD = $ARGV[0];
|
||||
}
|
||||
else {
|
||||
print "-p requires password file argument\n";
|
||||
usage();
|
||||
}
|
||||
}
|
||||
elsif (/^-h$/) {
|
||||
$header = 1;
|
||||
}
|
||||
|
||||
# Index File
|
||||
elsif (/^-i$/) {
|
||||
shift(@ARGV);
|
||||
|
||||
if (defined $ARGV[0]) {
|
||||
|
||||
# Find out what type
|
||||
if ($ARGV[0] eq "day") {
|
||||
$INDEX_TYPE = $INDEX_DAY;
|
||||
}
|
||||
elsif ($ARGV[0] eq "hour") {
|
||||
$INDEX_TYPE = $INDEX_HOUR;
|
||||
}
|
||||
shift(@ARGV);
|
||||
unless (defined $ARGV[0]) {
|
||||
print "-i requires index file argument\n";
|
||||
usage();
|
||||
}
|
||||
$INDEX = $ARGV[0];
|
||||
}
|
||||
else {
|
||||
print "-i requires index file argument and type\n";
|
||||
usage();
|
||||
}
|
||||
open(INDEX, ">$INDEX") or die "Can not open $INDEX";
|
||||
}
|
||||
elsif (/^-V$/) {
|
||||
version();
|
||||
exit(0);
|
||||
}
|
||||
elsif (/^-m$/) {
|
||||
$month_num = 1;
|
||||
}
|
||||
elsif (/^-y$/) {
|
||||
$iso8601 = 1;
|
||||
}
|
||||
elsif (/^-z$/) {
|
||||
shift(@ARGV);
|
||||
if (defined $ARGV[0]) {
|
||||
my $tz = "$ARGV[0]";
|
||||
|
||||
if ($tz =~ m/^list$/i) {
|
||||
if ($_HAS_DATETIME_TIMEZONE) {
|
||||
my $txt = "
|
||||
-----------------------------------
|
||||
TIMEZONE LIST
|
||||
-----------------------------------\n";
|
||||
foreach ( get_timezone_list() ) {
|
||||
$txt .= $_ . "\n";
|
||||
}
|
||||
print( $txt );
|
||||
}
|
||||
else {
|
||||
print "DateTime module not loaded -- cannot list timezones\n";
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
# validate the string if we have DateTime module
|
||||
elsif ($_HAS_DATETIME_TIMEZONE) {
|
||||
my $realtz = 0;
|
||||
foreach ( get_timezone_list() ) {
|
||||
if ($tz =~ m/^$_$/i) {
|
||||
$realtz = $_;
|
||||
last;
|
||||
}
|
||||
}
|
||||
if ($realtz) {
|
||||
$ENV{TZ} = $realtz;
|
||||
}
|
||||
else {
|
||||
print "invalid timezone provided. Use -z to list valid timezones.\n";
|
||||
usage();
|
||||
}
|
||||
}
|
||||
# blindly take it otherwise
|
||||
else {
|
||||
$ENV{TZ} = $tz;
|
||||
}
|
||||
}
|
||||
else {
|
||||
print "-z requires the time zone argument\n";
|
||||
usage();
|
||||
}
|
||||
}
|
||||
else {
|
||||
print "Unknown option: $_\n";
|
||||
usage();
|
||||
}
|
||||
shift(@ARGV);
|
||||
}
|
||||
|
||||
# Was the time given
|
||||
if (defined $ARGV[0]) {
|
||||
my $t_in;
|
||||
my $t_out;
|
||||
|
||||
$TIME = $ARGV[0];
|
||||
if ($ARGV[0] =~ /\.\./) {
|
||||
($t_in, $t_out) = split(/\.\./, $ARGV[0]);
|
||||
}
|
||||
else {
|
||||
$t_in = $ARGV[0];
|
||||
$t_out = 0;
|
||||
}
|
||||
$in_seconds = parse_isodate($t_in);
|
||||
die "Invalid Date: $t_in\n" if ($in_seconds < 0);
|
||||
|
||||
if ($t_out) {
|
||||
$out_seconds = parse_isodate($t_out);
|
||||
die "Invalid Date: $t_out\n" if ($out_seconds < 0);
|
||||
}
|
||||
else {
|
||||
$out_seconds = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$in_seconds = 0;
|
||||
$out_seconds = 0;
|
||||
}
|
||||
|
||||
# Print header info
|
||||
print_header() if ($header == 1);
|
||||
|
||||
# Print the index header
|
||||
if ($INDEX ne "") {
|
||||
my $time_str = "";
|
||||
if ($INDEX_TYPE == $INDEX_DAY) {
|
||||
$time_str = "Daily";
|
||||
}
|
||||
else {
|
||||
$time_str = "Hourly";
|
||||
}
|
||||
if ($BODY ne "") {
|
||||
print INDEX "$time_str Summary for Timeline of $BODY\n\n";
|
||||
}
|
||||
else {
|
||||
print INDEX "$time_str Summary for Timeline of STDIN\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
read_body();
|
||||
|
||||
print_tl();
|
||||
|
||||
################ SUBROUTINES ##################
|
||||
|
||||
#convert yyyy-mm-dd string to Unix date
|
||||
sub parse_isodate {
|
||||
my $iso_date = shift;
|
||||
|
||||
my $sec = 0;
|
||||
my $min = 0;
|
||||
my $hour = 0;
|
||||
my $wday = 0;
|
||||
my $yday = 0;
|
||||
if ($iso_date =~ /^(\d\d\d\d)\-(\d\d)\-(\d\d)$/) {
|
||||
return mktime($sec, $min, $hour, $3, $2 - 1, $1 - 1900, $wday, $yday);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
# Read the body file from the BODY variable
|
||||
sub read_body {
|
||||
|
||||
# Read the body file from STDIN or the -b specified body file
|
||||
if ($BODY ne "") {
|
||||
open(BODY, "<$BODY") or die "Can't open $BODY";
|
||||
}
|
||||
else {
|
||||
open(BODY, "<&STDIN") or die "Can't dup STDIN";
|
||||
}
|
||||
|
||||
while (<BODY>) {
|
||||
next if ((/^\#/) || (/^\s+$/));
|
||||
|
||||
chomp;
|
||||
|
||||
my (
|
||||
$tmp1, $file, $st_ino, $st_ls,
|
||||
$st_uid, $st_gid, $st_size, $st_atime,
|
||||
$st_mtime, $st_ctime, $st_crtime, $tmp2
|
||||
)
|
||||
= &tm_split($_);
|
||||
|
||||
# Sanity check so that we ignore the header entries
|
||||
next unless ((defined $st_ino) && ($st_ino =~ /[\d-]+/));
|
||||
next unless ((defined $st_uid) && ($st_uid =~ /\d+/));
|
||||
next unless ((defined $st_gid) && ($st_gid =~ /\d+/));
|
||||
next unless ((defined $st_size) && ($st_size =~ /\d+/));
|
||||
next unless ((defined $st_mtime) && ($st_mtime =~ /\d+/));
|
||||
next unless ((defined $st_atime) && ($st_atime =~ /\d+/));
|
||||
next unless ((defined $st_ctime) && ($st_ctime =~ /\d+/));
|
||||
next unless ((defined $st_crtime) && ($st_crtime =~ /\d+/));
|
||||
|
||||
# we need *some* value in mactimes!
|
||||
next if (!$st_atime && !$st_mtime && !$st_ctime && !$st_crtime);
|
||||
|
||||
# Skip if these are all too early
|
||||
next
|
||||
if ( ($st_mtime < $in_seconds)
|
||||
&& ($st_atime < $in_seconds)
|
||||
&& ($st_ctime < $in_seconds)
|
||||
&& ($st_crtime < $in_seconds));
|
||||
|
||||
# add leading zeros to timestamps because we will later sort
|
||||
# these using a string-based comparison
|
||||
$st_mtime = sprintf("%.10d", $st_mtime);
|
||||
$st_atime = sprintf("%.10d", $st_atime);
|
||||
$st_ctime = sprintf("%.10d", $st_ctime);
|
||||
$st_crtime = sprintf("%.10d", $st_crtime);
|
||||
|
||||
# Put all the times in one big array along with the inode and
|
||||
# name (they are used in the final sorting)
|
||||
|
||||
# If the date on the file is too old, don't put it in the array
|
||||
my $post = ",$st_ino,$file";
|
||||
|
||||
if ($out_seconds) {
|
||||
$timestr2macstr{"$st_mtime$post"} .= "m"
|
||||
if (
|
||||
($st_mtime >= $in_seconds)
|
||||
&& ($st_mtime < $out_seconds)
|
||||
&& ( (!(exists $timestr2macstr{"$st_mtime$post"}))
|
||||
|| ($timestr2macstr{"$st_mtime$post"} !~ /m/))
|
||||
);
|
||||
|
||||
$timestr2macstr{"$st_atime$post"} .= "a"
|
||||
if (
|
||||
($st_atime >= $in_seconds)
|
||||
&& ($st_atime < $out_seconds)
|
||||
&& ( (!(exists $timestr2macstr{"$st_atime$post"}))
|
||||
|| ($timestr2macstr{"$st_atime$post"} !~ /a/))
|
||||
);
|
||||
|
||||
$timestr2macstr{"$st_ctime$post"} .= "c"
|
||||
if (
|
||||
($st_ctime >= $in_seconds)
|
||||
&& ($st_ctime < $out_seconds)
|
||||
&& ( (!(exists $timestr2macstr{"$st_ctime$post"}))
|
||||
|| ($timestr2macstr{"$st_ctime$post"} !~ /c/))
|
||||
);
|
||||
|
||||
$timestr2macstr{"$st_crtime$post"} .= "b"
|
||||
if (
|
||||
($st_crtime >= $in_seconds)
|
||||
&& ($st_crtime < $out_seconds)
|
||||
&& ( (!(exists $timestr2macstr{"$st_crtime$post"}))
|
||||
|| ($timestr2macstr{"$st_crtime$post"} !~ /b/))
|
||||
);
|
||||
}
|
||||
else {
|
||||
$timestr2macstr{"$st_mtime$post"} .= "m"
|
||||
if (
|
||||
($st_mtime >= $in_seconds)
|
||||
&& ( (!(exists $timestr2macstr{"$st_mtime$post"}))
|
||||
|| ($timestr2macstr{"$st_mtime$post"} !~ /m/))
|
||||
);
|
||||
|
||||
$timestr2macstr{"$st_atime$post"} .= "a"
|
||||
if (
|
||||
($st_atime >= $in_seconds)
|
||||
&& ( (!(exists $timestr2macstr{"$st_atime$post"}))
|
||||
|| ($timestr2macstr{"$st_atime$post"} !~ /a/))
|
||||
);
|
||||
|
||||
$timestr2macstr{"$st_ctime$post"} .= "c"
|
||||
if (
|
||||
($st_ctime >= $in_seconds)
|
||||
&& ( (!(exists $timestr2macstr{"$st_ctime$post"}))
|
||||
|| ($timestr2macstr{"$st_ctime$post"} !~ /c/))
|
||||
);
|
||||
|
||||
$timestr2macstr{"$st_crtime$post"} .= "b"
|
||||
if (
|
||||
($st_crtime >= $in_seconds)
|
||||
&& ( (!(exists $timestr2macstr{"$st_crtime$post"}))
|
||||
|| ($timestr2macstr{"$st_crtime$post"} !~ /b/))
|
||||
);
|
||||
}
|
||||
|
||||
# if the UID or GID is not in the array then add it.
|
||||
# these are filled if the -p or -g options are given
|
||||
$uid2names{$st_uid} = $st_uid
|
||||
unless (defined $uid2names{$st_uid});
|
||||
$gid2names{$st_gid} = $st_gid
|
||||
unless (defined $gid2names{$st_gid});
|
||||
|
||||
#
|
||||
# put /'s between multiple UID/GIDs
|
||||
#
|
||||
$uid2names{$st_uid} =~ s@\s@/@g;
|
||||
$gid2names{$st_gid} =~ s@\s@/@g;
|
||||
|
||||
$file2other{$file} =
|
||||
"$st_ls:$uid2names{$st_uid}:$gid2names{$st_gid}:$st_size";
|
||||
}
|
||||
|
||||
close BODY;
|
||||
} # end of read_body
|
||||
|
||||
sub print_header {
|
||||
return if ($header == 0);
|
||||
|
||||
print "The Sleuth Kit mactime Timeline\n";
|
||||
|
||||
print "Input Source: ";
|
||||
if ($BODY eq "") {
|
||||
print "STDIN\n";
|
||||
}
|
||||
else {
|
||||
print "$BODY\n";
|
||||
}
|
||||
|
||||
print "Time: $TIME\t\t" if ($TIME ne "");
|
||||
|
||||
if ($ENV{TZ} eq "") {
|
||||
print "\n";
|
||||
}
|
||||
else {
|
||||
print "Timezone: $ENV{TZ}\n";
|
||||
}
|
||||
|
||||
print "passwd File: $PASSWD" if ($PASSWD ne "");
|
||||
if ($GROUP ne "") {
|
||||
print "\t" if ($PASSWD ne "");
|
||||
print "group File: $GROUP";
|
||||
}
|
||||
print "\n" if (($PASSWD ne "") || ($GROUP ne ""));
|
||||
|
||||
print "\n";
|
||||
}
|
||||
|
||||
#
|
||||
# Print the time line
|
||||
#
|
||||
sub print_tl {
|
||||
|
||||
my $prev_day = ""; # has the format of 'day day_week mon year'
|
||||
my $prev_hour = ""; # has just the hour and is used for hourly index
|
||||
my $prev_cnt = 0;
|
||||
my $old_date_string = "";
|
||||
|
||||
my $delim = ":";
|
||||
if ($COMMA != 0) {
|
||||
print "Date,Size,Type,Mode,UID,GID,Meta,File Name\n";
|
||||
$delim = ",";
|
||||
}
|
||||
|
||||
# Cycle through the files and print them in sorted order.
|
||||
# Note that we sort using a string comparison because the keys
|
||||
# also contain the inode and file name
|
||||
for my $key (sort { $a cmp $b } keys %timestr2macstr) {
|
||||
my $time;
|
||||
my $inode;
|
||||
my $file;
|
||||
|
||||
if ($key =~ /^(\d+),([\d-]+),(.*)$/) {
|
||||
$time = $1;
|
||||
$inode = $2;
|
||||
$file = $3;
|
||||
}
|
||||
else {
|
||||
next;
|
||||
}
|
||||
|
||||
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
|
||||
if ($iso8601) {
|
||||
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
|
||||
gmtime($time);
|
||||
}
|
||||
else {
|
||||
($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
|
||||
localtime($time);
|
||||
}
|
||||
|
||||
# the month here is 0-11, not 1-12, like what we want
|
||||
$mon++;
|
||||
|
||||
print
|
||||
"\t($sec,$min,$hour,MDay: $mday,M: $mon,$year,$wday,$yday,$isdst) = ($time)\n"
|
||||
if $debug;
|
||||
|
||||
#
|
||||
# cosmetic change to make it look like unix dates
|
||||
#
|
||||
$mon = "0$mon" if $mon < 10;
|
||||
$mday = "0$mday" if $mday < 10;
|
||||
$hour = "0$hour" if $hour < 10;
|
||||
$min = "0$min" if $min < 10;
|
||||
$sec = "0$sec" if $sec < 10;
|
||||
|
||||
my $yeart = $year + 1900;
|
||||
|
||||
# How do we print the date?
|
||||
#
|
||||
my $date_string;
|
||||
if ($iso8601) {
|
||||
if ($time == 0) {
|
||||
$date_string = "0000-00-00T00:00:00Z";
|
||||
}
|
||||
else {
|
||||
$date_string =
|
||||
"$yeart-$mon-${mday}T$hour:$min:${sec}Z";
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($time == 0) {
|
||||
$date_string = "Xxx Xxx 00 0000 00:00:00";
|
||||
}
|
||||
elsif ($month_num) {
|
||||
$date_string =
|
||||
"$digit_to_day{$wday} $mon $mday $yeart $hour:$min:$sec";
|
||||
}
|
||||
else {
|
||||
$date_string =
|
||||
"$digit_to_day{$wday} $digit_to_month{$mon} $mday $yeart $hour:$min:$sec";
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# However, we only print the date if it's different from the one
|
||||
# above. We need to fill the empty space with blanks, though.
|
||||
#
|
||||
if ($old_date_string eq $date_string) {
|
||||
if ($iso8601) {
|
||||
$date_string = " ";
|
||||
}
|
||||
else {
|
||||
$date_string = " ";
|
||||
}
|
||||
$prev_cnt++
|
||||
if ($INDEX ne "");
|
||||
}
|
||||
else {
|
||||
$old_date_string = $date_string;
|
||||
|
||||
# Indexing code
|
||||
if ($INDEX ne "") {
|
||||
|
||||
# First time it is run
|
||||
if ($prev_day eq "") {
|
||||
$prev_day = "$mday $wday $mon $yeart";
|
||||
$prev_hour = $hour;
|
||||
$prev_cnt = 0;
|
||||
}
|
||||
|
||||
# A new day, so print the results
|
||||
elsif ($prev_day ne "$mday $wday $mon $yeart") {
|
||||
my @prev_vals = split(/ /, $prev_day);
|
||||
|
||||
my $date_str;
|
||||
if ($month_num) {
|
||||
$date_str =
|
||||
"$digit_to_day{$prev_vals[1]} "
|
||||
. "$prev_vals[2] "
|
||||
. "$prev_vals[0] ${prev_vals[3]}";
|
||||
}
|
||||
else {
|
||||
$date_str =
|
||||
"$digit_to_day{$prev_vals[1]} "
|
||||
. "$digit_to_month{$prev_vals[2]} "
|
||||
. "$prev_vals[0] ${prev_vals[3]}";
|
||||
}
|
||||
|
||||
$date_str .= " $prev_hour:00:00"
|
||||
if ($INDEX_TYPE == $INDEX_HOUR);
|
||||
|
||||
print INDEX "${date_str}${delim} $prev_cnt\n";
|
||||
|
||||
# Reset
|
||||
$prev_cnt = 0;
|
||||
$prev_day = "$mday $wday $mon $yeart";
|
||||
$prev_hour = $hour;
|
||||
|
||||
}
|
||||
|
||||
# Same day, but new hour
|
||||
elsif (($INDEX_TYPE == $INDEX_HOUR) && ($prev_hour != $hour)) {
|
||||
my @prev_vals = split(/ /, $prev_day);
|
||||
|
||||
if ($month_num) {
|
||||
print INDEX "$digit_to_day{$prev_vals[1]} "
|
||||
. "$prev_vals[2] "
|
||||
. "$prev_vals[0] ${prev_vals[3]} "
|
||||
. "$prev_hour:00:00${delim} $prev_cnt\n";
|
||||
}
|
||||
else {
|
||||
print INDEX "$digit_to_day{$prev_vals[1]} "
|
||||
. "$digit_to_month{$prev_vals[2]} "
|
||||
. "$prev_vals[0] ${prev_vals[3]} "
|
||||
. "$prev_hour:00:00${delim} $prev_cnt\n";
|
||||
}
|
||||
|
||||
# Reset
|
||||
$prev_cnt = 0;
|
||||
$prev_hour = $hour;
|
||||
}
|
||||
$prev_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Muck around with the [mac]times string to make it pretty.
|
||||
#
|
||||
my $mactime_tmp = $timestr2macstr{$key};
|
||||
my $mactime = "";
|
||||
if ($mactime_tmp =~ /m/) {
|
||||
$mactime = "m";
|
||||
}
|
||||
else {
|
||||
$mactime = ".";
|
||||
}
|
||||
|
||||
if ($mactime_tmp =~ /a/) {
|
||||
$mactime .= "a";
|
||||
}
|
||||
else {
|
||||
$mactime .= ".";
|
||||
}
|
||||
|
||||
if ($mactime_tmp =~ /c/) {
|
||||
$mactime .= "c";
|
||||
}
|
||||
else {
|
||||
$mactime .= ".";
|
||||
}
|
||||
|
||||
if ($mactime_tmp =~ /b/) {
|
||||
$mactime .= "b";
|
||||
}
|
||||
else {
|
||||
$mactime .= ".";
|
||||
}
|
||||
|
||||
my ($ls, $uids, $groups, $size) = split(/:/, $file2other{$file});
|
||||
|
||||
print "FILE: $file MODES: $ls U: $uids G: $groups S: $size\n"
|
||||
if $debug;
|
||||
|
||||
if ($COMMA == 0) {
|
||||
printf("%s %8s %3s %s %-8s %-8s %-8s %s\n",
|
||||
$date_string, $size, $mactime, $ls, $uids, $groups, $inode,
|
||||
$file);
|
||||
}
|
||||
else {
|
||||
# escape any quotes in filename
|
||||
my $file_tmp = $file;
|
||||
$file_tmp =~ s/\"/\"\"/g;
|
||||
printf("%s,%s,%s,%s,%s,%s,%s,\"%s\"\n",
|
||||
$old_date_string, $size, $mactime, $ls, $uids, $groups, $inode,
|
||||
$file_tmp);
|
||||
}
|
||||
}
|
||||
|
||||
# Finish the index page for the last entry
|
||||
if (($INDEX ne "") && ($prev_cnt > 0)) {
|
||||
my @prev_vals = split(/ /, $prev_day);
|
||||
|
||||
my $date_str;
|
||||
if ($month_num) {
|
||||
$date_str =
|
||||
"$digit_to_day{$prev_vals[1]} "
|
||||
. "$prev_vals[2] "
|
||||
. "$prev_vals[0] ${prev_vals[3]}";
|
||||
}
|
||||
else {
|
||||
$date_str =
|
||||
"$digit_to_day{$prev_vals[1]} "
|
||||
. "$digit_to_month{$prev_vals[2]} "
|
||||
. "$prev_vals[0] ${prev_vals[3]}";
|
||||
}
|
||||
|
||||
$date_str .= " $prev_hour:00:00"
|
||||
if ($INDEX_TYPE == $INDEX_HOUR);
|
||||
|
||||
print INDEX "${date_str}${delim} $prev_cnt\n";
|
||||
close INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Routines for reading and caching user and group information. These
|
||||
# are used in multiple programs... it caches the info once, then hopefully
|
||||
# won't be used again.
|
||||
#
|
||||
# Steve Romig, May 1991.
|
||||
#
|
||||
# Provides a bunch of routines and a bunch of arrays. Routines
|
||||
# (and their usage):
|
||||
#
|
||||
# load_passwd_info($use_getent, $file_name)
|
||||
#
|
||||
# loads user information into the %uname* and %uid* arrays
|
||||
# (see below).
|
||||
#
|
||||
# If $use_getent is non-zero:
|
||||
# get the info via repeated 'getpwent' calls. This can be
|
||||
# *slow* on some hosts, especially if they are running as a
|
||||
# YP (NIS) client.
|
||||
# If $use_getent is 0:
|
||||
# if $file_name is "", then get the info from reading the
|
||||
# results of "ypcat passwd" and from /etc/passwd. Otherwise,
|
||||
# read the named file. The file should be in passwd(5)
|
||||
# format.
|
||||
#
|
||||
# load_group_info($use_gentent, $file_name)
|
||||
#
|
||||
# is similar to load_passwd_info.
|
||||
#
|
||||
# Information is stored in several convenient associative arrays:
|
||||
#
|
||||
# %uid2names Assoc array, indexed by uid, value is list of
|
||||
# user names with that uid, in form "name name
|
||||
# name...".
|
||||
#
|
||||
# %gid2members Assoc array, indexed by gid, value is list of
|
||||
# group members in form "name name name..."
|
||||
#
|
||||
# %gname2gid Assoc array, indexed by group name, value is
|
||||
# matching gid.
|
||||
#
|
||||
# %gid2names Assoc array, indexed by gid, value is the
|
||||
# list of group names with that gid in form
|
||||
# "name name name...".
|
||||
#
|
||||
# You can also use routines named the same as the arrays - pass the index
|
||||
# as the arg, get back the value. If you use this, get{gr|pw}{uid|gid|nam}
|
||||
# will be used to lookup entries that aren't found in the cache.
|
||||
#
|
||||
# To be done:
|
||||
# probably ought to add routines to deal with full names.
|
||||
# maybe there ought to be some anal-retentive checking of password
|
||||
# and group entries.
|
||||
# probably ought to cache get{pw|gr}{nam|uid|gid} lookups also.
|
||||
# probably ought to avoid overwriting existing entries (eg, duplicate
|
||||
# names in password file would collide in the tables that are
|
||||
# indexed by name).
|
||||
#
|
||||
# Disclaimer:
|
||||
# If you use YP and you use netgroup entries such as
|
||||
# +@servers::::::
|
||||
# +:*:::::/usr/local/utils/messages
|
||||
# then loading the password file in with &load_passwd_info(0) will get
|
||||
# you mostly correct YP stuff *except* that it won't do the password and
|
||||
# shell substitutions as you'd expect. You might want to use
|
||||
# &load_passwd_info(1) instead to use getpwent calls to do the lookups,
|
||||
# which would be more correct.
|
||||
#
|
||||
#
|
||||
# minor changes to make it fit with the TCT program, 9/25/99, - dan
|
||||
# A whole lot removed to clean it up for TSK - July 2008 - Brian
|
||||
#
|
||||
|
||||
package main;
|
||||
|
||||
my $passwd_loaded = 0; # flags to use to avoid reloading everything
|
||||
my $group_loaded = 0; # unnecessarily...
|
||||
|
||||
#
|
||||
# Update user information for the user named $name. We cache the password,
|
||||
# uid, login group, home directory and shell.
|
||||
#
|
||||
|
||||
sub add_pw_info {
|
||||
my ($name, $tmp, $uid) = @_;
|
||||
|
||||
if ((defined $name) && ($name ne "")) {
|
||||
|
||||
if ((defined $uid) && ($uid ne "")) {
|
||||
if (defined($uid2names{$uid})) {
|
||||
$uid2names{$uid} .= " $name";
|
||||
}
|
||||
else {
|
||||
$uid2names{$uid} = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Update group information for the group named $name. We cache the gid
|
||||
# and the list of group members.
|
||||
#
|
||||
|
||||
sub add_gr_info {
|
||||
my ($name, $tmp, $gid) = @_;
|
||||
|
||||
if ((defined $name) && ($name ne "")) {
|
||||
|
||||
if ((defined $gid) && ($gid ne "")) {
|
||||
if (defined($gid2names{$gid})) {
|
||||
$gid2names{$gid} .= " $name";
|
||||
}
|
||||
else {
|
||||
$gid2names{$gid} = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub load_passwd_info {
|
||||
my ($file_name) = @_;
|
||||
my (@pw_info);
|
||||
|
||||
if ($passwd_loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
$passwd_loaded = 1;
|
||||
|
||||
open(FILE, $file_name)
|
||||
|| die "can't open $file_name";
|
||||
|
||||
while (<FILE>) {
|
||||
chop;
|
||||
|
||||
if ($_ !~ /^\+/) {
|
||||
&add_pw_info(split(/:/));
|
||||
}
|
||||
}
|
||||
close(FILE);
|
||||
}
|
||||
|
||||
sub load_group_info {
|
||||
my ($file_name) = @_;
|
||||
my (@gr_info);
|
||||
|
||||
if ($group_loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
$group_loaded = 1;
|
||||
|
||||
open(FILE, $file_name)
|
||||
|| die "can't open $file_name";
|
||||
|
||||
while (<FILE>) {
|
||||
chop;
|
||||
if ($_ !~ /^\+/) {
|
||||
&add_gr_info(split(/:/));
|
||||
}
|
||||
}
|
||||
close(FILE);
|
||||
}
|
||||
|
||||
#
|
||||
# Split a time machine record.
|
||||
#
|
||||
sub tm_split {
|
||||
my ($line) = @_;
|
||||
my (@fields);
|
||||
|
||||
for (@fields = split(/\|/, $line)) {
|
||||
s/%([A-F0-9][A-F0-9])/pack("C", hex($1))/egis;
|
||||
}
|
||||
return @fields;
|
||||
}
|
||||
1;
|
||||
|
@ -1046,7 +1046,7 @@ public class Timeline extends CallableSystemAction implements Presenter.Toolbar,
|
||||
pathToBodyFile = PlatformUtil.getOSFilePath(pathToBodyFile);
|
||||
if (PlatformUtil.isWindowsOS()) {
|
||||
macpath = machome + java.io.File.separator + "mactime.exe";
|
||||
cmdpath = PlatformUtil.getOSFilePath(cmdpath);
|
||||
cmdpath = PlatformUtil.getOSFilePath(macpath);
|
||||
mactimeArgs = new String[]{"-b", pathToBodyFile, "-d", "-y"};
|
||||
} else {
|
||||
cmdpath = "perl";
|
||||
|
@ -71,20 +71,13 @@
|
||||
<var name="extra-bin-name" value="${app.name}64.exe"/>
|
||||
<var name="aut-bin-name" value="${app.name}.exe"/>
|
||||
<var name="jre-path" value="${env.JRE_HOME_32}"/>
|
||||
<var name="package-type" value="x86" />
|
||||
<antcall target="run-ai-32" inheritAll="true" inheritRefs="true" />
|
||||
<delete dir="${nbdist.dir}/installer_${app.name}_32-cache"/>
|
||||
<move file="${nbdist.dir}/installer_${app.name}_32-SetupFiles/installer_${app.name}_32.msi" tofile="${nbdist.dir}/installer_${app.name}_32-${app.version}.msi" />
|
||||
</target>
|
||||
|
||||
<target name="run-ai-32" depends="add-ai-productinfo,add-ai-files,add-ai-jre,add-ai-shortcuts,add-ai-env" description="Builds the 64 bit installer.">
|
||||
<!-- Leaving this commented out bit for documentation purposes. Not sure what its supposed to do. -->
|
||||
<!-- Need to find a way to deal with beta version -->
|
||||
<!--<echo message="Setting ${app.name} version to ${app.version}..."/>
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /SetVersion ${app.version}"/>
|
||||
</exec>-->
|
||||
<!--<delete file="${aip-path}"/>-->
|
||||
</target>
|
||||
<target name="run-ai-32" depends="add-ai-productinfo,add-ai-files,add-ai-jre,add-ai-shortcuts,add-ai-env,ai-build" description="Builds the 32 bit installer."/>
|
||||
|
||||
<target name="check-ai-64" if="jre.home.64" description="Builds the 64 bit installer IF JRE_HOME_64 is set.">
|
||||
<property environment="env"/>
|
||||
@ -92,13 +85,14 @@
|
||||
<var name="extra-bin-name" value="${app.name}.exe"/>
|
||||
<var name="aut-bin-name" value="${app.name}64.exe"/>
|
||||
<var name="jre-path" value="${env.JRE_HOME_64}"/>
|
||||
<var name="package-type" value="x64" />
|
||||
<echo message="aip-path: ${aip-path}" />
|
||||
<antcall target="run-ai-64" inheritAll="true" inheritRefs="true" />
|
||||
<delete dir="${nbdist.dir}/installer_${app.name}_64-cache"/>
|
||||
<move file="${nbdist.dir}/installer_${app.name}_64-SetupFiles/installer_${app.name}_64.msi" tofile="${nbdist.dir}/installer_${app.name}_64-${app.version}.msi" />
|
||||
</target>
|
||||
|
||||
<target name="run-ai-64" depends="add-ai-productinfo,add-ai-files,add-ai-jre,add-ai-shortcuts,add-ai-env" description="Builds the 64 bit installer."/>
|
||||
<target name="run-ai-64" depends="add-ai-productinfo,add-ai-files,add-ai-jre,add-ai-shortcuts,ai-set-type,ai-build" description="Builds the 64 bit installer."/>
|
||||
|
||||
<target name="add-ai-productinfo" description="Add product information to the aip file">
|
||||
<scriptdef name="generateguid" language="javascript">
|
||||
@ -185,8 +179,17 @@
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /NewEnvironment -name PATH -value %GSTREAMER_PATH% -install_operation CreateUpdate -behavior Append -system_variable"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="ai-build" description="Build the installer.">
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/build ${aip-path}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="ai-set-type" description="Set the installer to only install on 64 bit machines.">
|
||||
<exec executable="${ai-exe-path}">
|
||||
<arg line="/edit ${aip-path} /SetPackageType ${package-type}"/>
|
||||
</exec>
|
||||
</target>
|
||||
</project>
|
||||
|
Loading…
x
Reference in New Issue
Block a user