From e52591abba63d6870577773be55b79511d8c138e Mon Sep 17 00:00:00 2001 From: Sean-M <Smoss117@gmail.com> Date: Wed, 6 Mar 2013 18:20:09 -0500 Subject: [PATCH] to be merged --- .../KeywordSearchConfigurationPanel1.java | 2 +- .../KeywordSearchEditListPanel.java | 8 +- .../KeywordSearchIngestModule.java | 14 +- .../KeywordSearchIngestSimplePanel.java | 8 +- .../KeywordSearchListsAbstract.java | 1050 ++++++++--------- .../KeywordSearchListsManagementPanel.form | 2 +- .../KeywordSearchListsManagementPanel.java | 6 +- .../KeywordSearchListsViewerPanel.java | 20 +- .../KeywordSearchResultFactory.java | 2 +- Testing/nbproject/project.xml | 9 + .../autopsy/testing/RegressionTest.java | 3 + 11 files changed, 568 insertions(+), 556 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchConfigurationPanel1.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchConfigurationPanel1.java index d22390f0a9..f40185e96b 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchConfigurationPanel1.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchConfigurationPanel1.java @@ -80,7 +80,7 @@ public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) { final String FEATURE_NAME = "Save Keyword List"; KeywordSearchListsXML writer = KeywordSearchListsXML.getCurrent(); - KeywordSearchList currentKeywordList = editListPanel.getCurrentKeywordList(); + KeywordSearchListsAbstract.KeywordSearchList currentKeywordList = editListPanel.getCurrentKeywordList(); List<Keyword> keywords = currentKeywordList.getKeywords(); if (keywords.isEmpty()) { diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchEditListPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchEditListPanel.java index c8657a0026..a720dde3ba 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchEditListPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchEditListPanel.java @@ -57,7 +57,7 @@ class KeywordSearchEditListPanel extends javax.swing.JPanel implements ListSelec private static Logger logger = Logger.getLogger(KeywordSearchEditListPanel.class.getName()); private KeywordTableModel tableModel; - private KeywordSearchList currentKeywordList; + private KeywordSearchListsAbstract.KeywordSearchList currentKeywordList; private boolean ingestRunning; @@ -608,7 +608,7 @@ private void exportButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN- KeywordSearchListsXML reader = KeywordSearchListsXML.getCurrent(); - List<KeywordSearchList> toWrite = new ArrayList<KeywordSearchList>(); + List<KeywordSearchListsAbstract.KeywordSearchList> toWrite = new ArrayList<KeywordSearchListsAbstract.KeywordSearchList>(); toWrite.add(reader.getList(currentKeywordList.getName())); final KeywordSearchListsXML exporter = new KeywordSearchListsXML(fileAbs); boolean written = exporter.saveLists(toWrite); @@ -693,11 +693,11 @@ public void load() { // Implemented by parent panel } - KeywordSearchList getCurrentKeywordList() { + KeywordSearchListsAbstract.KeywordSearchList getCurrentKeywordList() { return currentKeywordList; } - void setCurrentKeywordList(KeywordSearchList list) { + void setCurrentKeywordList(KeywordSearchListsAbstract.KeywordSearchList list) { currentKeywordList = list; } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java index 0545b7c97f..4bb259b9b7 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestModule.java @@ -101,7 +101,7 @@ int getTime() { private volatile boolean runSearcher = false; //whether to run searcher next time private List<Keyword> keywords; //keywords to search private List<String> keywordLists; // lists currently being searched - private Map<String, KeywordSearchList> keywordToList; //keyword to list name mapping + private Map<String, KeywordSearchListsAbstract.KeywordSearchList> keywordToList; //keyword to list name mapping private Timer commitTimer; private Timer searchTimer; private Indexer indexer; @@ -380,7 +380,7 @@ public void init(IngestModuleInit initContext) { keywords = new ArrayList<Keyword>(); keywordLists = new ArrayList<String>(); - keywordToList = new HashMap<String, KeywordSearchList>(); + keywordToList = new HashMap<String, KeywordSearchListsAbstract.KeywordSearchList>(); initKeywords(); @@ -566,7 +566,7 @@ void addKeywordLists(List<String> listsToAdd) { StringBuilder sb = new StringBuilder(); - for (KeywordSearchList list : loader.getListsL()) { + for (KeywordSearchListsAbstract.KeywordSearchList list : loader.getListsL()) { final String listName = list.getName(); if (list.getUseForIngest() == true || (listsToAdd != null && listsToAdd.contains(listName))) { @@ -798,7 +798,7 @@ private final class Searcher extends SwingWorker<Object, Void> { */ private List<Keyword> keywords; //keywords to search private List<String> keywordLists; // lists currently being searched - private Map<String, KeywordSearchList> keywordToList; //keyword to list name mapping + private Map<String, KeywordSearchListsAbstract.KeywordSearchList> keywordToList; //keyword to list name mapping private AggregateProgressHandle progressGroup; private final Logger logger = Logger.getLogger(Searcher.class.getName()); private boolean finalRun = false; @@ -806,7 +806,7 @@ private final class Searcher extends SwingWorker<Object, Void> { Searcher(List<String> keywordLists) { this.keywordLists = new ArrayList<String>(keywordLists); this.keywords = new ArrayList<Keyword>(); - this.keywordToList = new HashMap<String, KeywordSearchList>(); + this.keywordToList = new HashMap<String, KeywordSearchListsAbstract.KeywordSearchList>(); //keywords are populated as searcher runs } @@ -874,7 +874,7 @@ public boolean cancel() { } final String queryStr = keywordQuery.getQuery(); - final KeywordSearchList list = keywordToList.get(queryStr); + final KeywordSearchListsAbstract.KeywordSearchList list = keywordToList.get(queryStr); final String listName = list.getName(); //new subProgress will be active after the initial query @@ -1110,7 +1110,7 @@ private void updateKeywords() { this.keywordToList.clear(); for (String name : this.keywordLists) { - KeywordSearchList list = loader.getList(name); + KeywordSearchListsAbstract.KeywordSearchList list = loader.getList(name); for (Keyword k : list.getKeywords()) { this.keywords.add(k); this.keywordToList.put(k.getQuery(), list); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestSimplePanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestSimplePanel.java index e3e91e5e57..35b9459405 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestSimplePanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchIngestSimplePanel.java @@ -38,12 +38,12 @@ public class KeywordSearchIngestSimplePanel extends javax.swing.JPanel { private final static Logger logger = Logger.getLogger(KeywordSearchIngestSimplePanel.class.getName()); public static final String PROP_OPTIONS = "Keyword Search_Options"; private KeywordTableModel tableModel; - private List<KeywordSearchList> lists; + private List<KeywordSearchListsAbstract.KeywordSearchList> lists; /** Creates new form KeywordSearchIngestSimplePanel */ public KeywordSearchIngestSimplePanel() { tableModel = new KeywordTableModel(); - lists = new ArrayList<KeywordSearchList>(); + lists = new ArrayList<KeywordSearchListsAbstract.KeywordSearchList>(); reloadLists(); initComponents(); customizeComponents(); @@ -222,7 +222,7 @@ public int getColumnCount() { @Override public Object getValueAt(int rowIndex, int columnIndex) { - KeywordSearchList list = KeywordSearchIngestSimplePanel.this.lists.get(rowIndex); + KeywordSearchListsAbstract.KeywordSearchList list = KeywordSearchIngestSimplePanel.this.lists.get(rowIndex); if(columnIndex == 0) { return list.getUseForIngest(); } else { @@ -238,7 +238,7 @@ public boolean isCellEditable(int rowIndex, int columnIndex) { @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { - KeywordSearchList list = KeywordSearchIngestSimplePanel.this.lists.get(rowIndex); + KeywordSearchListsAbstract.KeywordSearchList list = KeywordSearchIngestSimplePanel.this.lists.get(rowIndex); if(columnIndex == 0){ KeywordSearchListsXML loader = KeywordSearchListsXML.getCurrent(); loader.addList(list.getName(), list.getKeywords(), (Boolean) aValue, false); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsAbstract.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsAbstract.java index de8e96dae8..23193818f1 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsAbstract.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsAbstract.java @@ -1,526 +1,526 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 Basis Technology Corp. - * Contact: carrier <at> sleuthkit <dot> org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.keywordsearch; - -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.io.File; -import java.util.ArrayList; -import java.util.Date; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.datamodel.BlackboardAttribute; - -/** - * Keyword list saving, loading, and editing abstract class. - */ -public abstract class KeywordSearchListsAbstract { - - protected String filePath; - Map<String, KeywordSearchList> theLists; //the keyword data - static KeywordSearchListsXML currentInstance = null; - private static final String CUR_LISTS_FILE_NAME = "keywords.xml"; - private static String CUR_LISTS_FILE = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_LISTS_FILE_NAME; - protected static final Logger logger = Logger.getLogger(KeywordSearchListsAbstract.class.getName()); - PropertyChangeSupport changeSupport; - protected List<String> lockedLists; - - public KeywordSearchListsAbstract(String filePath) { - this.filePath = filePath; - theLists = new LinkedHashMap<String, KeywordSearchList>(); - lockedLists = new ArrayList<String>(); - changeSupport = new PropertyChangeSupport(this); - } - - //property support - public enum ListsEvt { - - LIST_ADDED, LIST_DELETED, LIST_UPDATED - }; - - /** - * get instance for managing the current keyword list of the application - */ - static KeywordSearchListsXML getCurrent() { - if (currentInstance == null) { - currentInstance = new KeywordSearchListsXML(CUR_LISTS_FILE); - currentInstance.reload(); - } - return currentInstance; - } - - void addPropertyChangeListener(PropertyChangeListener l) { - changeSupport.addPropertyChangeListener(l); - } - - private void prepopulateLists() { - if (! theLists.isEmpty()) { - return; - } - //phone number - List<Keyword> phones = new ArrayList<Keyword>(); - phones.add(new Keyword("[(]{0,1}\\d\\d\\d[)]{0,1}[\\.-]\\d\\d\\d[\\.-]\\d\\d\\d\\d", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)); - //phones.add(new Keyword("\\d{8,10}", false)); - //IP address - List<Keyword> ips = new ArrayList<Keyword>(); - ips.add(new Keyword("(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IP_ADDRESS)); - //email - List<Keyword> emails = new ArrayList<Keyword>(); - emails.add(new Keyword("[A-Z0-9._%-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL)); - //URL - List<Keyword> urls = new ArrayList<Keyword>(); - //urls.add(new Keyword("http://|https://|^www\\.", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL)); - urls.add(new Keyword("((((ht|f)tp(s?))\\://)|www\\.)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,5})(\\:[0-9]+)*(/($|[a-zA-Z0-9\\.\\,\\;\\?\\'\\\\+&%\\$#\\=~_\\-]+))*", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL)); - - //urls.add(new Keyword("ssh://", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL)); - - //disable messages for harcoded/locked lists - String name; - - name = "Phone Numbers"; - lockedLists.add(name); - addList(name, phones, false, false, true); - - name = "IP Addresses"; - lockedLists.add(name); - addList(name, ips, false, false, true); - - name = "Email Addresses"; - lockedLists.add(name); - addList(name, emails, true, false, true); - - name = "URLs"; - lockedLists.add(name); - addList(name, urls, false, false, true); - } - - /** - * load the file or create new - */ - public void reload() { - boolean created = false; - - //theLists.clear(); - //populate only the first time - prepopulateLists(); - - //reset all the lists other than locked lists (we don't save them to XML) - //we want to preserve state of locked lists - List<String> toClear = new ArrayList<String>(); - for (String list : theLists.keySet()) { - if (theLists.get(list).isLocked() == false) { - toClear.add(list); - } - } - for (String clearList : toClear) { - theLists.remove(clearList); - } - - if (!this.listFileExists()) { - //create new if it doesn't exist - save(); - created = true; - } - - //load, if fails to laod create new - if (!load() && !created) { - //create new if failed to load - save(); - } - - - } - - List<KeywordSearchList> getListsL() { - List<KeywordSearchList> ret = new ArrayList<KeywordSearchList>(); - for (KeywordSearchList list : theLists.values()) { - ret.add(list); - } - return ret; - } - - List<KeywordSearchList> getListsL(boolean locked) { - List<KeywordSearchList> ret = new ArrayList<KeywordSearchList>(); - for (KeywordSearchList list : theLists.values()) { - if (list.isLocked().equals(locked)) { - ret.add(list); - } - } - return ret; - } - - /** - * Get list names of all loaded keyword list names - * - * @return List of keyword list names - */ - List<String> getListNames() { - return new ArrayList<String>(theLists.keySet()); - } - - /** - * Get list names of all locked or unlocked loaded keyword list names - * - * @param locked true if look for locked lists, false otherwise - * @return List of keyword list names - */ - List<String> getListNames(boolean locked) { - ArrayList<String> lists = new ArrayList<String>(); - for (String listName : theLists.keySet()) { - KeywordSearchList list = theLists.get(listName); - if (locked == list.isLocked()) { - lists.add(listName); - } - } - - return lists; - } - - /** - * return first list that contains the keyword - * - * @param keyword - * @return found list or null - */ - KeywordSearchList getListWithKeyword(Keyword keyword) { - KeywordSearchList found = null; - for (KeywordSearchList list : theLists.values()) { - if (list.hasKeyword(keyword)) { - found = list; - break; - } - } - return found; - } - - /** - * return first list that contains the keyword - * - * @param keyword - * @return found list or null - */ - KeywordSearchList getListWithKeyword(String keyword) { - KeywordSearchList found = null; - for (KeywordSearchList list : theLists.values()) { - if (list.hasKeyword(keyword)) { - found = list; - break; - } - } - return found; - } - - /** - * get number of lists currently stored - * - * @return number of lists currently stored - */ - int getNumberLists() { - return theLists.size(); - } - - /** - * get number of unlocked or locked lists currently stored - * - * @param locked true if look for locked lists, false otherwise - * @return number of unlocked lists currently stored - */ - int getNumberLists(boolean locked) { - int numLists = 0; - for (String listName : theLists.keySet()) { - KeywordSearchList list = theLists.get(listName); - if (locked == list.isLocked()) { - ++numLists; - } - } - return numLists; - } - - /** - * get list by name or null - * - * @param name id of the list - * @return keyword list representation - */ - KeywordSearchList getList(String name) { - return theLists.get(name); - } - - /** - * check if list with given name id exists - * - * @param name id to check - * @return true if list already exists or false otherwise - */ - boolean listExists(String name) { - return getList(name) != null; - } - - /** - * adds the new word list using name id replacing old one if exists with the - * same name - * - * @param name the name of the new list or list to replace - * @param newList list of keywords - * @param useForIngest should this list be used for ingest - * @return true if old list was replaced - */ - boolean addList(String name, List<Keyword> newList, boolean useForIngest, boolean ingestMessages, boolean locked) { - boolean replaced = false; - KeywordSearchList curList = getList(name); - final Date now = new Date(); - - if (curList == null) { - theLists.put(name, new KeywordSearchList(name, now, now, useForIngest, ingestMessages, newList, locked)); -// if (!locked) { -// save(); -// } - changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, name); - } else { - theLists.put(name, new KeywordSearchList(name, curList.getDateCreated(), now, useForIngest, ingestMessages, newList, locked)); -// if (!locked) { -// save(); -// } - replaced = true; - changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, name); - } - - return replaced; - } - - boolean addList(String name, List<Keyword> newList, boolean useForIngest, boolean ingestMessages) { - //make sure that the list is readded as a locked/built in list - boolean isLocked = this.lockedLists.contains(name); - return addList(name, newList, useForIngest, ingestMessages, isLocked); - } - - boolean addList(String name, List<Keyword> newList) { - boolean isLocked = this.lockedLists.contains(name); - return addList(name, newList, true, isLocked); - } - - boolean addList(KeywordSearchList list) { - return addList(list.getName(), list.getKeywords(), list.getUseForIngest(), list.getIngestMessages(), list.isLocked()); - } - - /** - * save multiple lists - * - * @param lists - * @return - */ - boolean saveLists(List<KeywordSearchList> lists) { - int oldSize = this.getNumberLists(); - - List<KeywordSearchList> overwritten = new ArrayList<KeywordSearchList>(); - List<KeywordSearchList> newLists = new ArrayList<KeywordSearchList>(); - for (KeywordSearchList list : lists) { - if (this.listExists(list.getName())) { - overwritten.add(list); - } else { - newLists.add(list); - } - theLists.put(list.getName(), list); - } - boolean saved = save(true); - if (saved) { - for (KeywordSearchList list : newLists) { - changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, list.getName()); - } - for (KeywordSearchList over : overwritten) { - changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, over.getName()); - } - } - - return saved; - } - - /** - * write out multiple lists - * - * @param lists - * @return - */ - boolean writeLists(List<KeywordSearchList> lists) { - int oldSize = this.getNumberLists(); - - List<KeywordSearchList> overwritten = new ArrayList<KeywordSearchList>(); - List<KeywordSearchList> newLists = new ArrayList<KeywordSearchList>(); - for (KeywordSearchList list : lists) { - if (this.listExists(list.getName())) { - overwritten.add(list); - } else { - newLists.add(list); - } - theLists.put(list.getName(), list); - } - //boolean saved = save(); - - for (KeywordSearchList list : newLists) { - changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, list.getName()); - } - for (KeywordSearchList over : overwritten) { - changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, over.getName()); - } - - return true; - } - - /** - * delete list if exists and save new list - * - * @param name of list to delete - * @return true if deleted - */ - boolean deleteList(String name) { - boolean deleted = false; - KeywordSearchList delList = getList(name); - if (delList != null && !delList.isLocked()) { - theLists.remove(name); - //deleted = save(); - } - changeSupport.firePropertyChange(ListsEvt.LIST_DELETED.toString(), null, name); - return true; - - } - - /** - * writes out current list replacing the last lists file - */ - public abstract boolean save(); - - /** - * writes out current list replacing the last lists file - * @param isExport true is this save operation is an export and not a 'Save - * As' - */ - public abstract boolean save(boolean isExport); - - /** - * load and parse List, then dispose - */ - public abstract boolean load(); - - private boolean listFileExists() { - File f = new File(filePath); - return f.exists() && f.canRead() && f.canWrite(); - } -} - -/** - * a representation of a single keyword list created or loaded - */ -class KeywordSearchList { - - private String name; - private Date created; - private Date modified; - private Boolean useForIngest; - private Boolean ingestMessages; - private List<Keyword> keywords; - private Boolean locked; - - KeywordSearchList(String name, Date created, Date modified, Boolean useForIngest, Boolean ingestMessages, List<Keyword> keywords, boolean locked) { - this.name = name; - this.created = created; - this.modified = modified; - this.useForIngest = useForIngest; - this.ingestMessages = ingestMessages; - this.keywords = keywords; - this.locked = locked; - } - - KeywordSearchList(String name, Date created, Date modified, Boolean useForIngest, Boolean ingestMessages, List<Keyword> keywords) { - this(name, created, modified, useForIngest, ingestMessages, keywords, false); - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final KeywordSearchList other = (KeywordSearchList) obj; - if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - int hash = 5; - return hash; - } - - String getName() { - return name; - } - - Date getDateCreated() { - return created; - } - - Date getDateModified() { - return modified; - } - - Boolean getUseForIngest() { - return useForIngest; - } - - void setUseForIngest(boolean use) { - this.useForIngest = use; - } - - Boolean getIngestMessages() { - return ingestMessages; - } - - void setIngestMessages(boolean ingestMessages) { - this.ingestMessages = ingestMessages; - } - - List<Keyword> getKeywords() { - return keywords; - } - - boolean hasKeyword(Keyword keyword) { - return keywords.contains(keyword); - } - - boolean hasKeyword(String keyword) { - //note, this ignores isLiteral - for (Keyword k : keywords) { - if (k.getQuery().equals(keyword)) { - return true; - } - } - return false; - } - - Boolean isLocked() { - return locked; - } +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier <at> sleuthkit <dot> org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.keywordsearch; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.File; +import java.util.ArrayList; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.datamodel.BlackboardAttribute; + +/** + * Keyword list saving, loading, and editing abstract class. + */ +public abstract class KeywordSearchListsAbstract { + + protected String filePath; + public Map<String, KeywordSearchList> theLists; //the keyword data + static KeywordSearchListsXML currentInstance = null; + private static final String CUR_LISTS_FILE_NAME = "keywords.xml"; + private static String CUR_LISTS_FILE = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_LISTS_FILE_NAME; + protected static final Logger logger = Logger.getLogger(KeywordSearchListsAbstract.class.getName()); + PropertyChangeSupport changeSupport; + protected List<String> lockedLists; + + public KeywordSearchListsAbstract(String filePath) { + this.filePath = filePath; + theLists = new LinkedHashMap<String, KeywordSearchList>(); + lockedLists = new ArrayList<String>(); + changeSupport = new PropertyChangeSupport(this); + } + + //property support + public enum ListsEvt { + + LIST_ADDED, LIST_DELETED, LIST_UPDATED + }; + + /** + * get instance for managing the current keyword list of the application + */ + public static KeywordSearchListsXML getCurrent() { + if (currentInstance == null) { + currentInstance = new KeywordSearchListsXML(CUR_LISTS_FILE); + currentInstance.reload(); + } + return currentInstance; + } + + void addPropertyChangeListener(PropertyChangeListener l) { + changeSupport.addPropertyChangeListener(l); + } + + private void prepopulateLists() { + if (! theLists.isEmpty()) { + return; + } + //phone number + List<Keyword> phones = new ArrayList<Keyword>(); + phones.add(new Keyword("[(]{0,1}\\d\\d\\d[)]{0,1}[\\.-]\\d\\d\\d[\\.-]\\d\\d\\d\\d", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER)); + //phones.add(new Keyword("\\d{8,10}", false)); + //IP address + List<Keyword> ips = new ArrayList<Keyword>(); + ips.add(new Keyword("(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IP_ADDRESS)); + //email + List<Keyword> emails = new ArrayList<Keyword>(); + emails.add(new Keyword("[A-Z0-9._%-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL)); + //URL + List<Keyword> urls = new ArrayList<Keyword>(); + //urls.add(new Keyword("http://|https://|^www\\.", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL)); + urls.add(new Keyword("((((ht|f)tp(s?))\\://)|www\\.)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,5})(\\:[0-9]+)*(/($|[a-zA-Z0-9\\.\\,\\;\\?\\'\\\\+&%\\$#\\=~_\\-]+))*", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL)); + + //urls.add(new Keyword("ssh://", false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL)); + + //disable messages for harcoded/locked lists + String name; + + name = "Phone Numbers"; + lockedLists.add(name); + addList(name, phones, false, false, true); + + name = "IP Addresses"; + lockedLists.add(name); + addList(name, ips, false, false, true); + + name = "Email Addresses"; + lockedLists.add(name); + addList(name, emails, true, false, true); + + name = "URLs"; + lockedLists.add(name); + addList(name, urls, false, false, true); + } + + /** + * load the file or create new + */ + public void reload() { + boolean created = false; + + //theLists.clear(); + //populate only the first time + prepopulateLists(); + + //reset all the lists other than locked lists (we don't save them to XML) + //we want to preserve state of locked lists + List<String> toClear = new ArrayList<String>(); + for (String list : theLists.keySet()) { + if (theLists.get(list).isLocked() == false) { + toClear.add(list); + } + } + for (String clearList : toClear) { + theLists.remove(clearList); + } + + if (!this.listFileExists()) { + //create new if it doesn't exist + save(); + created = true; + } + + //load, if fails to laod create new + if (!load() && !created) { + //create new if failed to load + save(); + } + + + } + + List<KeywordSearchList> getListsL() { + List<KeywordSearchList> ret = new ArrayList<KeywordSearchList>(); + for (KeywordSearchList list : theLists.values()) { + ret.add(list); + } + return ret; + } + + List<KeywordSearchList> getListsL(boolean locked) { + List<KeywordSearchList> ret = new ArrayList<KeywordSearchList>(); + for (KeywordSearchList list : theLists.values()) { + if (list.isLocked().equals(locked)) { + ret.add(list); + } + } + return ret; + } + + /** + * Get list names of all loaded keyword list names + * + * @return List of keyword list names + */ + List<String> getListNames() { + return new ArrayList<String>(theLists.keySet()); + } + + /** + * Get list names of all locked or unlocked loaded keyword list names + * + * @param locked true if look for locked lists, false otherwise + * @return List of keyword list names + */ + List<String> getListNames(boolean locked) { + ArrayList<String> lists = new ArrayList<String>(); + for (String listName : theLists.keySet()) { + KeywordSearchList list = theLists.get(listName); + if (locked == list.isLocked()) { + lists.add(listName); + } + } + + return lists; + } + + /** + * return first list that contains the keyword + * + * @param keyword + * @return found list or null + */ + KeywordSearchList getListWithKeyword(Keyword keyword) { + KeywordSearchList found = null; + for (KeywordSearchList list : theLists.values()) { + if (list.hasKeyword(keyword)) { + found = list; + break; + } + } + return found; + } + + /** + * return first list that contains the keyword + * + * @param keyword + * @return found list or null + */ + KeywordSearchList getListWithKeyword(String keyword) { + KeywordSearchList found = null; + for (KeywordSearchList list : theLists.values()) { + if (list.hasKeyword(keyword)) { + found = list; + break; + } + } + return found; + } + + /** + * get number of lists currently stored + * + * @return number of lists currently stored + */ + int getNumberLists() { + return theLists.size(); + } + + /** + * get number of unlocked or locked lists currently stored + * + * @param locked true if look for locked lists, false otherwise + * @return number of unlocked lists currently stored + */ + int getNumberLists(boolean locked) { + int numLists = 0; + for (String listName : theLists.keySet()) { + KeywordSearchList list = theLists.get(listName); + if (locked == list.isLocked()) { + ++numLists; + } + } + return numLists; + } + + /** + * get list by name or null + * + * @param name id of the list + * @return keyword list representation + */ + KeywordSearchList getList(String name) { + return theLists.get(name); + } + + /** + * check if list with given name id exists + * + * @param name id to check + * @return true if list already exists or false otherwise + */ + boolean listExists(String name) { + return getList(name) != null; + } + + /** + * adds the new word list using name id replacing old one if exists with the + * same name + * + * @param name the name of the new list or list to replace + * @param newList list of keywords + * @param useForIngest should this list be used for ingest + * @return true if old list was replaced + */ + boolean addList(String name, List<Keyword> newList, boolean useForIngest, boolean ingestMessages, boolean locked) { + boolean replaced = false; + KeywordSearchList curList = getList(name); + final Date now = new Date(); + + if (curList == null) { + theLists.put(name, new KeywordSearchList(name, now, now, useForIngest, ingestMessages, newList, locked)); +// if (!locked) { +// save(); +// } + changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, name); + } else { + theLists.put(name, new KeywordSearchList(name, curList.getDateCreated(), now, useForIngest, ingestMessages, newList, locked)); +// if (!locked) { +// save(); +// } + replaced = true; + changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, name); + } + + return replaced; + } + + boolean addList(String name, List<Keyword> newList, boolean useForIngest, boolean ingestMessages) { + //make sure that the list is readded as a locked/built in list + boolean isLocked = this.lockedLists.contains(name); + return addList(name, newList, useForIngest, ingestMessages, isLocked); + } + + boolean addList(String name, List<Keyword> newList) { + boolean isLocked = this.lockedLists.contains(name); + return addList(name, newList, true, isLocked); + } + + boolean addList(KeywordSearchList list) { + return addList(list.getName(), list.getKeywords(), list.getUseForIngest(), list.getIngestMessages(), list.isLocked()); + } + + /** + * save multiple lists + * + * @param lists + * @return + */ + boolean saveLists(List<KeywordSearchList> lists) { + int oldSize = this.getNumberLists(); + + List<KeywordSearchList> overwritten = new ArrayList<KeywordSearchList>(); + List<KeywordSearchList> newLists = new ArrayList<KeywordSearchList>(); + for (KeywordSearchList list : lists) { + if (this.listExists(list.getName())) { + overwritten.add(list); + } else { + newLists.add(list); + } + theLists.put(list.getName(), list); + } + boolean saved = save(true); + if (saved) { + for (KeywordSearchList list : newLists) { + changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, list.getName()); + } + for (KeywordSearchList over : overwritten) { + changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, over.getName()); + } + } + + return saved; + } + + /** + * write out multiple lists + * + * @param lists + * @return + */ + boolean writeLists(List<KeywordSearchList> lists) { + int oldSize = this.getNumberLists(); + + List<KeywordSearchList> overwritten = new ArrayList<KeywordSearchList>(); + List<KeywordSearchList> newLists = new ArrayList<KeywordSearchList>(); + for (KeywordSearchList list : lists) { + if (this.listExists(list.getName())) { + overwritten.add(list); + } else { + newLists.add(list); + } + theLists.put(list.getName(), list); + } + //boolean saved = save(); + + for (KeywordSearchList list : newLists) { + changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, list.getName()); + } + for (KeywordSearchList over : overwritten) { + changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, over.getName()); + } + + return true; + } + + /** + * delete list if exists and save new list + * + * @param name of list to delete + * @return true if deleted + */ + boolean deleteList(String name) { + boolean deleted = false; + KeywordSearchList delList = getList(name); + if (delList != null && !delList.isLocked()) { + theLists.remove(name); + //deleted = save(); + } + changeSupport.firePropertyChange(ListsEvt.LIST_DELETED.toString(), null, name); + return true; + + } + + /** + * writes out current list replacing the last lists file + */ + public abstract boolean save(); + + /** + * writes out current list replacing the last lists file + * @param isExport true is this save operation is an export and not a 'Save + * As' + */ + public abstract boolean save(boolean isExport); + + /** + * load and parse List, then dispose + */ + public abstract boolean load(); + + private boolean listFileExists() { + File f = new File(filePath); + return f.exists() && f.canRead() && f.canWrite(); + } + + /** + * a representation of a single keyword list created or loaded + */ + public class KeywordSearchList { + + private String name; + private Date created; + private Date modified; + private Boolean useForIngest; + private Boolean ingestMessages; + private List<Keyword> keywords; + private Boolean locked; + + KeywordSearchList(String name, Date created, Date modified, Boolean useForIngest, Boolean ingestMessages, List<Keyword> keywords, boolean locked) { + this.name = name; + this.created = created; + this.modified = modified; + this.useForIngest = useForIngest; + this.ingestMessages = ingestMessages; + this.keywords = keywords; + this.locked = locked; + } + + KeywordSearchList(String name, Date created, Date modified, Boolean useForIngest, Boolean ingestMessages, List<Keyword> keywords) { + this(name, created, modified, useForIngest, ingestMessages, keywords, false); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final KeywordSearchList other = (KeywordSearchList) obj; + if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 5; + return hash; + } + + public String getName() { + return name; + } + + public Date getDateCreated() { + return created; + } + + public Date getDateModified() { + return modified; + } + + public Boolean getUseForIngest() { + return useForIngest; + } + + public void setUseForIngest(boolean use) { + this.useForIngest = use; + } + + public Boolean getIngestMessages() { + return ingestMessages; + } + + public void setIngestMessages(boolean ingestMessages) { + this.ingestMessages = ingestMessages; + } + + public List<Keyword> getKeywords() { + return keywords; + } + + public boolean hasKeyword(Keyword keyword) { + return keywords.contains(keyword); + } + + public boolean hasKeyword(String keyword) { + //note, this ignores isLiteral + for (Keyword k : keywords) { + if (k.getQuery().equals(keyword)) { + return true; + } + } + return false; + } + + public Boolean isLocked() { + return locked; + } + } } \ No newline at end of file diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsManagementPanel.form b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsManagementPanel.form index f3b8306b06..cb2629ae11 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsManagementPanel.form +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsManagementPanel.form @@ -37,7 +37,7 @@ <Component id="importButton" min="-2" pref="126" max="-2" attributes="0"/> </Group> </Group> - <EmptySpace min="0" pref="4" max="32767" attributes="0"/> + <EmptySpace min="0" pref="0" max="32767" attributes="0"/> </Group> </Group> <EmptySpace max="-2" attributes="0"/> diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsManagementPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsManagementPanel.java index ae73ef504e..3e64ad20d3 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsManagementPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsManagementPanel.java @@ -243,12 +243,12 @@ private void importButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN- return; } - List<KeywordSearchList> toImport = reader.getListsL(); - List<KeywordSearchList> toImportConfirmed = new ArrayList<KeywordSearchList>(); + List<KeywordSearchListsAbstract.KeywordSearchList> toImport = reader.getListsL(); + List<KeywordSearchListsAbstract.KeywordSearchList> toImportConfirmed = new ArrayList<KeywordSearchListsAbstract.KeywordSearchList>(); final KeywordSearchListsXML writer = KeywordSearchListsXML.getCurrent(); - for (KeywordSearchList list : toImport) { + for (KeywordSearchListsAbstract.KeywordSearchList list : toImport) { //check name collisions if (writer.listExists(list.getName())) { Object[] options = {"Yes, overwrite", diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsViewerPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsViewerPanel.java index bf27605fcd..e124ef44e2 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsViewerPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchListsViewerPanel.java @@ -105,7 +105,7 @@ public void valueChanged(ListSelectionEvent e) { ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource(); if (!listSelectionModel.isSelectionEmpty()) { int index = listSelectionModel.getMinSelectionIndex(); - KeywordSearchList list = listsTableModel.getListAt(index); + KeywordSearchListsAbstract.KeywordSearchList list = listsTableModel.getListAt(index); keywordsTableModel.resync(list); } else { keywordsTableModel.deleteAll(); @@ -307,13 +307,13 @@ private void searchAction(ActionEvent e) { @Override public List<Keyword> getQueryList() { List<Keyword> ret = new ArrayList<Keyword>(); - for (KeywordSearchList list : getSelectedLists()) { + for (KeywordSearchListsAbstract.KeywordSearchList list : getSelectedLists()) { ret.addAll(list.getKeywords()); } return ret; } - private List<KeywordSearchList> getSelectedLists() { + private List<KeywordSearchListsAbstract.KeywordSearchList> getSelectedLists() { return listsTableModel.getSelectedListsL(); } @@ -427,7 +427,7 @@ List<String> getAllLists() { return ret; } - KeywordSearchList getListAt(int rowIndex) { + KeywordSearchListsAbstract.KeywordSearchList getListAt(int rowIndex) { return listsHandle.getList((String) getValueAt(rowIndex, 1)); } @@ -441,8 +441,8 @@ List<String> getSelectedLists() { return ret; } - List<KeywordSearchList> getSelectedListsL() { - List<KeywordSearchList> ret = new ArrayList<KeywordSearchList>(); + List<KeywordSearchListsAbstract.KeywordSearchList> getSelectedListsL() { + List<KeywordSearchListsAbstract.KeywordSearchList> ret = new ArrayList<KeywordSearchListsAbstract.KeywordSearchList>(); for (String s : getSelectedLists()) { ret.add(listsHandle.getList(s)); } @@ -462,8 +462,8 @@ void resync() { } //add lists to the model - private void addLists(List<KeywordSearchList> lists) { - for (KeywordSearchList list : lists) { + private void addLists(List<KeywordSearchListsAbstract.KeywordSearchList> lists) { + for (KeywordSearchListsAbstract.KeywordSearchList list : lists) { if (!listExists(list.getName())) { listData.add(new ListTableEntry(list, ingestRunning)); } @@ -476,7 +476,7 @@ private class ListTableEntry implements Comparable<ListTableEntry> { String name; Boolean selected; - ListTableEntry(KeywordSearchList list, boolean ingestRunning) { + ListTableEntry(KeywordSearchListsAbstract.KeywordSearchList list, boolean ingestRunning) { this.name = list.getName(); if (ingestRunning) { this.selected = list.getUseForIngest(); @@ -558,7 +558,7 @@ public Class<?> getColumnClass(int c) { return getValueAt(0, c).getClass(); } - void resync(KeywordSearchList list) { + void resync(KeywordSearchListsAbstract.KeywordSearchList list) { listData.clear(); for (Keyword k : list.getKeywords()) { listData.add(new KeywordTableEntry(k)); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java index 634ac92402..36975c9cda 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchResultFactory.java @@ -236,7 +236,7 @@ protected boolean createKeys(List<KeyValueQuery> toPopulate) { //get listname String listName = ""; - KeywordSearchList list = KeywordSearchListsXML.getCurrent().getListWithKeyword(tcq.getQueryString()); + KeywordSearchListsAbstract.KeywordSearchList list = KeywordSearchListsXML.getCurrent().getListWithKeyword(tcq.getQueryString()); if (list != null) { listName = list.getName(); } diff --git a/Testing/nbproject/project.xml b/Testing/nbproject/project.xml index 2de5ca7b67..6b7be2ee79 100644 --- a/Testing/nbproject/project.xml +++ b/Testing/nbproject/project.xml @@ -15,6 +15,15 @@ <specification-version>5.0</specification-version> </run-dependency> </dependency> + <dependency> + <code-name-base>org.sleuthkit.autopsy.keywordsearch</code-name-base> + <build-prerequisite/> + <compile-dependency/> + <run-dependency> + <release-version>5</release-version> + <specification-version>3.0</specification-version> + </run-dependency> + </dependency> </module-dependencies> <test-dependencies> <test-type> diff --git a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java index 3746f52abb..33a5480573 100644 --- a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java +++ b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java @@ -52,6 +52,7 @@ import org.netbeans.jemmy.operators.JTextFieldOperator; import org.netbeans.junit.NbModuleSuite; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.autopsy.keywordsearch.*; /** * This test expects the following system properties to be set: * img_path: The fully qualified path to the image file (if split, the first file) @@ -207,6 +208,8 @@ public void testConfigureSearch() { logger.info("Search Configure"); JDialog jd = JDialogOperator.waitJDialog("Advanced Keyword Search Configuration", false, false); JDialogOperator jdo = new JDialogOperator(jd); + KeywordSearchListsXML curr = KeywordSearchListsXML.getCurrent(); + curr.theLists.get("URLs").setUseForIngest(true); String words = System.getProperty("keyword_path"); JButtonOperator jbo0 = new JButtonOperator(jdo, "Import List", 0); jbo0.pushNoBlock(); -- GitLab