mirror of
https://github.com/elisspace/autopsy.git
synced 2026-09-06 02:24:30 +00:00
Merge branch 'master' of github.com:sleuthkit/autopsy
This commit is contained in:
@@ -56,7 +56,7 @@ import org.sleuthkit.datamodel.SleuthkitJNI.CaseDbHandle.AddImageProcess;
|
||||
* open at a time. Use getCurrentCase() to retrieve the object for the current
|
||||
* case.
|
||||
*/
|
||||
public class Case {
|
||||
public class Case implements SleuthkitCase.ErrorObserver {
|
||||
|
||||
private static final String autopsyVer = Version.getVersion(); // current version of autopsy. Change it when the version is changed
|
||||
private static final String appName = Version.getName() + " " + autopsyVer;
|
||||
@@ -130,6 +130,7 @@ public class Case {
|
||||
this.xmlcm = xmlcm;
|
||||
this.db = db;
|
||||
this.services = new Services(db);
|
||||
db.addErrorObserver(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -983,4 +984,9 @@ public class Case {
|
||||
CoreComponentControl.closeCoreWindows();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveError(String context, String errorMessage) {
|
||||
MessageNotifyUtil.Notify.error(context, errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
*
|
||||
* @author jantonius
|
||||
*/
|
||||
@ServiceProvider(service = CaseNewAction.class)
|
||||
public final class CaseNewAction implements ActionListener {
|
||||
@ServiceProvider(service = CaseNewActionInterface.class)
|
||||
public final class CaseNewAction implements CaseNewActionInterface {
|
||||
|
||||
private NewCaseWizardAction wizard = SystemAction.get(NewCaseWizardAction.class);
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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.casemodule;
|
||||
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public interface CaseNewActionInterface extends ActionListener {
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.1" encoding="UTF-8" ?>
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<AuxValues>
|
||||
@@ -36,7 +36,7 @@
|
||||
<Component id="autopsyLogo" alignment="0" min="-2" pref="257" max="-2" attributes="0"/>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="editorPanel" min="-2" max="-2" attributes="1"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Component id="closeButton" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
@@ -65,16 +65,16 @@
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="createNewLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="openCaseButton" min="-2" max="-2" attributes="1"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="openLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<Component id="openRecentButton" min="-2" pref="70" max="-2" attributes="1"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="openRecentLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Component id="openCaseButton" min="-2" max="-2" attributes="1"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="openLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace pref="60" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
@@ -83,37 +83,22 @@
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="-2" pref="32" max="-2" attributes="0"/>
|
||||
<Component id="newCaseButton" min="-2" pref="56" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="50" max="-2" attributes="0"/>
|
||||
<Component id="createNewLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="32" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="2" attributes="0">
|
||||
<Component id="createNewLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="newCaseButton" alignment="2" min="-2" pref="56" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="-2" max="-2" attributes="0"/>
|
||||
<Component id="openCaseButton" min="-2" pref="58" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="31" max="-2" attributes="0"/>
|
||||
<Component id="openLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="2" attributes="0">
|
||||
<Component id="openRecentLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="openRecentButton" alignment="2" min="-2" pref="70" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="openRecentButton" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" alignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="32" max="-2" attributes="0"/>
|
||||
<Component id="openRecentLabel" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="2" attributes="0">
|
||||
<Component id="openLabel" alignment="2" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="openCaseButton" alignment="2" min="-2" pref="58" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
<EmptySpace pref="25" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
@@ -140,30 +125,6 @@
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="newCaseButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="openCaseButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.openCaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="null" type="code"/>
|
||||
</Property>
|
||||
<Property name="borderPainted" type="boolean" value="false"/>
|
||||
<Property name="contentAreaFilled" type="boolean" value="false"/>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[1, 1, 1, 1]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[70, 70]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openCaseButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="openRecentButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
@@ -195,16 +156,6 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="openLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="13" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.openLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="openRecentLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
@@ -215,6 +166,40 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="openCaseButton">
|
||||
<Properties>
|
||||
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
|
||||
<Image iconType="3" name="/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.openCaseButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="null" type="code"/>
|
||||
</Property>
|
||||
<Property name="borderPainted" type="boolean" value="false"/>
|
||||
<Property name="contentAreaFilled" type="boolean" value="false"/>
|
||||
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
|
||||
<Insets value="[1, 1, 1, 1]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[70, 70]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="openCaseButtonActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="openLabel">
|
||||
<Properties>
|
||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||
<Font name="Tahoma" size="13" style="0"/>
|
||||
</Property>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/Bundle.properties" key="CueBannerPanel.openLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Component class="javax.swing.JLabel" name="autopsyLogo">
|
||||
|
||||
@@ -29,6 +29,7 @@ import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import org.openide.util.Lookup;
|
||||
import org.sleuthkit.autopsy.coreutils.Version;
|
||||
import org.netbeans.api.options.OptionsDisplayer;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -61,11 +62,11 @@ public class CueBannerPanel extends javax.swing.JPanel {
|
||||
closeButton = new javax.swing.JButton();
|
||||
editorPanel = new javax.swing.JPanel();
|
||||
newCaseButton = new javax.swing.JButton();
|
||||
openCaseButton = new javax.swing.JButton();
|
||||
openRecentButton = new javax.swing.JButton();
|
||||
createNewLabel = new javax.swing.JLabel();
|
||||
openLabel = new javax.swing.JLabel();
|
||||
openRecentLabel = new javax.swing.JLabel();
|
||||
openCaseButton = new javax.swing.JButton();
|
||||
openLabel = new javax.swing.JLabel();
|
||||
autopsyLogo = new javax.swing.JLabel();
|
||||
this.autopsyLogo.setText("");
|
||||
|
||||
@@ -83,6 +84,24 @@ public class CueBannerPanel extends javax.swing.JPanel {
|
||||
}
|
||||
});
|
||||
|
||||
openRecentButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_recent.png"))); // NOI18N
|
||||
openRecentButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openRecentButton.text")); // NOI18N
|
||||
openRecentButton.setBorder(null);
|
||||
openRecentButton.setBorderPainted(false);
|
||||
openRecentButton.setContentAreaFilled(false);
|
||||
openRecentButton.setPreferredSize(new java.awt.Dimension(70, 70));
|
||||
openRecentButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
openRecentButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
createNewLabel.setFont(new java.awt.Font("Tahoma", 0, 13)); // NOI18N
|
||||
createNewLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.createNewLabel.text")); // NOI18N
|
||||
|
||||
openRecentLabel.setFont(new java.awt.Font("Tahoma", 0, 13)); // NOI18N
|
||||
openRecentLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openRecentLabel.text")); // NOI18N
|
||||
|
||||
openCaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_existing.png"))); // NOI18N
|
||||
openCaseButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openCaseButton.text")); // NOI18N
|
||||
openCaseButton.setBorder(null);
|
||||
@@ -96,27 +115,9 @@ public class CueBannerPanel extends javax.swing.JPanel {
|
||||
}
|
||||
});
|
||||
|
||||
openRecentButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/btn_icon_open_recent.png"))); // NOI18N
|
||||
openRecentButton.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openRecentButton.text")); // NOI18N
|
||||
openRecentButton.setBorder(null);
|
||||
openRecentButton.setBorderPainted(false);
|
||||
openRecentButton.setContentAreaFilled(false);
|
||||
openRecentButton.setPreferredSize(new java.awt.Dimension(70, 70));
|
||||
openRecentButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
openRecentButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
|
||||
createNewLabel.setFont(new java.awt.Font("Tahoma", 0, 13));
|
||||
createNewLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.createNewLabel.text")); // NOI18N
|
||||
|
||||
openLabel.setFont(new java.awt.Font("Tahoma", 0, 13));
|
||||
openLabel.setFont(new java.awt.Font("Tahoma", 0, 13)); // NOI18N
|
||||
openLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openLabel.text")); // NOI18N
|
||||
|
||||
openRecentLabel.setFont(new java.awt.Font("Tahoma", 0, 13));
|
||||
openRecentLabel.setText(org.openide.util.NbBundle.getMessage(CueBannerPanel.class, "CueBannerPanel.openRecentLabel.text")); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout editorPanelLayout = new javax.swing.GroupLayout(editorPanel);
|
||||
editorPanel.setLayout(editorPanelLayout);
|
||||
editorPanelLayout.setHorizontalGroup(
|
||||
@@ -127,41 +128,32 @@ public class CueBannerPanel extends javax.swing.JPanel {
|
||||
.addComponent(newCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(createNewLabel))
|
||||
.addGroup(editorPanelLayout.createSequentialGroup()
|
||||
.addComponent(openCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(openLabel))
|
||||
.addGroup(editorPanelLayout.createSequentialGroup()
|
||||
.addComponent(openRecentButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(openRecentLabel)))
|
||||
.addComponent(openRecentLabel))
|
||||
.addGroup(editorPanelLayout.createSequentialGroup()
|
||||
.addComponent(openCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(openLabel)))
|
||||
.addContainerGap(60, Short.MAX_VALUE))
|
||||
);
|
||||
editorPanelLayout.setVerticalGroup(
|
||||
editorPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(editorPanelLayout.createSequentialGroup()
|
||||
.addGroup(editorPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(editorPanelLayout.createSequentialGroup()
|
||||
.addGap(32, 32, 32)
|
||||
.addComponent(newCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(editorPanelLayout.createSequentialGroup()
|
||||
.addGap(50, 50, 50)
|
||||
.addComponent(createNewLabel)))
|
||||
.addGroup(editorPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(editorPanelLayout.createSequentialGroup()
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(openCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(editorPanelLayout.createSequentialGroup()
|
||||
.addGap(31, 31, 31)
|
||||
.addComponent(openLabel)))
|
||||
.addGroup(editorPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(editorPanelLayout.createSequentialGroup()
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(openRecentButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGroup(editorPanelLayout.createSequentialGroup()
|
||||
.addGap(32, 32, 32)
|
||||
.addComponent(openRecentLabel)))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addGap(32, 32, 32)
|
||||
.addGroup(editorPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
|
||||
.addComponent(createNewLabel)
|
||||
.addComponent(newCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(editorPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
|
||||
.addComponent(openRecentLabel)
|
||||
.addComponent(openRecentButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGap(0, 0, Short.MAX_VALUE)
|
||||
.addGroup(editorPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
|
||||
.addComponent(openLabel)
|
||||
.addComponent(openCaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addContainerGap(25, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
autopsyLogo.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/casemodule/welcome_logo.png"))); // NOI18N
|
||||
@@ -188,14 +180,14 @@ public class CueBannerPanel extends javax.swing.JPanel {
|
||||
.addComponent(autopsyLogo, javax.swing.GroupLayout.PREFERRED_SIZE, 257, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(editorPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGap(18, 18, 18)
|
||||
.addComponent(closeButton)))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void newCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newCaseButtonActionPerformed
|
||||
Lookup.getDefault().lookup(CaseNewAction.class).actionPerformed(evt);
|
||||
Lookup.getDefault().lookup(CaseNewActionInterface.class).actionPerformed(evt);
|
||||
}//GEN-LAST:event_newCaseButtonActionPerformed
|
||||
|
||||
private void openCaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openCaseButtonActionPerformed
|
||||
@@ -255,6 +247,15 @@ public class CueBannerPanel extends javax.swing.JPanel {
|
||||
closeButton.addActionListener(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Close button label (default is "Close").
|
||||
*
|
||||
* @param text The new label for the button.
|
||||
*/
|
||||
public void setCloseButtonText(String text) {
|
||||
closeButton.setText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the open recent cases window.
|
||||
*/
|
||||
|
||||
@@ -43,6 +43,7 @@ public class IngestMonitor {
|
||||
private Timer timer;
|
||||
private static final java.util.logging.Logger MONITOR_LOGGER = java.util.logging.Logger.getLogger("monitor");
|
||||
private MonitorAction monitor;
|
||||
public static final int DISK_FREE_SPACE_UNKNOWN = -1;
|
||||
|
||||
IngestMonitor() {
|
||||
|
||||
@@ -101,7 +102,7 @@ public class IngestMonitor {
|
||||
return monitor.getFreeSpace();
|
||||
} catch (SecurityException e) {
|
||||
logger.log(Level.WARNING, "Error checking for free disk space on ingest data drive", e);
|
||||
return -1;
|
||||
return DISK_FREE_SPACE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +110,7 @@ public class IngestMonitor {
|
||||
private class MonitorAction implements ActionListener {
|
||||
|
||||
private final static long MIN_FREE_DISK_SPACE = 100L * 1024 * 1024; //100MB
|
||||
private File root = new File(File.separator); //default, roto dir where autopsy runs
|
||||
private File root = new File(File.separator); //default, root dir where autopsy runs
|
||||
|
||||
MonitorAction() {
|
||||
//find drive where case is located
|
||||
@@ -170,12 +171,25 @@ public class IngestMonitor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get free space in bytes of the drive where case dir resides
|
||||
* Get free space in bytes of the drive where case dir resides, or -1 if
|
||||
* unknown
|
||||
*
|
||||
* @return free space in bytes
|
||||
*/
|
||||
private long getFreeSpace() throws SecurityException {
|
||||
return root.getFreeSpace();
|
||||
final long freeSpace = root.getFreeSpace();
|
||||
|
||||
if (freeSpace == 0) {
|
||||
//check if network drive, some network filesystems always return 0
|
||||
final String monitoredPath = root.getAbsolutePath();
|
||||
if (monitoredPath.startsWith("\\\\") || monitoredPath.startsWith("//")) {
|
||||
return DISK_FREE_SPACE_UNKNOWN;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return freeSpace;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,8 +205,13 @@ public class IngestMonitor {
|
||||
logger.log(Level.WARNING, "Unable to check for free disk space (permission issue)", e);
|
||||
return true; //OK
|
||||
}
|
||||
//logger.log(Level.INFO, "Checking free disk apce: " + freeSpace + " need: " + Long.toString(MIN_FREE_DISK_SPACE));
|
||||
return freeSpace > MIN_FREE_DISK_SPACE;
|
||||
|
||||
if (freeSpace == DISK_FREE_SPACE_UNKNOWN) {
|
||||
return true;
|
||||
} else {
|
||||
//logger.log(Level.INFO, "Checking free disk apce: " + freeSpace + " need: " + Long.toString(MIN_FREE_DISK_SPACE));
|
||||
return freeSpace > MIN_FREE_DISK_SPACE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -399,10 +399,10 @@ public class ReportHTML implements TableReportModule {
|
||||
try {
|
||||
AbstractFile file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(sourceArtifact.getObjectID());
|
||||
|
||||
// Don't make a local copy of the file if it is unallocated space or a virtual directory.
|
||||
if (file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS ||
|
||||
file.getType() == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS ||
|
||||
file.getType() == TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR) {
|
||||
// Don't make a local copy of the file if it is a directory or unallocated space.
|
||||
if (file.isDir() ||
|
||||
file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS ||
|
||||
file.getType() == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) {
|
||||
row.add("");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2012 Basis Technology Corp.
|
||||
* Copyright 2013 Basis Technology Corp.
|
||||
*
|
||||
* Copyright 2012 42six Solutions.
|
||||
* Contact: aebadirad <at> 42six <dot> com
|
||||
@@ -30,7 +30,6 @@ import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
@@ -59,47 +58,12 @@ public final class ReportWizardAction extends CallableSystemAction implements P
|
||||
private JButton toolbarButton = new JButton();
|
||||
private static final String ACTION_NAME = "Generate Report";
|
||||
|
||||
public ReportWizardAction() {
|
||||
setEnabled(false);
|
||||
Case.addPropertyChangeListener(new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (evt.getPropertyName().equals(Case.CASE_CURRENT_CASE)) {
|
||||
Case newCase = (Case) evt.getNewValue();
|
||||
setEnabled(newCase != null);
|
||||
|
||||
// Make the cases' Reoports folder, if it doesn't exist
|
||||
if (newCase != null) {
|
||||
boolean exists = (new File(newCase.getCaseDirectory() + File.separator + "Reports")).exists();
|
||||
if (!exists) {
|
||||
boolean reportCreate = (new File(newCase.getCaseDirectory() + File.separator + "Reports")).mkdirs();
|
||||
if (!reportCreate) {
|
||||
logger.log(Level.WARNING, "Could not create Reports directory for case. It does not exist.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize the Generate Report button
|
||||
toolbarButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
ReportWizardAction.this.actionPerformed(e);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* When the Generate Report button or menu item is selected, open the reporting wizard.
|
||||
* When the wizard is finished, create a ReportGenerator with the wizard information,
|
||||
* and start all necessary reports.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
public static void doReportWizard() {
|
||||
// Create the wizard
|
||||
WizardDescriptor wiz = new WizardDescriptor(new ReportWizardIterator());
|
||||
wiz.setTitleFormat(new MessageFormat("{0} {1}"));
|
||||
@@ -133,7 +97,45 @@ public final class ReportWizardAction extends CallableSystemAction implements P
|
||||
|
||||
// Open the progress window for the user
|
||||
generator.displayProgressPanels();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ReportWizardAction() {
|
||||
setEnabled(false);
|
||||
Case.addPropertyChangeListener(new PropertyChangeListener() {
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (evt.getPropertyName().equals(Case.CASE_CURRENT_CASE)) {
|
||||
Case newCase = (Case) evt.getNewValue();
|
||||
setEnabled(newCase != null);
|
||||
|
||||
// Make the cases' Reoports folder, if it doesn't exist
|
||||
if (newCase != null) {
|
||||
boolean exists = (new File(newCase.getCaseDirectory() + File.separator + "Reports")).exists();
|
||||
if (!exists) {
|
||||
boolean reportCreate = (new File(newCase.getCaseDirectory() + File.separator + "Reports")).mkdirs();
|
||||
if (!reportCreate) {
|
||||
logger.log(Level.WARNING, "Could not create Reports directory for case. It does not exist.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize the Generate Report button
|
||||
toolbarButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
ReportWizardAction.this.actionPerformed(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
doReportWizard();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
0
RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java
Executable file → Normal file
0
RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java
Executable file → Normal file
@@ -49,6 +49,7 @@ import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||
import org.sleuthkit.autopsy.ingest.PipelineContext;
|
||||
import org.sleuthkit.autopsy.ingest.IngestMessage;
|
||||
import org.sleuthkit.autopsy.ingest.IngestMonitor;
|
||||
import org.sleuthkit.autopsy.ingest.ModuleContentEvent;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
@@ -426,7 +427,7 @@ public final class SevenZipIngestModule extends IngestModuleAbstractFile {
|
||||
|
||||
//check if unpacking this file will result in out of disk space
|
||||
//this is additional to zip bomb prevention mechanism
|
||||
if (freeDiskSpace != -1 && size > 0) { //if known free space and file not empty
|
||||
if (freeDiskSpace != IngestMonitor.DISK_FREE_SPACE_UNKNOWN && size > 0) { //if known free space and file not empty
|
||||
long newDiskSpace = freeDiskSpace - size;
|
||||
if (newDiskSpace < MIN_FREE_DISK_SPACE) {
|
||||
String msg = "Not enough disk space to unpack archive item: " + archiveFile.getName() + ", " + fileName;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#Updated by build script
|
||||
#Sun, 02 Jun 2013 00:12:29 -0400
|
||||
#Thu, 25 Jul 2013 15:34:25 -0400
|
||||
LBL_splash_window_title=Starting Autopsy
|
||||
SPLASH_HEIGHT=288
|
||||
SPLASH_WIDTH=538
|
||||
@@ -8,4 +8,4 @@ SplashRunningTextBounds=5,266,530,17
|
||||
SplashRunningTextColor=0x0
|
||||
SplashRunningTextFontSize=18
|
||||
|
||||
currentVersion=Autopsy 20130602
|
||||
currentVersion=Autopsy 20130725
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#Updated by build script
|
||||
#Thu, 23 May 2013 00:04:58 -0400
|
||||
#Thu, 25 Jul 2013 15:34:25 -0400
|
||||
|
||||
CTL_MainWindow_Title=Autopsy 20130523
|
||||
CTL_MainWindow_Title_No_Project=Autopsy 20130523
|
||||
CTL_MainWindow_Title=Autopsy 20130725
|
||||
CTL_MainWindow_Title_No_Project=Autopsy 20130725
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
# 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.
|
||||
|
||||
from tskdbdiff import TskDbDiff, TskDbDiffException
|
||||
import codecs
|
||||
import datetime
|
||||
import logging
|
||||
@@ -190,7 +190,8 @@ class TestRunner(object):
|
||||
|
||||
try:
|
||||
# Dump the database before we diff or use it for rebuild
|
||||
TskDbDiff.dump_output_db(test_data)
|
||||
TskDbDiff.dump_output_db(test_data.get_db_path(DBType.OUTPUT), test_data.get_db_dump_path(DBType.OUTPUT),
|
||||
test_data.get_sorted_data_path(DBType.OUTPUT))
|
||||
except sqlite3.OperationalError as e:
|
||||
print("Ingest did not run properly.",
|
||||
"Make sure no other instances of Autopsy are open and try again.")
|
||||
@@ -221,8 +222,7 @@ class TestRunner(object):
|
||||
|
||||
TestResultsDiffer.run_diff(test_data)
|
||||
test_data.overall_passed = (test_data.html_report_passed and
|
||||
test_data.errors_diff_passed and test_data.sorted_data_passed and
|
||||
test_data.db_dump_passed and test_data.db_diff_results.passed)
|
||||
test_data.errors_diff_passed and test_data.db_diff_passed)
|
||||
|
||||
Reports.generate_reports(test_data)
|
||||
if(not test_data.overall_passed):
|
||||
@@ -396,10 +396,9 @@ class TestData(object):
|
||||
gold_archive: a pathto_File, the gold standard archive
|
||||
logs_dir: a pathto_Dir, the location where autopsy logs are stored
|
||||
solr_index: a pathto_Dir, the locatino of the solr index
|
||||
db_diff_results: a DiffResults, the results of the database comparison
|
||||
html_report_passed: a boolean, did the HTML report diff pass?
|
||||
errors_diff_passed: a boolean, did the error diff pass?
|
||||
db_dump_passed: a boolean, did the db dump diff pass?
|
||||
db_diff_passed: a boolean, did the db diff pass?
|
||||
overall_passed: a boolean, did the test pass?
|
||||
total_test_time: a String representation of the test duration
|
||||
start_date: a String representation of this TestData's start date
|
||||
@@ -448,11 +447,9 @@ class TestData(object):
|
||||
self.solr_index = make_path(self.output_path, AUTOPSY_TEST_CASE,
|
||||
"ModuleOutput", "KeywordSearch")
|
||||
# Results and Info
|
||||
self.db_diff_results = None
|
||||
self.html_report_passed = False
|
||||
self.errors_diff_passed = False
|
||||
self.sorted_data_passed = False
|
||||
self.db_dump_passed = False
|
||||
self.db_diff_passed = False
|
||||
self.overall_passed = False
|
||||
# Ingest info
|
||||
self.total_test_time = ""
|
||||
@@ -603,7 +600,7 @@ class TestConfiguration(object):
|
||||
timer = 0
|
||||
self.images = []
|
||||
# Email info
|
||||
self.email_enabled = False
|
||||
self.email_enabled = args.email_enabled
|
||||
self.mail_server = ""
|
||||
self.mail_to = ""
|
||||
self.mail_subject = ""
|
||||
@@ -713,356 +710,12 @@ class TestConfiguration(object):
|
||||
if subject_elements:
|
||||
subject = subject_elements[0]
|
||||
self.mail_subject = subject.getAttribute("value").encode().decode("utf_8")
|
||||
if self.mail_server and self.mail_to:
|
||||
if self.mail_server and self.mail_to and self.args.email_enabled:
|
||||
self.email_enabled = True
|
||||
|
||||
|
||||
|
||||
class TskDbDiff(object):
|
||||
"""Represents the differences between the gold and output databases.
|
||||
|
||||
Contains methods to compare two databases.
|
||||
|
||||
Attributes:
|
||||
gold_artifacts:
|
||||
autopsy_artifacts:
|
||||
gold_attributes:
|
||||
autopsy_attributes:
|
||||
gold_objects:
|
||||
autopsy_objects:
|
||||
artifact_comparison:
|
||||
attribute_comparision:
|
||||
report_errors: a listof_listof_String, the error messages that will be
|
||||
printed to screen in the run_diff method
|
||||
passed: a boolean, did the diff pass?
|
||||
autopsy_db_file:
|
||||
gold_db_file:
|
||||
"""
|
||||
def __init__(self, output_db_path, gold_db_path):
|
||||
"""Constructor for TskDbDiff.
|
||||
|
||||
Args:
|
||||
output_db_path: a pathto_File, the output database
|
||||
gold_db_path: a pathto_File, the gold database
|
||||
"""
|
||||
self.gold_artifacts = []
|
||||
self.autopsy_artifacts = []
|
||||
self.gold_attributes = 0
|
||||
self.autopsy_attributes = 0
|
||||
self.gold_objects = 0
|
||||
self.autopsy_objects = 0
|
||||
self.artifact_comparison = []
|
||||
self.attribute_comparison = []
|
||||
self.report_errors = []
|
||||
self.autopsy_db_file = output_db_path
|
||||
self.gold_db_file = gold_db_path
|
||||
|
||||
def _get_artifacts(self, cursor):
|
||||
"""Get a list of artifacts from the given SQLCursor.
|
||||
|
||||
Args:
|
||||
cursor: SQLCursor - the cursor to execute on
|
||||
|
||||
Returns:
|
||||
listof_Artifact - the artifacts found by the query
|
||||
"""
|
||||
cursor.execute("SELECT COUNT(*) FROM blackboard_artifact_types")
|
||||
length = cursor.fetchone()[0] + 1
|
||||
artifacts = []
|
||||
for type_id in range(1, length):
|
||||
cursor.execute("SELECT COUNT(*) FROM blackboard_artifacts WHERE artifact_type_id=%d" % type_id)
|
||||
artifacts.append(cursor.fetchone()[0])
|
||||
return artifacts
|
||||
|
||||
def _count_attributes(self, cursor):
|
||||
"""Count the attributes from the given SQLCursor.
|
||||
|
||||
Args:
|
||||
cursor: SQLCursor - the cursor to execute on
|
||||
|
||||
Returns:
|
||||
Nat - the number of attributes found by the query
|
||||
"""
|
||||
cursor.execute("SELECT COUNT(*) FROM blackboard_attributes")
|
||||
return cursor.fetchone()[0]
|
||||
|
||||
def _count_objects(self, cursor):
|
||||
"""Count the objects from the given SQLCursor.
|
||||
|
||||
Args:
|
||||
cursor: SQLCursor - the cursor to execute on
|
||||
|
||||
Returns:
|
||||
Nat - the number of objects found by the query
|
||||
"""
|
||||
cursor.execute("SELECT COUNT(*) FROM tsk_objects")
|
||||
return cursor.fetchone()[0]
|
||||
|
||||
def _compare_bb_artifacts(self):
|
||||
"""Compares the blackboard artifact counts of two databases.
|
||||
|
||||
Returns:
|
||||
True if the artifacts are the same, false otherwise.
|
||||
"""
|
||||
exceptions = []
|
||||
passed = True
|
||||
if self.gold_artifacts != self.autopsy_artifacts:
|
||||
msg = "There was a difference in the number of artifacts.\n"
|
||||
exceptions.append(msg)
|
||||
Errors.add_email_msg(msg)
|
||||
passed = False
|
||||
print("Email will be sent to ", self.mail_to)
|
||||
else:
|
||||
rner = len(self.gold_artifacts)
|
||||
for type_id in range(1, rner):
|
||||
if self.gold_artifacts[type_id] != self.autopsy_artifacts[type_id]:
|
||||
error = str("Artifact counts do not match for type id %d. " % type_id)
|
||||
error += str("Gold: %d, Test: %d" %
|
||||
(self.gold_artifacts[type_id],
|
||||
self.autopsy_artifacts[type_id]))
|
||||
exceptions.append(error)
|
||||
passed = False
|
||||
self.report_errors.append(exceptions)
|
||||
return passed
|
||||
print("No email will be sent.")
|
||||
|
||||
def _compare_bb_attributes(self):
|
||||
"""Compares the blackboard attribute counts of two databases.
|
||||
|
||||
Updates this TskDbDiff's report_errors with the error messages from the
|
||||
attribute diff
|
||||
|
||||
Returns:
|
||||
True is the attributes are the same, False otherwise.
|
||||
"""
|
||||
exceptions = []
|
||||
passed = True
|
||||
if self.gold_attributes != self.autopsy_attributes:
|
||||
error = "Attribute counts do not match. "
|
||||
error += str("Gold: %d, Test: %d" % (self.gold_attributes, self.autopsy_attributes))
|
||||
exceptions.append(error)
|
||||
msg = "There was a difference in the number of attributes.\n"
|
||||
Errors.add_email_msg(msg)
|
||||
passed = False
|
||||
self.report_errors.append(exceptions)
|
||||
return passed
|
||||
|
||||
def _compare_tsk_objects(self):
|
||||
"""Compares the TSK object counts of two databases."""
|
||||
exceptions = []
|
||||
passed = True
|
||||
if self.gold_objects != self.autopsy_objects:
|
||||
error = "TSK Object counts do not match. "
|
||||
error += str("Gold: %d, Test: %d" % (self.gold_objects, self.autopsy_objects))
|
||||
exceptions.append(error)
|
||||
msg ="There was a difference between the tsk object counts.\n"
|
||||
Errors.add_email_msg(msg)
|
||||
passed = False
|
||||
self.report_errors.append(exceptions)
|
||||
return passed
|
||||
|
||||
def _get_basic_counts(self, autopsy_cur, gold_cur):
|
||||
"""Count the items necessary to compare the databases.
|
||||
|
||||
Gets the counts of objects, artifacts, and attributes in the Gold
|
||||
and Ouput databases and updates this TskDbDiff's attributes
|
||||
accordingly
|
||||
|
||||
Args:
|
||||
autopsy_cur: SQLCursor - the cursor for the output database
|
||||
gold_cur: SQLCursor - the cursor for the gold database
|
||||
"""
|
||||
try:
|
||||
# Objects
|
||||
self.gold_objects = self._count_objects(gold_cur)
|
||||
self.autopsy_objects = self._count_objects(autopsy_cur)
|
||||
# Artifacts
|
||||
self.gold_artifacts = self._get_artifacts(gold_cur)
|
||||
self.autopsy_artifacts = self._get_artifacts(autopsy_cur)
|
||||
# Attributes
|
||||
self.gold_attributes = self._count_attributes(gold_cur)
|
||||
self.autopsy_attributes = self._count_attributes(autopsy_cur)
|
||||
except sqlite3.Error as e:
|
||||
Errors.print_error("Error while querying the databases:" + str(e))
|
||||
|
||||
def run_diff(self):
|
||||
"""Basic test between output and gold databases.
|
||||
|
||||
Compares only counts of objects and blackboard items.
|
||||
Note: SQLITE needs unix style pathing
|
||||
|
||||
Raises:
|
||||
sqlite3.OperationalError, if either of the database files do not
|
||||
exist
|
||||
"""
|
||||
# Get connections and cursors to output / gold databases
|
||||
autopsy_con = sqlite3.connect(self.autopsy_db_file)
|
||||
autopsy_cur = autopsy_con.cursor()
|
||||
gold_con = sqlite3.connect(self.gold_db_file)
|
||||
gold_cur = gold_con.cursor()
|
||||
|
||||
# Get Counts of objects, artifacts, and attributes
|
||||
self._get_basic_counts(autopsy_cur, gold_cur)
|
||||
|
||||
# We're done with the databases, close up the connections
|
||||
autopsy_con.close()
|
||||
gold_con.close()
|
||||
|
||||
# Compare counts
|
||||
objects_passed = self._compare_tsk_objects()
|
||||
artifacts_passed = self._compare_bb_artifacts()
|
||||
attributes_passed = self._compare_bb_attributes()
|
||||
|
||||
self.passed = objects_passed and artifacts_passed and attributes_passed
|
||||
|
||||
self.artifact_comparison = self.report_errors[1]
|
||||
self.attribute_comparison = self.report_errors[2]
|
||||
|
||||
okay = "All counts match."
|
||||
print_report(self.report_errors[0], "COMPARE TSK OBJECTS", okay)
|
||||
print_report(self.report_errors[1], "COMPARE ARTIFACTS", okay)
|
||||
print_report(self.report_errors[2], "COMPARE ATTRIBUTES", okay)
|
||||
|
||||
return DiffResults(self)
|
||||
|
||||
def _dump_output_db_bb(autopsy_con, db_file, data_file, sorted_data_file):
|
||||
"""Dumps sorted text results to the given output location.
|
||||
|
||||
Smart method that deals with a blackboard comparison to avoid issues
|
||||
with different IDs based on when artifacts were created.
|
||||
|
||||
Args:
|
||||
autopsy_con: a SQLConn to the autopsy database.
|
||||
db_file: a pathto_File, the output database.
|
||||
data_file: a pathto_File, the dump file to write to
|
||||
sorted_data_file: a pathto_File, the sorted dump file to write to
|
||||
"""
|
||||
autopsy_cur2 = autopsy_con.cursor()
|
||||
# Get the list of all artifacts
|
||||
# @@@ Could add a SORT by parent_path in here since that is how we are going to later sort it.
|
||||
autopsy_cur2.execute("SELECT tsk_files.parent_path, tsk_files.name, blackboard_artifact_types.display_name, blackboard_artifacts.artifact_id FROM blackboard_artifact_types INNER JOIN blackboard_artifacts ON blackboard_artifact_types.artifact_type_id = blackboard_artifacts.artifact_type_id INNER JOIN tsk_files ON tsk_files.obj_id = blackboard_artifacts.obj_id")
|
||||
database_log = codecs.open(data_file, "wb", "utf_8")
|
||||
rw = autopsy_cur2.fetchone()
|
||||
appnd = False
|
||||
counter = 0
|
||||
artifact_count = 0
|
||||
artifact_fail = 0
|
||||
# Cycle through artifacts
|
||||
try:
|
||||
while (rw != None):
|
||||
# File Name and artifact type
|
||||
if(rw[0] != None):
|
||||
database_log.write(rw[0] + rw[1] + ' <artifact type="' + rw[2] + '" > ')
|
||||
else:
|
||||
database_log.write(rw[1] + ' <artifact type="' + rw[2] + '" > ')
|
||||
|
||||
# Get attributes for this artifact
|
||||
autopsy_cur1 = autopsy_con.cursor()
|
||||
looptry = True
|
||||
artifact_count += 1
|
||||
try:
|
||||
key = ""
|
||||
key = str(rw[3])
|
||||
key = key,
|
||||
autopsy_cur1.execute("SELECT blackboard_attributes.source, blackboard_attribute_types.display_name, blackboard_attributes.value_type, blackboard_attributes.value_text, blackboard_attributes.value_int32, blackboard_attributes.value_int64, blackboard_attributes.value_double FROM blackboard_attributes INNER JOIN blackboard_attribute_types ON blackboard_attributes.attribute_type_id = blackboard_attribute_types.attribute_type_id WHERE artifact_id =? ORDER BY blackboard_attributes.source, blackboard_attribute_types.display_name, blackboard_attributes.value_type, blackboard_attributes.value_text, blackboard_attributes.value_int32, blackboard_attributes.value_int64, blackboard_attributes.value_double", key)
|
||||
attributes = autopsy_cur1.fetchall()
|
||||
except sqlite3.Error as e:
|
||||
Errors.print_error(str(e))
|
||||
Errors.print_error(str(rw[3]))
|
||||
msg ="Attributes in artifact id (in output DB)# " + str(rw[3]) + " encountered an error: " + str(e) +" .\n"
|
||||
Errors.add_email_msg(msg)
|
||||
looptry = False
|
||||
print(artifact_fail)
|
||||
artifact_fail += 1
|
||||
print(artifact_fail)
|
||||
database_log.write('Error Extracting Attributes');
|
||||
|
||||
# Print attributes
|
||||
if(looptry == True):
|
||||
src = attributes[0][0]
|
||||
for attr in attributes:
|
||||
val = 3 + attr[2]
|
||||
numvals = 0
|
||||
for x in range(3, 6):
|
||||
if(attr[x] != None):
|
||||
numvals += 1
|
||||
if(numvals > 1):
|
||||
msg = "There were too many values for attribute type: " + attr[1] + " for artifact with id #" + str(rw[3]) + ".\n"
|
||||
Errors.add_email_msg(msg)
|
||||
Errors.print_error(msg)
|
||||
if(not appnd):
|
||||
Errors.add_email_attachment(db_file)
|
||||
appnd = True
|
||||
if(not attr[0] == src):
|
||||
msg ="There were inconsistent sources for artifact with id #" + str(rw[3]) + ".\n"
|
||||
Errors.add_email_msg(msg)
|
||||
Errors.print_error(msg)
|
||||
if(not appnd):
|
||||
Errors.add_email_attachment(db_file)
|
||||
appnd = True
|
||||
try:
|
||||
database_log.write('<attribute source="' + attr[0] + '" type="' + attr[1] + '" value="')
|
||||
inpval = attr[val]
|
||||
if((type(inpval) != 'unicode') or (type(inpval) != 'str')):
|
||||
inpval = str(inpval)
|
||||
patrn = re.compile("[\n\0\a\b\r\f\e]")
|
||||
inpval = re.sub(patrn, ' ', inpval)
|
||||
database_log.write(inpval)
|
||||
except IOError as e:
|
||||
Errors.print_error(str(e))
|
||||
|
||||
database_log.write('" />')
|
||||
database_log.write(' <artifact/>\n')
|
||||
rw = autopsy_cur2.fetchone()
|
||||
|
||||
# Now sort the file
|
||||
srtcmdlst = ["sort", data_file, "-o", sorted_data_file]
|
||||
subprocess.call(srtcmdlst)
|
||||
print(artifact_fail)
|
||||
if(artifact_fail > 0):
|
||||
msg ="There were " + str(artifact_count) + " artifacts and " + str(artifact_fail) + " threw an exception while loading.\n"
|
||||
Errors.add_email_msg(msg)
|
||||
except Exception as e:
|
||||
Errors.print_error('outer exception: ' + str(e))
|
||||
|
||||
def _dump_output_db_nonbb(test_data):
|
||||
"""Dumps a database to a text file.
|
||||
|
||||
Does not dump the artifact and attributes.
|
||||
|
||||
Args:
|
||||
test_data: the TestData that corresponds with this dump.
|
||||
"""
|
||||
# Make a copy of the DB
|
||||
autopsy_db_file = test_data.get_db_path(DBType.OUTPUT)
|
||||
backup_db_file = test_data.get_db_path(DBType.BACKUP)
|
||||
shutil.copy(autopsy_db_file, backup_db_file)
|
||||
autopsy_con = sqlite3.connect(backup_db_file)
|
||||
|
||||
# Delete the blackboard tables
|
||||
autopsy_con.execute("DROP TABLE blackboard_artifacts")
|
||||
autopsy_con.execute("DROP TABLE blackboard_attributes")
|
||||
|
||||
# Write to the database dump
|
||||
with codecs.open(test_data.test_dbdump, "wb", "utf_8") as db_log:
|
||||
for line in autopsy_con.iterdump():
|
||||
db_log.write('%s\n' %line)
|
||||
|
||||
|
||||
def dump_output_db(test_data):
|
||||
"""Dumps the given database to text files for later comparison.
|
||||
|
||||
Args:
|
||||
test_data: the TestData that corresponds to this dump.
|
||||
"""
|
||||
autopsy_db_file = test_data.get_db_path(DBType.OUTPUT)
|
||||
autopsy_con = sqlite3.connect(autopsy_db_file)
|
||||
autopsy_cur = autopsy_con.cursor()
|
||||
# Try to query the databases. Ignore any exceptions, the function will
|
||||
# return an error later on if these do fail
|
||||
TskDbDiff._dump_output_db_bb(autopsy_con, autopsy_db_file,
|
||||
test_data.autopsy_data_file,
|
||||
test_data.get_sorted_data_path(DBType.OUTPUT))
|
||||
TskDbDiff._dump_output_db_nonbb(test_data)
|
||||
autopsy_con.close()
|
||||
|
||||
#-------------------------------------------------#
|
||||
# Functions relating to comparing outputs #
|
||||
@@ -1078,11 +731,13 @@ class TestResultsDiffer(object):
|
||||
databaseDiff: TskDbDiff object created based off test_data
|
||||
"""
|
||||
try:
|
||||
# Diff the gold and output databases
|
||||
output_db_path = test_data.get_db_path(DBType.OUTPUT)
|
||||
gold_db_path = test_data.get_db_path(DBType.GOLD)
|
||||
db_diff = TskDbDiff(output_db_path, gold_db_path)
|
||||
test_data.db_diff_results = db_diff.run_diff()
|
||||
output_db = test_data.get_db_path(DBType.OUTPUT)
|
||||
gold_db = test_data.get_db_path(DBType.GOLD)
|
||||
output_dir = test_data.output_path
|
||||
gold_bb_dump = test_data.get_sorted_data_path(DBType.GOLD)
|
||||
gold_dump = test_data.get_db_dump_path(DBType.GOLD)
|
||||
test_data.db_diff_pass = all(TskDbDiff(output_db, gold_db, output_dir=output_dir, gold_bb_dump=gold_bb_dump,
|
||||
gold_dump=gold_dump).run_diff())
|
||||
|
||||
# Compare Exceptions
|
||||
# replace is a fucntion that replaces strings of digits with 'd'
|
||||
@@ -1094,18 +749,6 @@ class TestResultsDiffer(object):
|
||||
replace)
|
||||
test_data.errors_diff_passed = passed
|
||||
|
||||
# Compare smart blackboard results
|
||||
output_data = test_data.get_sorted_data_path(DBType.OUTPUT)
|
||||
gold_data = test_data.get_sorted_data_path(DBType.GOLD)
|
||||
passed = TestResultsDiffer._compare_text(output_data, gold_data)
|
||||
test_data.sorted_data_passed = passed
|
||||
|
||||
# Compare the rest of the database (non-BB)
|
||||
output_dump = test_data.get_db_dump_path(DBType.OUTPUT)
|
||||
gold_dump = test_data.get_db_dump_path(DBType.GOLD)
|
||||
passed = TestResultsDiffer._compare_text(output_dump, gold_dump)
|
||||
test_data.db_dump_passed = passed
|
||||
|
||||
# Compare html output
|
||||
gold_report_path = test_data.get_html_report_path(DBType.GOLD)
|
||||
output_report_path = test_data.get_html_report_path(DBType.OUTPUT)
|
||||
@@ -1119,6 +762,8 @@ class TestResultsDiffer(object):
|
||||
except sqlite3.OperationalError as e:
|
||||
Errors.print_error("Tests failed while running the diff:\n")
|
||||
Errors.print_error(str(e))
|
||||
except TskDbDiffException as e:
|
||||
Errors.print_error(str(e))
|
||||
except Exception as e:
|
||||
Errors.print_error("Tests failed due to an error, try rebuilding or creating gold standards.\n")
|
||||
Errors.print_error(str(e) + "\n")
|
||||
@@ -1339,14 +984,14 @@ class Reports(object):
|
||||
info += "<tr><td>Out Of Disk Space:\
|
||||
<p style='font-size: 11px;'>(will skew other test results)</p></td>"
|
||||
info += "<td>" + str(len(search_log_set("autopsy", "Stopping ingest due to low disk space on disk", test_data))) + "</td></tr>"
|
||||
info += "<tr><td>TSK Objects Count:</td>"
|
||||
info += "<td>" + str(test_data.db_diff_results.output_objs) + "</td></tr>"
|
||||
info += "<tr><td>Artifacts Count:</td>"
|
||||
info += "<td>" + str(test_data.db_diff_results.output_artifacts)+ "</td></tr>"
|
||||
info += "<tr><td>Attributes Count:</td>"
|
||||
info += "<td>" + str(test_data.db_diff_results.output_attrs) + "</td></tr>"
|
||||
# info += "<tr><td>TSK Objects Count:</td>"
|
||||
# info += "<td>" + str(test_data.db_diff_results.output_objs) + "</td></tr>"
|
||||
# info += "<tr><td>Artifacts Count:</td>"
|
||||
# info += "<td>" + str(test_data.db_diff_results.output_artifacts)+ "</td></tr>"
|
||||
# info += "<tr><td>Attributes Count:</td>"
|
||||
# info += "<td>" + str(test_data.db_diff_results.output_attrs) + "</td></tr>"
|
||||
info += "</table>\
|
||||
</div>"
|
||||
</div>"
|
||||
# For all the general print statements in the test_config
|
||||
output = "<div id='general'>\
|
||||
<h2><a name='" + test_data.image_name + "-general'>General Output</a></h2>\
|
||||
@@ -1453,12 +1098,12 @@ class Reports(object):
|
||||
vars.append( str(test_data.indexed_files) )
|
||||
vars.append( str(test_data.indexed_chunks) )
|
||||
vars.append( str(len(search_log_set("autopsy", "Stopping ingest due to low disk space on disk", test_data))) )
|
||||
vars.append( str(test_data.db_diff_results.output_objs) )
|
||||
vars.append( str(test_data.db_diff_results.output_artifacts) )
|
||||
vars.append( str(test_data.db_diff_results.output_objs) )
|
||||
# vars.append( str(test_data.db_diff_results.output_objs) )
|
||||
# vars.append( str(test_data.db_diff_results.output_artifacts) )
|
||||
# vars.append( str(test_data.db_diff_results.output_objs) )
|
||||
vars.append( make_local_path("gold", test_data.image_name, DB_FILENAME) )
|
||||
vars.append( test_data.db_diff_results.get_artifact_comparison() )
|
||||
vars.append( test_data.db_diff_results.get_attribute_comparison() )
|
||||
# vars.append( test_data.db_diff_results.get_artifact_comparison() )
|
||||
# vars.append( test_data.db_diff_results.get_attribute_comparison() )
|
||||
vars.append( make_local_path("gold", test_data.image_name, "standard.html") )
|
||||
vars.append( str(test_data.html_report_passed) )
|
||||
vars.append( test_data.ant_to_string() )
|
||||
@@ -1493,12 +1138,12 @@ class Reports(object):
|
||||
titles.append("Indexed Files Count")
|
||||
titles.append("Indexed File Chunks Count")
|
||||
titles.append("Out Of Disk Space")
|
||||
titles.append("Tsk Objects Count")
|
||||
titles.append("Artifacts Count")
|
||||
titles.append("Attributes Count")
|
||||
# titles.append("Tsk Objects Count")
|
||||
# titles.append("Artifacts Count")
|
||||
# titles.append("Attributes Count")
|
||||
titles.append("Gold Database Name")
|
||||
titles.append("Artifacts Comparison")
|
||||
titles.append("Attributes Comparison")
|
||||
# titles.append("Artifacts Comparison")
|
||||
# titles.append("Attributes Comparison")
|
||||
titles.append("Gold Report Name")
|
||||
titles.append("Report Comparison")
|
||||
titles.append("Ant Command Line")
|
||||
@@ -1951,6 +1596,7 @@ class Args(object):
|
||||
self.exception = False
|
||||
self.exception_string = ""
|
||||
self.fr = False
|
||||
self.email_enabled = False
|
||||
|
||||
def parse(self):
|
||||
"""Get the command line arguments and parse them."""
|
||||
@@ -2010,6 +1656,8 @@ class Args(object):
|
||||
elif arg == "-fr" or arg == "--forcerun":
|
||||
print("Not downloading new images")
|
||||
self.fr = True
|
||||
elif arg == "-e" or arg == "-email":
|
||||
self.email_enabled = True
|
||||
else:
|
||||
print(usage())
|
||||
return False
|
||||
|
||||
@@ -152,3 +152,4 @@ def get_files_by_ext(dir_path, ext):
|
||||
"""
|
||||
return [ os.path.join(dir_path, file) for file in os.listdir(dir_path) if
|
||||
file.endswith(ext) ]
|
||||
|
||||
|
||||
@@ -1,186 +1,187 @@
|
||||
import codecs
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import socket
|
||||
import sqlite3
|
||||
import subprocess
|
||||
import sys
|
||||
from sys import platform as _platform
|
||||
import time
|
||||
import traceback
|
||||
import xml
|
||||
from xml.dom.minidom import parse, parseString
|
||||
import Emailer
|
||||
|
||||
def compile(errore, attachli, parsedin):
|
||||
global redo
|
||||
global tryredo
|
||||
global failedbool
|
||||
global errorem
|
||||
errorem = errore
|
||||
global attachl
|
||||
attachl = attachli
|
||||
global passed
|
||||
global parsed
|
||||
parsed = parsedin
|
||||
passed = True
|
||||
tryredo = False
|
||||
redo = True
|
||||
while(redo):
|
||||
passed = True
|
||||
if(passed):
|
||||
gitPull("sleuthkit")
|
||||
if(passed):
|
||||
vsBuild()
|
||||
if(passed):
|
||||
gitPull("autopsy")
|
||||
if(passed):
|
||||
antBuild("datamodel", False)
|
||||
if(passed):
|
||||
antBuild("autopsy", True)
|
||||
if(passed):
|
||||
redo = False
|
||||
else:
|
||||
print("Compile Failed")
|
||||
time.sleep(3600)
|
||||
attachl = []
|
||||
errorem = "The test standard didn't match the gold standard.\n"
|
||||
failedbool = False
|
||||
if(tryredo):
|
||||
errorem = ""
|
||||
errorem += "Rebuilt properly.\n"
|
||||
Emailer.send_email(parsed, errorem, attachl, True)
|
||||
attachl = []
|
||||
passed = True
|
||||
|
||||
#Pulls from git
|
||||
def gitPull(TskOrAutopsy):
|
||||
global SYS
|
||||
global errorem
|
||||
global attachl
|
||||
ccwd = ""
|
||||
gppth = Emailer.make_local_path("..", "GitPullOutput" + TskOrAutopsy + ".txt")
|
||||
attachl.append(gppth)
|
||||
gpout = open(gppth, 'a')
|
||||
toPull = "https://www.github.com/sleuthkit/" + TskOrAutopsy
|
||||
call = ["git", "pull", toPull]
|
||||
if TskOrAutopsy == "sleuthkit":
|
||||
ccwd = os.path.join("..", "..", "..", "sleuthkit")
|
||||
else:
|
||||
ccwd = os.path.join("..", "..")
|
||||
subprocess.call(call, stdout=sys.stdout, cwd=ccwd)
|
||||
gpout.close()
|
||||
|
||||
|
||||
#Builds TSK as a win32 applicatiion
|
||||
def vsBuild():
|
||||
global redo
|
||||
global tryredo
|
||||
global passed
|
||||
global parsed
|
||||
#Please ensure that the current working directory is $autopsy/testing/script
|
||||
oldpath = os.getcwd()
|
||||
os.chdir(os.path.join("..", "..", "..","sleuthkit", "win32"))
|
||||
vs = []
|
||||
vs.append("/cygdrive/c/windows/microsoft.NET/framework/v4.0.30319/MSBuild.exe")
|
||||
vs.append(os.path.join("Tsk-win.sln"))
|
||||
vs.append("/p:configuration=release")
|
||||
vs.append("/p:platform=win32")
|
||||
vs.append("/t:clean")
|
||||
vs.append("/t:rebuild")
|
||||
print(vs)
|
||||
VSpth = Emailer.make_local_path("..", "VSOutput.txt")
|
||||
VSout = open(VSpth, 'a')
|
||||
subprocess.call(vs, stdout=VSout)
|
||||
VSout.close()
|
||||
os.chdir(oldpath)
|
||||
chk = os.path.join("..", "..", "..","sleuthkit", "win32", "Release", "libtsk_jni.dll")
|
||||
try:
|
||||
open(chk)
|
||||
except IOError as e:
|
||||
global errorem
|
||||
global attachl
|
||||
if(not tryredo):
|
||||
errorem += "LIBTSK C++ failed to build.\n"
|
||||
attachl.append(VSpth)
|
||||
Emailer.send_email(parsed, errorem, attachl, False)
|
||||
tryredo = True
|
||||
passed = False
|
||||
redo = True
|
||||
|
||||
|
||||
|
||||
#Builds Autopsy or the Datamodel
|
||||
def antBuild(which, Build):
|
||||
global redo
|
||||
global passed
|
||||
global tryredo
|
||||
global parsed
|
||||
directory = os.path.join("..", "..")
|
||||
ant = []
|
||||
if which == "datamodel":
|
||||
directory = os.path.join("..", "..", "..", "sleuthkit", "bindings", "java")
|
||||
ant.append("ant")
|
||||
ant.append("-f")
|
||||
ant.append(directory)
|
||||
ant.append("clean")
|
||||
if(Build):
|
||||
ant.append("build")
|
||||
else:
|
||||
ant.append("dist")
|
||||
antpth = Emailer.make_local_path("..", "ant" + which + "Output.txt")
|
||||
antout = open(antpth, 'a')
|
||||
succd = subprocess.call(ant, stdout=antout)
|
||||
antout.close()
|
||||
global errorem
|
||||
global attachl
|
||||
if which == "datamodel":
|
||||
chk = os.path.join("..", "..", "..","sleuthkit", "bindings", "java", "dist", "TSK_DataModel.jar")
|
||||
try:
|
||||
open(chk)
|
||||
except IOError as e:
|
||||
if(not tryredo):
|
||||
errorem += "DataModel Java build failed.\n"
|
||||
attachl.append(antpth)
|
||||
Emailer.send_email(parsed, errorem, attachl, False)
|
||||
passed = False
|
||||
tryredo = True
|
||||
elif (succd != 0 and (not tryredo)):
|
||||
errorem += "Autopsy build failed.\n"
|
||||
attachl.append(antpth)
|
||||
Emailer.send_email(parsed, errorem, attachl, False)
|
||||
tryredo = True
|
||||
elif (succd != 0):
|
||||
passed = False
|
||||
|
||||
|
||||
def main():
|
||||
errore = ""
|
||||
attachli = []
|
||||
config_file = ""
|
||||
arg = sys.argv.pop(0)
|
||||
arg = sys.argv.pop(0)
|
||||
config_file = arg
|
||||
parsedin = parse(config_file)
|
||||
compile(errore, attachli, parsedin)
|
||||
|
||||
class OS:
|
||||
LINUX, MAC, WIN, CYGWIN = range(4)
|
||||
if __name__ == "__main__":
|
||||
global SYS
|
||||
if _platform == "linux" or _platform == "linux2":
|
||||
SYS = OS.LINUX
|
||||
elif _platform == "darwin":
|
||||
SYS = OS.MAC
|
||||
elif _platform == "win32":
|
||||
SYS = OS.WIN
|
||||
elif _platform == "cygwin":
|
||||
SYS = OS.CYGWIN
|
||||
|
||||
if SYS is OS.WIN or SYS is OS.CYGWIN:
|
||||
main()
|
||||
else:
|
||||
print("We only support Windows and Cygwin at this time.")
|
||||
import codecs
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import socket
|
||||
import sqlite3
|
||||
import subprocess
|
||||
import sys
|
||||
from sys import platform as _platform
|
||||
import time
|
||||
import traceback
|
||||
import xml
|
||||
from xml.dom.minidom import parse, parseString
|
||||
import Emailer
|
||||
from regression_utils import *
|
||||
|
||||
def compile(errore, attachli, parsedin):
|
||||
global redo
|
||||
global tryredo
|
||||
global failedbool
|
||||
global errorem
|
||||
errorem = errore
|
||||
global attachl
|
||||
attachl = attachli
|
||||
global passed
|
||||
global parsed
|
||||
parsed = parsedin
|
||||
passed = True
|
||||
tryredo = False
|
||||
redo = True
|
||||
while(redo):
|
||||
passed = True
|
||||
if(passed):
|
||||
gitPull("sleuthkit")
|
||||
if(passed):
|
||||
vsBuild()
|
||||
if(passed):
|
||||
gitPull("autopsy")
|
||||
if(passed):
|
||||
antBuild("datamodel", False)
|
||||
if(passed):
|
||||
antBuild("autopsy", True)
|
||||
if(passed):
|
||||
redo = False
|
||||
else:
|
||||
print("Compile Failed")
|
||||
time.sleep(3600)
|
||||
attachl = []
|
||||
errorem = "The test standard didn't match the gold standard.\n"
|
||||
failedbool = False
|
||||
if(tryredo):
|
||||
errorem = ""
|
||||
errorem += "Rebuilt properly.\n"
|
||||
Emailer.send_email(parsed, errorem, attachl, True)
|
||||
attachl = []
|
||||
passed = True
|
||||
|
||||
#Pulls from git
|
||||
def gitPull(TskOrAutopsy):
|
||||
global SYS
|
||||
global errorem
|
||||
global attachl
|
||||
ccwd = ""
|
||||
gppth = make_local_path("..", "GitPullOutput" + TskOrAutopsy + ".txt")
|
||||
attachl.append(gppth)
|
||||
gpout = open(gppth, 'a')
|
||||
toPull = "https://www.github.com/sleuthkit/" + TskOrAutopsy
|
||||
call = ["git", "pull", toPull]
|
||||
if TskOrAutopsy == "sleuthkit":
|
||||
ccwd = os.path.join("..", "..", "..", "sleuthkit")
|
||||
else:
|
||||
ccwd = os.path.join("..", "..")
|
||||
subprocess.call(call, stdout=sys.stdout, cwd=ccwd)
|
||||
gpout.close()
|
||||
|
||||
|
||||
#Builds TSK as a win32 applicatiion
|
||||
def vsBuild():
|
||||
global redo
|
||||
global tryredo
|
||||
global passed
|
||||
global parsed
|
||||
#Please ensure that the current working directory is $autopsy/testing/script
|
||||
oldpath = os.getcwd()
|
||||
os.chdir(os.path.join("..", "..", "..","sleuthkit", "win32"))
|
||||
vs = []
|
||||
vs.append("/cygdrive/c/windows/microsoft.NET/framework/v4.0.30319/MSBuild.exe")
|
||||
vs.append(os.path.join("Tsk-win.sln"))
|
||||
vs.append("/p:configuration=release")
|
||||
vs.append("/p:platform=win32")
|
||||
vs.append("/t:clean")
|
||||
vs.append("/t:rebuild")
|
||||
print(vs)
|
||||
VSpth = make_local_path("..", "VSOutput.txt")
|
||||
VSout = open(VSpth, 'a')
|
||||
subprocess.call(vs, stdout=VSout)
|
||||
VSout.close()
|
||||
os.chdir(oldpath)
|
||||
chk = os.path.join("..", "..", "..","sleuthkit", "win32", "Release", "libtsk_jni.dll")
|
||||
try:
|
||||
open(chk)
|
||||
except IOError as e:
|
||||
global errorem
|
||||
global attachl
|
||||
if(not tryredo):
|
||||
errorem += "LIBTSK C++ failed to build.\n"
|
||||
attachl.append(VSpth)
|
||||
send_email(parsed, errorem, attachl, False)
|
||||
tryredo = True
|
||||
passed = False
|
||||
redo = True
|
||||
|
||||
|
||||
|
||||
#Builds Autopsy or the Datamodel
|
||||
def antBuild(which, Build):
|
||||
global redo
|
||||
global passed
|
||||
global tryredo
|
||||
global parsed
|
||||
directory = os.path.join("..", "..")
|
||||
ant = []
|
||||
if which == "datamodel":
|
||||
directory = os.path.join("..", "..", "..", "sleuthkit", "bindings", "java")
|
||||
ant.append("ant")
|
||||
ant.append("-f")
|
||||
ant.append(directory)
|
||||
ant.append("clean")
|
||||
if(Build):
|
||||
ant.append("build")
|
||||
else:
|
||||
ant.append("dist")
|
||||
antpth = make_local_path("..", "ant" + which + "Output.txt")
|
||||
antout = open(antpth, 'a')
|
||||
succd = subprocess.call(ant, stdout=antout)
|
||||
antout.close()
|
||||
global errorem
|
||||
global attachl
|
||||
if which == "datamodel":
|
||||
chk = os.path.join("..", "..", "..","sleuthkit", "bindings", "java", "dist", "TSK_DataModel.jar")
|
||||
try:
|
||||
open(chk)
|
||||
except IOError as e:
|
||||
if(not tryredo):
|
||||
errorem += "DataModel Java build failed.\n"
|
||||
attachl.append(antpth)
|
||||
Emailer.send_email(parsed, errorem, attachl, False)
|
||||
passed = False
|
||||
tryredo = True
|
||||
elif (succd != 0 and (not tryredo)):
|
||||
errorem += "Autopsy build failed.\n"
|
||||
attachl.append(antpth)
|
||||
Emailer.send_email(parsed, errorem, attachl, False)
|
||||
tryredo = True
|
||||
elif (succd != 0):
|
||||
passed = False
|
||||
|
||||
|
||||
def main():
|
||||
errore = ""
|
||||
attachli = []
|
||||
config_file = ""
|
||||
arg = sys.argv.pop(0)
|
||||
arg = sys.argv.pop(0)
|
||||
config_file = arg
|
||||
parsedin = parse(config_file)
|
||||
compile(errore, attachli, parsedin)
|
||||
|
||||
class OS:
|
||||
LINUX, MAC, WIN, CYGWIN = range(4)
|
||||
if __name__ == "__main__":
|
||||
global SYS
|
||||
if _platform == "linux" or _platform == "linux2":
|
||||
SYS = OS.LINUX
|
||||
elif _platform == "darwin":
|
||||
SYS = OS.MAC
|
||||
elif _platform == "win32":
|
||||
SYS = OS.WIN
|
||||
elif _platform == "cygwin":
|
||||
SYS = OS.CYGWIN
|
||||
|
||||
if SYS is OS.WIN or SYS is OS.CYGWIN:
|
||||
main()
|
||||
else:
|
||||
print("We only support Windows and Cygwin at this time.")
|
||||
|
||||
284
test/script/tskdbdiff.py
Normal file
284
test/script/tskdbdiff.py
Normal file
@@ -0,0 +1,284 @@
|
||||
import re
|
||||
import sqlite3
|
||||
import subprocess
|
||||
import shutil
|
||||
import os
|
||||
import codecs
|
||||
import datetime
|
||||
import sys
|
||||
|
||||
class TskDbDiff(object):
|
||||
"""Represents the differences between the gold and output databases.
|
||||
|
||||
Contains methods to compare two databases.
|
||||
|
||||
Attributes:
|
||||
gold_artifacts:
|
||||
autopsy_artifacts:
|
||||
gold_attributes:
|
||||
autopsy_attributes:
|
||||
gold_objects:
|
||||
autopsy_objects:
|
||||
artifact_comparison:
|
||||
attribute_comparision:
|
||||
report_errors: a listof_listof_String, the error messages that will be
|
||||
printed to screen in the run_diff method
|
||||
passed: a boolean, did the diff pass?
|
||||
autopsy_db_file:
|
||||
gold_db_file:
|
||||
"""
|
||||
def __init__(self, output_db, gold_db, output_dir=None, gold_bb_dump=None, gold_dump=None, verbose=False):
|
||||
"""Constructor for TskDbDiff.
|
||||
|
||||
Args:
|
||||
output_db_path: a pathto_File, the output database
|
||||
gold_db_path: a pathto_File, the gold database
|
||||
output_dir: (optional) a pathto_Dir, the location where the generated files will be put.
|
||||
gold_bb_dump: (optional) a pathto_File, the location where the gold blackboard dump is located
|
||||
gold_dump: (optional) a pathto_File, the location where the gold non-blackboard dump is located
|
||||
verbose: (optional) a boolean, should the diff results be printed to stdout?
|
||||
"""
|
||||
self.output_db_file = output_db
|
||||
self.gold_db_file = gold_db
|
||||
self.output_dir = output_dir
|
||||
self.gold_bb_dump = gold_bb_dump
|
||||
self.gold_dump = gold_dump
|
||||
self._generate_gold_dump = gold_dump is None
|
||||
self._generate_gold_bb_dump = gold_bb_dump is None
|
||||
self._bb_dump_diff = ""
|
||||
self._dump_diff = ""
|
||||
self._bb_dump = ""
|
||||
self._dump = ""
|
||||
self.verbose = verbose
|
||||
|
||||
def run_diff(self):
|
||||
"""Compare the databases.
|
||||
|
||||
Raises:
|
||||
TskDbDiffException: if an error occurs while diffing or dumping the database
|
||||
"""
|
||||
self._init_diff()
|
||||
# generate the gold database dumps if necessary
|
||||
if self._generate_gold_dump:
|
||||
TskDbDiff._dump_output_db_nonbb(self.gold_db_file, self.gold_dump)
|
||||
if self._generate_gold_bb_dump:
|
||||
TskDbDiff._dump_output_db_bb(self.gold_db_file, self.gold_bb_dump)
|
||||
|
||||
# generate the output database dumps
|
||||
TskDbDiff.dump_output_db(self.output_db_file, self._dump, self._bb_dump)
|
||||
|
||||
dump_diff_pass = self._diff(self._dump, self.gold_dump, self._dump_diff)
|
||||
bb_dump_diff_pass = self._diff(self._bb_dump, self.gold_bb_dump, self._bb_dump_diff)
|
||||
|
||||
self._cleanup_diff()
|
||||
return dump_diff_pass, bb_dump_diff_pass
|
||||
|
||||
def _init_diff(self):
|
||||
"""Set up the necessary files based on the arguments given at construction"""
|
||||
if self.output_dir is None:
|
||||
# No stored files
|
||||
self._bb_dump = TskDbDiff._get_tmp_file("SortedData", ".txt")
|
||||
self._bb_dump_diff = TskDbDiff._get_tmp_file("SortedData-Diff", ".txt")
|
||||
self._dump = TskDbDiff._get_tmp_file("DBDump", ".txt")
|
||||
self._dump_diff = TskDbDiff._get_tmp_file("DBDump-Diff", ".txt")
|
||||
else:
|
||||
self._bb_dump = os.path.join(self.output_dir, "SortedData.txt")
|
||||
self._bb_dump_diff = os.path.join(self.output_dir, "SortedData-Diff.txt")
|
||||
self._dump = os.path.join(self.output_dir, "DBDump.txt")
|
||||
self._dump_diff = os.path.join(self.output_dir, "DBDump-Diff.txt")
|
||||
|
||||
if self.gold_bb_dump is None:
|
||||
self.gold_bb_dump = TskDbDiff._get_tmp_file("GoldSortedData", ".txt")
|
||||
self.gold_dump = TskDbDiff._get_tmp_file("GoldDBDump", ".txt")
|
||||
|
||||
def _cleanup_diff(self):
|
||||
if self.output_dir is None:
|
||||
#cleanup temp files
|
||||
os.remove(self._dump)
|
||||
os.remove(self._bb_dump)
|
||||
if os.path.isfile(self._dump_diff):
|
||||
os.remove(self._dump_diff)
|
||||
if os.path.isfile(self._bb_dump_diff):
|
||||
os.remove(self._bb_dump_diff)
|
||||
if self.gold_bb_dump is None:
|
||||
os.remove(self.gold_bb_dump)
|
||||
os.remove(self.gold_dump)
|
||||
|
||||
def _diff(self, output_file, gold_file, diff_path):
|
||||
"""Compare two text files.
|
||||
|
||||
Args:
|
||||
output_file: a pathto_File, the output text file
|
||||
gold_file: a pathto_File, the input text file
|
||||
"""
|
||||
if(not os.path.isfile(output_file)):
|
||||
return False
|
||||
output_data = codecs.open(output_file, "r", "utf_8").read()
|
||||
gold_data = codecs.open(gold_file, "r", "utf_8").read()
|
||||
|
||||
if (not(gold_data == output_data)):
|
||||
diff_file = codecs.open(diff_path, "wb", "utf_8")
|
||||
dffcmdlst = ["diff", output_file, gold_file]
|
||||
subprocess.call(dffcmdlst, stdout = diff_file)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def _dump_output_db_bb(db_file, bb_dump_file):
|
||||
"""Dumps sorted text results to the given output location.
|
||||
|
||||
Smart method that deals with a blackboard comparison to avoid issues
|
||||
with different IDs based on when artifacts were created.
|
||||
|
||||
Args:
|
||||
db_file: a pathto_File, the output database.
|
||||
bb_dump_file: a pathto_File, the sorted dump file to write to
|
||||
"""
|
||||
unsorted_dump = TskDbDiff._get_tmp_file("dump_data", ".txt")
|
||||
conn = sqlite3.connect(db_file)
|
||||
autopsy_cur2 = conn.cursor()
|
||||
# Get the list of all artifacts
|
||||
# @@@ Could add a SORT by parent_path in here since that is how we are going to later sort it.
|
||||
autopsy_cur2.execute("SELECT tsk_files.parent_path, tsk_files.name, blackboard_artifact_types.display_name, blackboard_artifacts.artifact_id FROM blackboard_artifact_types INNER JOIN blackboard_artifacts ON blackboard_artifact_types.artifact_type_id = blackboard_artifacts.artifact_type_id INNER JOIN tsk_files ON tsk_files.obj_id = blackboard_artifacts.obj_id")
|
||||
database_log = codecs.open(unsorted_dump, "wb", "utf_8")
|
||||
rw = autopsy_cur2.fetchone()
|
||||
appnd = False
|
||||
counter = 0
|
||||
artifact_count = 0
|
||||
artifact_fail = 0
|
||||
# Cycle through artifacts
|
||||
try:
|
||||
while (rw != None):
|
||||
# File Name and artifact type
|
||||
if(rw[0] != None):
|
||||
database_log.write(rw[0] + rw[1] + ' <artifact type="' + rw[2] + '" > ')
|
||||
else:
|
||||
database_log.write(rw[1] + ' <artifact type="' + rw[2] + '" > ')
|
||||
|
||||
# Get attributes for this artifact
|
||||
autopsy_cur1 = conn.cursor()
|
||||
looptry = True
|
||||
artifact_count += 1
|
||||
try:
|
||||
key = ""
|
||||
key = str(rw[3])
|
||||
key = key,
|
||||
autopsy_cur1.execute("SELECT blackboard_attributes.source, blackboard_attribute_types.display_name, blackboard_attributes.value_type, blackboard_attributes.value_text, blackboard_attributes.value_int32, blackboard_attributes.value_int64, blackboard_attributes.value_double FROM blackboard_attributes INNER JOIN blackboard_attribute_types ON blackboard_attributes.attribute_type_id = blackboard_attribute_types.attribute_type_id WHERE artifact_id =? ORDER BY blackboard_attributes.source, blackboard_attribute_types.display_name, blackboard_attributes.value_type, blackboard_attributes.value_text, blackboard_attributes.value_int32, blackboard_attributes.value_int64, blackboard_attributes.value_double", key)
|
||||
attributes = autopsy_cur1.fetchall()
|
||||
except sqlite3.Error as e:
|
||||
msg ="Attributes in artifact id (in output DB)# " + str(rw[3]) + " encountered an error: " + str(e) +" .\n"
|
||||
looptry = False
|
||||
artifact_fail += 1
|
||||
database_log.write('Error Extracting Attributes')
|
||||
database_log.close()
|
||||
raise TskDbDiffException(msg)
|
||||
|
||||
# Print attributes
|
||||
if(looptry == True):
|
||||
src = attributes[0][0]
|
||||
for attr in attributes:
|
||||
val = 3 + attr[2]
|
||||
numvals = 0
|
||||
for x in range(3, 6):
|
||||
if(attr[x] != None):
|
||||
numvals += 1
|
||||
if(numvals > 1):
|
||||
msg = "There were too many values for attribute type: " + attr[1] + " for artifact with id #" + str(rw[3]) + ".\n"
|
||||
if(not attr[0] == src):
|
||||
msg ="There were inconsistent sources for artifact with id #" + str(rw[3]) + ".\n"
|
||||
try:
|
||||
database_log.write('<attribute source="' + attr[0] + '" type="' + attr[1] + '" value="')
|
||||
inpval = attr[val]
|
||||
if((type(inpval) != 'unicode') or (type(inpval) != 'str')):
|
||||
inpval = str(inpval)
|
||||
patrn = re.compile("[\n\0\a\b\r\f\e]")
|
||||
inpval = re.sub(patrn, ' ', inpval)
|
||||
database_log.write(inpval)
|
||||
except IOError as e:
|
||||
raise TskDbDiffException("Unexpected IO error while writing to database log." + str(e))
|
||||
|
||||
database_log.write('" />')
|
||||
database_log.write(' <artifact/>\n')
|
||||
rw = autopsy_cur2.fetchone()
|
||||
|
||||
# Now sort the file
|
||||
srtcmdlst = ["sort", unsorted_dump, "-o", bb_dump_file]
|
||||
subprocess.call(srtcmdlst)
|
||||
print(artifact_fail)
|
||||
if(artifact_fail > 0):
|
||||
msg ="There were " + str(artifact_count) + " artifacts and " + str(artifact_fail) + " threw an exception while loading.\n"
|
||||
except Exception as e:
|
||||
raise TskDbDiffException("Unexpected error while dumping blackboard database: " + str(e))
|
||||
finally:
|
||||
database_log.close()
|
||||
|
||||
def _dump_output_db_nonbb(db_file, dump_file):
|
||||
"""Dumps a database to a text file.
|
||||
|
||||
Does not dump the artifact and attributes.
|
||||
|
||||
Args:
|
||||
db_file: a pathto_File, the database file to dump
|
||||
dump_file: a pathto_File, the location to dump the non-blackboard database items
|
||||
"""
|
||||
backup_db_file = TskDbDiff._get_tmp_file("tsk_backup_db", ".db")
|
||||
shutil.copy(db_file, backup_db_file)
|
||||
conn = sqlite3.connect(backup_db_file)
|
||||
|
||||
# Delete the blackboard tables
|
||||
conn.execute("DROP TABLE blackboard_artifacts")
|
||||
conn.execute("DROP TABLE blackboard_attributes")
|
||||
|
||||
# Write to the database dump
|
||||
with codecs.open(dump_file, "wb", "utf_8") as db_log:
|
||||
for line in conn.iterdump():
|
||||
db_log.write('%s\n' % line)
|
||||
|
||||
# cleanup the backup
|
||||
os.remove(backup_db_file)
|
||||
|
||||
def dump_output_db(db_file, dump_file, bb_dump_file):
|
||||
"""Dumps the given database to text files for later comparison.
|
||||
|
||||
Args:
|
||||
db_file: a pathto_File, the database file to dump
|
||||
dump_file: a pathto_File, the location to dump the non-blackboard database items
|
||||
bb_dump_file: a pathto_File, the location to dump the blackboard database items
|
||||
"""
|
||||
TskDbDiff._dump_output_db_nonbb(db_file, dump_file)
|
||||
TskDbDiff._dump_output_db_bb(db_file, bb_dump_file)
|
||||
|
||||
def _get_tmp_file(base, ext):
|
||||
time = datetime.datetime.now().time().strftime("%H%M%f")
|
||||
return os.path.join(os.environ['TMP'], base + time + ext)
|
||||
|
||||
|
||||
class TskDbDiffException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
sys.argv.pop(0)
|
||||
output_db = sys.argv.pop(0)
|
||||
gold_db = sys.argv.pop(0)
|
||||
except:
|
||||
print("usage: tskdbdiff [OUPUT DB PATH] [GOLD DB PATH]")
|
||||
sys.exit()
|
||||
|
||||
db_diff = TskDbDiff(output_db, gold_db)
|
||||
dump_passed, bb_dump_passed = db_diff.run_diff()
|
||||
|
||||
if dump_passed and bb_dump_passed:
|
||||
print("Database comparison passed.")
|
||||
elif not dump_passed:
|
||||
print("Non blackboard database comparison failed.")
|
||||
elif not bb_dump_passed:
|
||||
print("Blackboard database comparison failed.")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
||||
1840
update_versions.py
1840
update_versions.py
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user