diff --git a/Case/nbproject/genfiles.properties b/Case/nbproject/genfiles.properties index 9c721222f6..6a27bbe1d2 100644 --- a/Case/nbproject/genfiles.properties +++ b/Case/nbproject/genfiles.properties @@ -1,8 +1,8 @@ -build.xml.data.CRC32=a2330d9e +build.xml.data.CRC32=2b495fd9 build.xml.script.CRC32=601bc2ba -build.xml.stylesheet.CRC32=a56c6a5b@2.47.1 +build.xml.stylesheet.CRC32=a56c6a5b@1.46.2 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. -nbproject/build-impl.xml.data.CRC32=a2330d9e +nbproject/build-impl.xml.data.CRC32=2b495fd9 nbproject/build-impl.xml.script.CRC32=65e93a36 -nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.47.1 +nbproject/build-impl.xml.stylesheet.CRC32=238281d1@1.46.2 diff --git a/Case/nbproject/project.xml b/Case/nbproject/project.xml index ed0e258923..1620ff17fa 100644 --- a/Case/nbproject/project.xml +++ b/Case/nbproject/project.xml @@ -123,6 +123,15 @@ 1.0 + + org.sleuthkit.autopsy.ingest + + + + 0-1 + 1.0 + + diff --git a/Case/src/org/sleuthkit/autopsy/casemodule/layer.xml b/Case/src/org/sleuthkit/autopsy/casemodule/layer.xml index 13aca85875..25182317bd 100644 --- a/Case/src/org/sleuthkit/autopsy/casemodule/layer.xml +++ b/Case/src/org/sleuthkit/autopsy/casemodule/layer.xml @@ -188,6 +188,11 @@ + + + + + diff --git a/Case/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestService.java b/Case/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestService.java new file mode 100644 index 0000000000..69e2d7b916 --- /dev/null +++ b/Case/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestService.java @@ -0,0 +1,76 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +package org.sleuthkit.autopsy.hashdatabase; + +import java.util.logging.Level; +import java.util.logging.Logger; +import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.IngestServiceFsContent; +import org.sleuthkit.datamodel.FsContent; + +public class HashDbIngestService implements IngestServiceFsContent { + + private static HashDbIngestService instance = null; + + private static String SERVICE_NAME = "Hash Db"; + + private static final Logger logger = Logger.getLogger(HashDbIngestService.class.getName()); + + private HashDbIngestService() { + + } + + public static synchronized HashDbIngestService getDefault() { + if (instance == null) { + instance = new HashDbIngestService(); + } + return instance; + } + + @Override + public void process(FsContent fsContent) { + logger.log(Level.INFO, "Processing fsContent: " + fsContent.getName()); + } + + @Override + public void complete() { + logger.log(Level.INFO, "complete()"); + } + + @Override + public String getName() { + return SERVICE_NAME; + } + + @Override + public void init(IngestManager manager) { + logger.log(Level.INFO, "init()"); + } + + @Override + public void stop() { + logger.log(Level.INFO, "stop()"); + } + + + +} diff --git a/Ingest/build.xml b/Ingest/build.xml new file mode 100644 index 0000000000..c92889e28a --- /dev/null +++ b/Ingest/build.xml @@ -0,0 +1,8 @@ + + + + + + Builds, tests, and runs the project org.sleuthkit.autopsy.ingest. + + diff --git a/Ingest/manifest.mf b/Ingest/manifest.mf new file mode 100644 index 0000000000..77e0a0d1dd --- /dev/null +++ b/Ingest/manifest.mf @@ -0,0 +1,9 @@ +Manifest-Version: 1.0 +Bundle-Localization: org/sleuthkit/autopsy/ingest/Bundle +Bundle-Name: %OpenIDE-Module-Name +Bundle-SymbolicName: org.sleuthkit.autopsy.ingest/1 +OpenIDE-Module-Implementation-Version: 1 +OpenIDE-Module-Layer: org/sleuthkit/autopsy/ingest/layer.xml +OpenIDE-Module-Requires: org.openide.windows.WindowManager +OpenIDE-Module: org.sleuthkit.autopsy.ingest/0 + diff --git a/Ingest/nbproject/build-impl.xml b/Ingest/nbproject/build-impl.xml new file mode 100644 index 0000000000..3362f1bf27 --- /dev/null +++ b/Ingest/nbproject/build-impl.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + You must set 'suite.dir' to point to your containing module suite + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ingest/nbproject/genfiles.properties b/Ingest/nbproject/genfiles.properties new file mode 100644 index 0000000000..f4f204a4e0 --- /dev/null +++ b/Ingest/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=1833dad1 +build.xml.script.CRC32=7d5a04db +build.xml.stylesheet.CRC32=a56c6a5b@1.46.2 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=1833dad1 +nbproject/build-impl.xml.script.CRC32=8b2da6d1 +nbproject/build-impl.xml.stylesheet.CRC32=238281d1@1.46.2 diff --git a/Ingest/nbproject/project.properties b/Ingest/nbproject/project.properties new file mode 100644 index 0000000000..e84197de12 --- /dev/null +++ b/Ingest/nbproject/project.properties @@ -0,0 +1,3 @@ +javac.source=1.6 +javac.compilerargs=-Xlint -Xlint:-serial +spec.version.base=1.0 diff --git a/Ingest/nbproject/project.xml b/Ingest/nbproject/project.xml new file mode 100644 index 0000000000..15cae5495e --- /dev/null +++ b/Ingest/nbproject/project.xml @@ -0,0 +1,121 @@ + + + org.netbeans.modules.apisupport.project + + + org.sleuthkit.autopsy.ingest + + + + org.netbeans.api.progress + + + + 1 + 1.24.1 + + + + org.netbeans.libs.osgi + + + + + org.netbeans.modules.settings + + + + 1 + 1.31.1 + + + + org.openide.awt + + + + 7.31.1 + + + + org.openide.dialogs + + + + 7.20.1 + + + + org.openide.modules + + + + 7.23.1 + + + + org.openide.nodes + + + + 7.21.1 + + + + org.openide.util + + + + 8.15.1 + + + + org.openide.util.lookup + + + + 8.8.1 + + + + org.openide.windows + + + + 6.40.1 + + + + org.sleuthkit.autopsy.corecomponentinterfaces + + + + 1 + 1.0 + + + + org.sleuthkit.autopsy.coreutils + + + + 0-1 + 0.0 + + + + org.sleuthkit.autopsy.datamodel + + + + 1 + 1.0 + + + + + org.sleuthkit.autopsy.ingest + + + + diff --git a/Ingest/nbproject/suite.properties b/Ingest/nbproject/suite.properties new file mode 100644 index 0000000000..29d7cc9bd6 --- /dev/null +++ b/Ingest/nbproject/suite.properties @@ -0,0 +1 @@ +suite.dir=${basedir}/.. diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Ingest/src/org/sleuthkit/autopsy/ingest/Bundle.properties new file mode 100644 index 0000000000..3efb782510 --- /dev/null +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -0,0 +1,9 @@ +CTL_IngestAction=Ingest +CTL_IngestTopComponent=Ingest +HINT_IngestTopComponent=Ingest window +OpenIDE-Module-Name=Ingest +IngestTopComponent.topLable.text=Image ingest services +IngestTopComponent.startButton.text=Start +IngestTopComponent.refreshFreqLabel.text=Refresh frequency +IngestTopComponent.fileProgressLabel.text=File progress +IngestTopComponent.imageProgressLabel.text=Image progress diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java new file mode 100644 index 0000000000..66e0612e67 --- /dev/null +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -0,0 +1,206 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.ingest; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; +import javax.swing.SwingUtilities; +import org.openide.util.Lookup; +import org.sleuthkit.datamodel.FsContent; +import org.sleuthkit.datamodel.Image; + +/** + * IngestManager sets up and manages ingest services + * runs them in a background thread + * notifies services when work is complete or should be interrupted + * processes messages from services in postMessage() and posts them to GUI + * + */ +public class IngestManager { + + private static final Logger logger = Logger.getLogger(IngestManager.class.getName()); + private IngestTopComponent tc; + private IngestManagerStats stats; + private int updateFrequency; + + + + /** + * + * @param tc handle to Ingest top component + */ + IngestManager(IngestTopComponent tc) { + this.tc = tc; + stats = new IngestManagerStats(); + } + + /** + * IngestManager entry point, enqueues image to be processed. + * Spawns background thread which enumerates all sorted files and executes chosen services per file in a pre-determined order. + * Notifies services when work is complete or should be interrupted using complete() and stop() calls. + * Does not block and can be called multiple times to enqueue more work to already running background process. + */ + void execute(Collection services, Image image) { + } + + /** + * returns the current minimal update frequency setting + * Services should call this between processing iterations to get current setting + * and use the setting to change notification and data refresh intervals + */ + public synchronized int getUpdateFrequency() { + return updateFrequency; + } + + /** + * set new minimal update frequency services should use + * @param frequency + */ + synchronized void setUpdateFrequency(int frequency) { + this.updateFrequency = frequency; + } + + /** + * returns ingest summary report (how many files ingested, any errors, etc) + */ + String getReport() { + return stats.toString(); + } + + /** + * Service publishes message using InegestManager handle + * Does not block. + * The message gets enqueued in the GUI thread and displayed in a widget + * IngestService should make an attempt not to publish the same message multiple times. + * Viewer will attempt to identify duplicate messages and filter them out (slower) + */ + public synchronized void postMessage(final IngestMessage message) { + + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + tc.displayMessage(message); + } + }); + } + + /** + * helper to return all image services managed (using Lookup API) + */ + public static Collection enumerateImageServices() { + return (Collection) Lookup.getDefault().lookupAll(IngestServiceImage.class); + } + + /** + * helper to return all file/dir services managed (using Lookup API) + */ + public static Collection enumerateFsContentServices() { + return (Collection) Lookup.getDefault().lookupAll(IngestServiceFsContent.class); + } + + /** + * get next file/dir to process + * the queue of FsContent to process is maintained internally + * and could be dynamically sorted as data comes in + */ + private synchronized FsContent getNextFsContent() { + return null; + } + + private synchronized boolean hasNextFsContent() { + return true; + } + + /** + * get next Image to process + * the queue of Images to process is maintained internally + * and could be dynamically sorted as data comes in + */ + private synchronized Image getNextImage() { + return null; + } + + private synchronized boolean hasNextImage() { + return true; + } + + /** + * collects IngestManager statistics during runtime + */ + private static class IngestManagerStats { + + Date startTime; + Date endTime; + int errorsTotal; + Map errors; + private static DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + IngestManagerStats() { + errors = new HashMap(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (startTime != null) { + sb.append("Start time: ").append(dateFormatter.format(startTime)); + } + if (endTime != null) { + sb.append("End time: ").append(dateFormatter.format(endTime)); + } + sb.append("Total ingest time: ").append(getTotalTime()); + sb.append("Total errors: ").append(errorsTotal); + if (errorsTotal > 0) { + sb.append("Errors per service:"); + for (IngestServiceAbstract service : errors.keySet()) { + final int errorsService = errors.get(service); + sb.append("\t").append(service.getName()).append(": ").append(errorsService); + } + } + return sb.toString(); + } + + void start() { + startTime = new Date(); + } + + void end() { + endTime = new Date(); + } + + long getTotalTime() { + if (startTime == null || endTime == null) { + return 0; + } + return endTime.getTime() - startTime.getTime(); + } + + void addError(IngestServiceAbstract source) { + ++errorsTotal; + int curServiceError = errors.get(source); + errors.put(source, curServiceError + 1); + } + } +} diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessage.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessage.java new file mode 100644 index 0000000000..95a86cdff9 --- /dev/null +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestMessage.java @@ -0,0 +1,142 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.ingest; + +import org.sleuthkit.autopsy.datamodel.KeyValueThing; + +/** + * Representation of text posted by ingest services + * + * Message should have a unique ID within context of originating source + * + */ +public class IngestMessage { + + public enum MessageType { + + DATA, INFO, WARNING, ERROR + }; + + private long ID; + private MessageType messageType; + private IngestServiceAbstract source; + private String text; + private KeyValueThing data; + + private IngestMessage(long ID, MessageType messageType, IngestServiceAbstract source, String text) { + this.ID = ID; + this.source = source; + this.messageType = messageType; + this.text = text; + } + + //getters + public long getID() { + return ID; + } + + public IngestServiceAbstract getSource() { + return source; + } + + public String getText() { + return text; + } + + public KeyValueThing getData() { + return data; + } + + public MessageType getMessageType() { + return messageType; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(Long.toString(ID)).append(": "); + sb.append("type: ").append(messageType.name()); + sb.append("source: ").append(source.getName()); + sb.append("text: ").append(text); + if (data != null) + sb.append("data: ").append(data.toString()); + return sb.toString(); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final IngestMessage other = (IngestMessage) obj; + if (this.ID != other.ID) { + return false; + } + if (this.messageType != other.messageType) { + return false; + } + if (this.source != other.source && (this.source == null || !this.source.equals(other.source))) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 83 * hash + (int) (this.ID ^ (this.ID >>> 32)); + hash = 83 * hash + (this.messageType != null ? this.messageType.hashCode() : 0); + hash = 83 * hash + (this.source != null ? this.source.hashCode() : 0); + hash = 83 * hash + (this.text != null ? this.text.hashCode() : 0); + return hash; + } + + + + + //factory methods + public static IngestMessage createMessage(long ID, MessageType messageType, IngestServiceAbstract source, String message) { + if (messageType == null || source == null || message == null) { + throw new IllegalArgumentException("message type, source and message cannot be null"); + } + IngestMessage im = new IngestMessage(ID, messageType, source, message); + return im; + } + + public static IngestMessage createErrorMessage(long ID, IngestServiceAbstract source, String message) { + if (source == null || message == null) { + throw new IllegalArgumentException("message type, source and message cannot be null"); + } + IngestMessage im = new IngestMessage(ID, MessageType.ERROR, source, message); + return im; + } + + public static IngestMessage createDataMessage(long ID, IngestServiceAbstract source, String message, KeyValueThing data) { + if (source == null || message == null) { + throw new IllegalArgumentException("source and message cannot be null"); + } + IngestMessage im = new IngestMessage(ID, MessageType.DATA, source, message); + im.data = data; + return im; + } + +} diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestServiceAbstract.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestServiceAbstract.java new file mode 100644 index 0000000000..fe683cf154 --- /dev/null +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestServiceAbstract.java @@ -0,0 +1,51 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.sleuthkit.autopsy.ingest; + +/** + * Base interface for ingest services + */ +public interface IngestServiceAbstract { + + /** + * notification from manager that brand new processing should be initiated. + * Service loads its configuration and performs initialization + * + * @param IngestManager handle to the manager to postMessage() to + */ + public void init(IngestManager manager); + + /** + * notification from manager that there is no more content to process and all work is done. + * Service performs any clean-up, notifies viewers and may also write results to the black-board + */ + public void complete(); + + /** + * notification from manager to stop processing due to some interruption (user, error, exception) + */ + public void stop(); + + /** + * get specific name of the service + * should be unique across services, a user-friendly name of the service shown in GUI + */ + public String getName(); +} diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestServiceFsContent.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestServiceFsContent.java new file mode 100644 index 0000000000..23701b7885 --- /dev/null +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestServiceFsContent.java @@ -0,0 +1,36 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.ingest; + +import org.sleuthkit.datamodel.FsContent; + +/** + * ingest service that acts on every FsContent in image + * + */ +public interface IngestServiceFsContent extends IngestServiceAbstract { + + /** + * notification from manager to process file / directory. + * Service may choose to perform an action or enqueue processing of a group of FsContents. + * The service notifies viewers via IngestManager.postMessage() + * and may also write results to the black-board as it is processing + */ + public void process(FsContent fsContent); +} diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestServiceImage.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestServiceImage.java new file mode 100644 index 0000000000..6eb7cfe124 --- /dev/null +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestServiceImage.java @@ -0,0 +1,35 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.ingest; + +import org.sleuthkit.datamodel.Image; + +/** + * ingest service that acts on entire image (such as Internet history) + * + */ +public interface IngestServiceImage extends IngestServiceAbstract { + + /** + * notification from manager to process image + * The service notifies viewers via IngestManager.postMessage() + * and may also write results to the black-board as it is processing. + */ + public void process(Image image); +} \ No newline at end of file diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form new file mode 100644 index 0000000000..c6bc17e530 --- /dev/null +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.form @@ -0,0 +1,201 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java new file mode 100644 index 0000000000..ebe0f8e982 --- /dev/null +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/IngestTopComponent.java @@ -0,0 +1,332 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.ingest; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.BoxLayout; +import javax.swing.JCheckBox; +import javax.swing.JScrollPane; +import javax.swing.JSlider; +import org.openide.util.NbBundle; +import org.openide.windows.TopComponent; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataExplorer; + +/** + * Top component explorer for the Ingest module. + */ +public final class IngestTopComponent extends TopComponent implements DataExplorer { + + private static IngestTopComponent instance; + private static final Logger logger = Logger.getLogger(IngestTopComponent.class.getName()); + private IngestManager manager = null; + private Collection services; + private Map serviceStates; + private ActionListener serviceSelListener = new ActionListener() { + + @Override + public void actionPerformed(ActionEvent ev) { + JCheckBox box = (JCheckBox) ev.getSource(); + serviceStates.put(box.getName(), box.isSelected()); + } + }; + + private IngestTopComponent() { + manager = new IngestManager(this); + services = new ArrayList(); + serviceStates = new HashMap(); + initComponents(); + customizeComponents(); + setName(NbBundle.getMessage(IngestTopComponent.class, "CTL_IngestTopComponent")); + setToolTipText(NbBundle.getMessage(IngestTopComponent.class, "HINT_IngestTopComponent")); + //putClientProperty(TopComponent.PROP_UNDOCKING_DISABLED, Boolean.TRUE); + putClientProperty(TopComponent.PROP_CLOSING_DISABLED, Boolean.TRUE); + + } + + public static synchronized IngestTopComponent getDefault() { + if (instance == null) { + instance = new IngestTopComponent(); + } + return instance; + } + + @Override + public TopComponent getTopComponent() { + return this; + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + logger.log(Level.INFO, "Unhandled property change: " + evt.getPropertyName()); + } + + @Override + public int getPersistenceType() { + return TopComponent.PERSISTENCE_NEVER; + } + + private void customizeComponents() { + //custom GUI setup not done by builder + freqSlider.setToolTipText("Lower update frequency can optimize performance of certain ingest services, but also reduce real time status feedback"); + + JScrollPane scrollPane = new JScrollPane(servicesPanel); + scrollPane.setPreferredSize(this.getSize()); + this.add(scrollPane, BorderLayout.CENTER); + + servicesPanel.setLayout(new BoxLayout(servicesPanel, BoxLayout.Y_AXIS)); + + Collection imageServices = IngestManager.enumerateImageServices(); + for (IngestServiceImage service : imageServices) { + services.add(service); + JCheckBox checkbox = new JCheckBox(service.getName(), true); + checkbox.addActionListener(serviceSelListener); + servicesPanel.add(checkbox); + } + + Collection fsServices = IngestManager.enumerateFsContentServices(); + for (IngestServiceFsContent service : fsServices) { + services.add(service); + JCheckBox checkbox = new JCheckBox(service.getName(), true); + checkbox.addActionListener(serviceSelListener); + servicesPanel.add(checkbox); + } + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + mainScrollPane = new javax.swing.JScrollPane(); + mainPanel = new javax.swing.JPanel(); + topLable = new javax.swing.JLabel(); + servicesPanel = new javax.swing.JPanel(); + freqSlider = new javax.swing.JSlider(); + startButton = new javax.swing.JButton(); + refreshFreqLabel = new javax.swing.JLabel(); + imageProgressBar = new javax.swing.JProgressBar(); + imageProgressLabel = new javax.swing.JLabel(); + jProgressBar1 = new javax.swing.JProgressBar(); + fileProgressLabel = new javax.swing.JLabel(); + + mainScrollPane.setPreferredSize(new java.awt.Dimension(289, 509)); + + topLable.setFont(new java.awt.Font("Tahoma", 0, 12)); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(topLable, org.openide.util.NbBundle.getMessage(IngestTopComponent.class, "IngestTopComponent.topLable.text")); // NOI18N + + servicesPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0))); + servicesPanel.setMinimumSize(new java.awt.Dimension(200, 150)); + servicesPanel.setPreferredSize(new java.awt.Dimension(200, 150)); + + javax.swing.GroupLayout servicesPanelLayout = new javax.swing.GroupLayout(servicesPanel); + servicesPanel.setLayout(servicesPanelLayout); + servicesPanelLayout.setHorizontalGroup( + servicesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 198, Short.MAX_VALUE) + ); + servicesPanelLayout.setVerticalGroup( + servicesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 148, Short.MAX_VALUE) + ); + + freqSlider.setMajorTickSpacing(1); + freqSlider.setMaximum(10); + freqSlider.setMinimum(1); + freqSlider.setPaintLabels(true); + freqSlider.setPaintTicks(true); + freqSlider.setSnapToTicks(true); + freqSlider.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + freqSliderStateChanged(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(startButton, org.openide.util.NbBundle.getMessage(IngestTopComponent.class, "IngestTopComponent.startButton.text")); // NOI18N + startButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + startButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(refreshFreqLabel, org.openide.util.NbBundle.getMessage(IngestTopComponent.class, "IngestTopComponent.refreshFreqLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(imageProgressLabel, org.openide.util.NbBundle.getMessage(IngestTopComponent.class, "IngestTopComponent.imageProgressLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(fileProgressLabel, org.openide.util.NbBundle.getMessage(IngestTopComponent.class, "IngestTopComponent.fileProgressLabel.text")); // NOI18N + + javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel); + mainPanel.setLayout(mainPanelLayout); + mainPanelLayout.setHorizontalGroup( + mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(mainPanelLayout.createSequentialGroup() + .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, mainPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(topLable)) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, mainPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(jProgressBar1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(imageProgressBar, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(servicesPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(freqSlider, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .addGap(173, 173, 173)) + .addGroup(mainPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(startButton) + .addContainerGap(316, Short.MAX_VALUE)) + .addGroup(mainPanelLayout.createSequentialGroup() + .addGap(81, 81, 81) + .addComponent(imageProgressLabel) + .addContainerGap(227, Short.MAX_VALUE)) + .addGroup(mainPanelLayout.createSequentialGroup() + .addGap(74, 74, 74) + .addComponent(refreshFreqLabel) + .addContainerGap(219, Short.MAX_VALUE)) + .addGroup(mainPanelLayout.createSequentialGroup() + .addGap(84, 84, 84) + .addComponent(fileProgressLabel) + .addContainerGap(238, Short.MAX_VALUE)) + ); + mainPanelLayout.setVerticalGroup( + mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(mainPanelLayout.createSequentialGroup() + .addGap(24, 24, 24) + .addComponent(topLable) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(servicesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(startButton) + .addGap(18, 18, 18) + .addComponent(freqSlider, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(refreshFreqLabel) + .addGap(28, 28, 28) + .addComponent(imageProgressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(imageProgressLabel) + .addGap(27, 27, 27) + .addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(fileProgressLabel) + .addContainerGap(75, Short.MAX_VALUE)) + ); + + mainScrollPane.setViewportView(mainPanel); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 289, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(mainScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 509, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + private void startButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startButtonActionPerformed + //pick the services + ListservicesToStart = new ArrayList(); + for (IngestServiceAbstract service : services) { + boolean serviceEnabled = serviceStates.get(service.getName()); + if (serviceEnabled) + servicesToStart.add(service); + } + + //pick the image + //TODO which image ? just enqueue all, and manager will skip already processed image + + manager.execute(services, null); + }//GEN-LAST:event_startButtonActionPerformed + + private void freqSliderStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_freqSliderStateChanged + JSlider source = (JSlider) evt.getSource(); + if (!source.getValueIsAdjusting()) { + final int refresh = (int) source.getValue(); + manager.setUpdateFrequency(refresh); + + } + }//GEN-LAST:event_freqSliderStateChanged + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel fileProgressLabel; + private javax.swing.JSlider freqSlider; + private javax.swing.JProgressBar imageProgressBar; + private javax.swing.JLabel imageProgressLabel; + private javax.swing.JProgressBar jProgressBar1; + private javax.swing.JPanel mainPanel; + private javax.swing.JScrollPane mainScrollPane; + private javax.swing.JLabel refreshFreqLabel; + private javax.swing.JPanel servicesPanel; + private javax.swing.JButton startButton; + private javax.swing.JLabel topLable; + // End of variables declaration//GEN-END:variables + + @Override + public void componentOpened() { + logger.log(Level.INFO, "IngestTopComponent opened()"); + } + + @Override + public void componentClosed() { + logger.log(Level.INFO, "IngestTopComponent closed()"); + } + + void writeProperties(java.util.Properties p) { + // better to version settings since initial version as advocated at + // http://wiki.apidesign.org/wiki/PropertyFiles + p.setProperty("version", "1.0"); + + } + + void readProperties(java.util.Properties p) { + String version = p.getProperty("version"); + + } + + /** + * Display ingest summary report in some dialog + */ + void displayReport(String ingestReport) { + //TODO widget + logger.log(Level.INFO, "INGEST REPORT: " + ingestReport); + } + + /** + * Display IngestMessage from service (forwarded by IngestManager) + */ + void displayMessage(IngestMessage ingestMessage) { + //TODO widget + logger.log(Level.INFO, "INGEST MESSAGE: " + ingestMessage.toString()); + } +} diff --git a/Ingest/src/org/sleuthkit/autopsy/ingest/layer.xml b/Ingest/src/org/sleuthkit/autopsy/ingest/layer.xml new file mode 100644 index 0000000000..4c998edccd --- /dev/null +++ b/Ingest/src/org/sleuthkit/autopsy/ingest/layer.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/KeywordSearch/nbproject/genfiles.properties b/KeywordSearch/nbproject/genfiles.properties index cc36a74245..6b82ce00cf 100644 --- a/KeywordSearch/nbproject/genfiles.properties +++ b/KeywordSearch/nbproject/genfiles.properties @@ -3,6 +3,6 @@ build.xml.script.CRC32=87b97b04 build.xml.stylesheet.CRC32=a56c6a5b@1.46.2 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. -nbproject/build-impl.xml.data.CRC32=957d4757 +nbproject/build-impl.xml.data.CRC32=d7ecf067 nbproject/build-impl.xml.script.CRC32=fe1f48d2 -nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.47.1 +nbproject/build-impl.xml.stylesheet.CRC32=238281d1@1.46.2 diff --git a/KeywordSearch/nbproject/project.xml b/KeywordSearch/nbproject/project.xml index 3dad2b3c4c..7059590a8d 100644 --- a/KeywordSearch/nbproject/project.xml +++ b/KeywordSearch/nbproject/project.xml @@ -117,6 +117,15 @@ 1.0 + + org.sleuthkit.autopsy.ingest + + + + 0-1 + 1.0 + + org.sleuthkit.autopsy.keywordsearch diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchDataExplorer.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchDataExplorer.java index 7082e80cfc..ab0e9a6d8e 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchDataExplorer.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchDataExplorer.java @@ -32,15 +32,13 @@ import org.sleuthkit.autopsy.keywordsearch.KeywordSearchQueryManager.Presentatio /** * Provides a data explorer to perform Solr searches with */ -@ServiceProvider(service = DataExplorer.class, position = 300) public class KeywordSearchDataExplorer implements DataExplorer { - private static KeywordSearchDataExplorer theInstance; + private static KeywordSearchDataExplorer theInstance = null; private KeywordSearchTabsTopComponent tc; private int filesIndexed; - public KeywordSearchDataExplorer() { - this.setTheInstance(); + private KeywordSearchDataExplorer() { this.filesIndexed = 0; this.tc = new KeywordSearchTabsTopComponent(); @@ -64,12 +62,11 @@ public class KeywordSearchDataExplorer implements DataExplorer { KeywordSearch.changeSupport.addPropertyChangeListener(KeywordSearch.NUM_FILES_CHANGE_EVT, new IndexChangeListener()); } - private synchronized void setTheInstance() { + public static synchronized KeywordSearchDataExplorer getDefault() { if (theInstance == null) { - theInstance = this; - } else { - throw new RuntimeException("Tried to instantiate mulitple instances of KeywordSearchTopComponent."); - } + theInstance = new KeywordSearchDataExplorer(); + } + return theInstance; } /** diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestService.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestService.java new file mode 100644 index 0000000000..ca3c433baa --- /dev/null +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestService.java @@ -0,0 +1,64 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.keywordsearch; + +import java.util.logging.Level; +import java.util.logging.Logger; +import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.ingest.IngestServiceFsContent; +import org.sleuthkit.datamodel.FsContent; + +//service provider registered in layer.xml +public final class KeywordSearchIngestService implements IngestServiceFsContent { + + private static final Logger logger = Logger.getLogger(KeywordSearchIngestService.class.getName()); + private static KeywordSearchIngestService instance = null; + + public static synchronized KeywordSearchIngestService getDefault() { + if (instance == null) { + instance = new KeywordSearchIngestService(); + } + return instance; + } + + @Override + public void process(FsContent fsContent) { + logger.log(Level.INFO, "Processing fsContent: " + fsContent.getName()); + } + + @Override + public void complete() { + logger.log(Level.INFO, "complete()"); + } + + @Override + public String getName() { + return "Keyword Search"; + } + + @Override + public void init(IngestManager manager) { + logger.log(Level.INFO, "init()"); + } + + @Override + public void stop() { + logger.log(Level.INFO, "stop()"); + } +} diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/layer.xml b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/layer.xml index 40f6e5e00b..06e2d7629d 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/layer.xml +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/layer.xml @@ -1,3 +1,16 @@ - + + + + + + + + + + + + + + diff --git a/nbproject/project.properties b/nbproject/project.properties index cce454d130..6e6debae3a 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -18,13 +18,15 @@ modules=\ ${project.org.sleuthkit.autopsy.datamodel}:\ ${project.org.sleuthkit.autopsy.casemodule}:\ ${project.org.sleuthkit.autopsy.keywordsearch}:\ - ${project.org.sleuthkit.autopsy.coreutils} + ${project.org.sleuthkit.autopsy.coreutils}:\ + ${project.org.sleuthkit.autopsy.ingest} project.org.sleuthkit.autopsy.casemodule=Case project.org.sleuthkit.autopsy.corecomponentinterfaces=CoreComponentInterfaces project.org.sleuthkit.autopsy.corecomponents=CoreComponents project.org.sleuthkit.autopsy.coreutils=CoreUtils project.org.sleuthkit.autopsy.directorytree=DirectoryTree project.org.sleuthkit.autopsy.filesearch=FileSearch +project.org.sleuthkit.autopsy.ingest=Ingest project.org.sleuthkit.autopsy.keywordsearch=KeywordSearch project.org.sleuthkit.autopsy.menuactions=MenuActions project.org.sleuthkit.autopsy.datamodel=DataModel