Autopsy  4.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
KeywordSearchList.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2016 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.keywordsearch;
20 
21 import java.beans.PropertyChangeListener;
22 import java.beans.PropertyChangeSupport;
23 import java.io.File;
24 import java.util.ArrayList;
25 import java.util.Date;
26 import java.util.LinkedHashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.logging.Level;
30 import org.openide.util.NbBundle;
34 
38 abstract class KeywordSearchList {
39 
40  protected static final Logger LOGGER = Logger.getLogger(KeywordSearchList.class.getName());
41 
42  // These are the valid characters that can appear either before or after a
43  // keyword hit. We use these characters to try to reduce the number of false
44  // positives for phone numbers and IP addresses. They don't work as well
45  // for "string" types such as URLs since the characters are more likely to
46  // appear in the resulting hit.
47  private static final String BOUNDARY_CHARACTERS = "[ \t\r\n\\.\\-\\?\\,\\;\\\\!\\:\\[\\]\\/\\(\\)\\\"\\\'\\>\\{\\}]";
48  private static final String PHONE_NUMBER_REGEX = BOUNDARY_CHARACTERS + "(\\([0-9]{3}\\)|[0-9]{3})([ \\-\\.])[0-9]{3}([ \\-\\.])[0-9]{4}" + BOUNDARY_CHARACTERS; //NON-NLS
49  private static final String IP_ADDRESS_REGEX = BOUNDARY_CHARACTERS + "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(1[0-9]{2}|2[0-4][0-9]|25[0-5]|[1-9][0-9]|[0-9])" + BOUNDARY_CHARACTERS; //NON-NLS
50  private static final String EMAIL_ADDRESS_REGEX = "(\\{?)[a-zA-Z0-9%+_\\-]+(\\.[a-zA-Z0-9%+_\\-]+)*(\\}?)\\@([a-zA-Z0-9]([a-zA-Z0-9\\-]*[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,4}"; //NON-NLS
51  private static final String URL_REGEX = "(((((h|H)(t|T))|(f|F))(t|T)(p|P)(s|S?)\\:\\/\\/)|(w|W){3,3}\\.)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,5})(\\:[0-9]+)*(\\/($|[a-zA-Z0-9\\.\\,\\;\\?\\'\\\\+&amp;%\\$#\\=~_\\-]+))*"; //NON-NLS
52 
62  private static final String CCN_REGEX = "(%?)(B?)([0-9][ \\-]*?){12,19}(\\^?)"; //NON-NLS
63 
64  protected String filePath;
65  Map<String, KeywordList> theLists; //the keyword data
66 
67  PropertyChangeSupport changeSupport;
68  protected List<String> lockedLists;
69 
70  KeywordSearchList(String filePath) {
71  this.filePath = filePath;
72  theLists = new LinkedHashMap<>();
73  lockedLists = new ArrayList<>();
74  changeSupport = new PropertyChangeSupport(this);
75  }
76 
82  enum ListsEvt {
83 
84  LIST_ADDED,
85  LIST_DELETED,
86  LIST_UPDATED
87  };
88 
89  enum LanguagesEvent {
90 
91  LANGUAGES_CHANGED,
92  ENCODINGS_CHANGED
93  }
94 
95  void fireLanguagesEvent(LanguagesEvent event) {
96  try {
97  changeSupport.firePropertyChange(event.toString(), null, null);
98  } catch (Exception e) {
99  LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
100  }
101  }
102 
103  public void addPropertyChangeListener(PropertyChangeListener listener) {
104  changeSupport.addPropertyChangeListener(listener);
105  }
106 
107  public void removePropertyChangeListener(PropertyChangeListener listener) {
108  changeSupport.removePropertyChangeListener(listener);
109  }
110 
111  private void prepopulateLists() {
112  if (!theLists.isEmpty()) {
113  return;
114  }
115  //phone number
116  List<Keyword> phones = new ArrayList<>();
117  phones.add(new Keyword(PHONE_NUMBER_REGEX, false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER));
118  lockedLists.add("Phone Numbers");
119  addList("Phone Numbers", phones, false, false, true);
120 
121  //IP address
122  List<Keyword> ips = new ArrayList<>();
123  ips.add(new Keyword(IP_ADDRESS_REGEX, false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IP_ADDRESS));
124  lockedLists.add("IP Addresses");
125  addList("IP Addresses", ips, false, false, true);
126 
127  //email
128  List<Keyword> emails = new ArrayList<>();
129  emails.add(new Keyword(EMAIL_ADDRESS_REGEX, false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL));
130  lockedLists.add("Email Addresses");
131  addList("Email Addresses", emails, true, false, true);
132 
133  //URL
134  List<Keyword> urls = new ArrayList<>();
135  urls.add(new Keyword(URL_REGEX, false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL));
136  lockedLists.add("URLs");
137  addList("URLs", urls, false, false, true);
138 
139  //CCN
140  List<Keyword> ccns = new ArrayList<>();
141  ccns.add(new Keyword(CCN_REGEX, false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
142  lockedLists.add("Credit Card Numbers");
143  addList("Credit Card Numbers", ccns, false, false, true);
144  }
145 
149  public void reload() {
150  boolean created = false;
151 
152  //theLists.clear();
153  //populate only the first time
154  prepopulateLists();
155 
156  //reset all the lists other than locked lists (we don't save them to XML)
157  //we want to preserve state of locked lists
158  List<String> toClear = new ArrayList<>();
159  for (String list : theLists.keySet()) {
160  if (theLists.get(list).isEditable() == false) {
161  toClear.add(list);
162  }
163  }
164  for (String clearList : toClear) {
165  theLists.remove(clearList);
166  }
167 
168  if (!listFileExists()) {
169  //create new if it doesn't exist
170  save();
171  created = true;
172  }
173 
174  //load, if fails to load create new
175  if (!load() && !created) {
176  //create new if failed to load
177  save();
178  }
179  }
180 
181  public List<KeywordList> getListsL() {
182  List<KeywordList> ret = new ArrayList<>();
183  for (KeywordList list : theLists.values()) {
184  ret.add(list);
185  }
186  return ret;
187  }
188 
189  public List<KeywordList> getListsL(boolean locked) {
190  List<KeywordList> ret = new ArrayList<>();
191  for (KeywordList list : theLists.values()) {
192  if (list.isEditable().equals(locked)) {
193  ret.add(list);
194  }
195  }
196  return ret;
197  }
198 
204  public List<String> getListNames() {
205  return new ArrayList<>(theLists.keySet());
206  }
207 
215  public List<String> getListNames(boolean locked) {
216  ArrayList<String> lists = new ArrayList<>();
217  for (String listName : theLists.keySet()) {
218  KeywordList list = theLists.get(listName);
219  if (locked == list.isEditable()) {
220  lists.add(listName);
221  }
222  }
223 
224  return lists;
225  }
226 
234  public KeywordList getListWithKeyword(String keyword) {
235  KeywordList found = null;
236  for (KeywordList list : theLists.values()) {
237  if (list.hasSearchTerm(keyword)) {
238  found = list;
239  break;
240  }
241  }
242  return found;
243  }
244 
250  int getNumberLists() {
251  return theLists.size();
252  }
253 
261  public int getNumberLists(boolean locked) {
262  int numLists = 0;
263  for (String listName : theLists.keySet()) {
264  KeywordList list = theLists.get(listName);
265  if (locked == list.isEditable()) {
266  ++numLists;
267  }
268  }
269  return numLists;
270  }
271 
279  public KeywordList getList(String name) {
280  return theLists.get(name);
281  }
282 
290  boolean listExists(String name) {
291  return getList(name) != null;
292  }
293 
304  boolean addList(String name, List<Keyword> newList, boolean useForIngest, boolean ingestMessages, boolean locked) {
305  boolean replaced = false;
306  KeywordList curList = getList(name);
307  final Date now = new Date();
308 
309  if (curList == null) {
310  theLists.put(name, new KeywordList(name, now, now, useForIngest, ingestMessages, newList, locked));
311  try {
312  changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, name);
313  } catch (Exception e) {
314  LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
315  MessageNotifyUtil.Notify.show(
316  NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.moduleErr"),
317  NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.addList.errMsg1.msg"),
318  MessageNotifyUtil.MessageType.ERROR);
319  }
320  } else {
321  theLists.put(name, new KeywordList(name, curList.getDateCreated(), now, useForIngest, ingestMessages, newList, locked));
322  replaced = true;
323 
324  try {
325  changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, name);
326  } catch (Exception e) {
327  LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
328  MessageNotifyUtil.Notify.show(
329  NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.moduleErr"),
330  NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.addList.errMsg2.msg"),
331  MessageNotifyUtil.MessageType.ERROR);
332  }
333  }
334 
335  return replaced;
336  }
337 
338  boolean addList(String name, List<Keyword> newList, boolean useForIngest, boolean ingestMessages) {
339  //make sure that the list is readded as a locked/built in list
340  boolean isLocked = this.lockedLists.contains(name);
341  return addList(name, newList, useForIngest, ingestMessages, isLocked);
342  }
343 
344  boolean addList(String name, List<Keyword> newList) {
345  return addList(name, newList, true, true);
346  }
347 
348  boolean addList(KeywordList list) {
349  return addList(list.getName(), list.getKeywords(), list.getUseForIngest(), list.getIngestMessages(), list.isEditable());
350  }
351 
359  boolean saveLists(List<KeywordList> lists) {
360  List<KeywordList> overwritten = new ArrayList<>();
361  List<KeywordList> newLists = new ArrayList<>();
362  for (KeywordList list : lists) {
363  if (this.listExists(list.getName())) {
364  overwritten.add(list);
365  } else {
366  newLists.add(list);
367  }
368  theLists.put(list.getName(), list);
369  }
370  boolean saved = save(true);
371  if (saved) {
372  for (KeywordList list : newLists) {
373  try {
374  changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, list.getName());
375  } catch (Exception e) {
376  LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
377  MessageNotifyUtil.Notify.show(
378  NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.moduleErr"),
379  NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.saveList.errMsg1.msg"),
380  MessageNotifyUtil.MessageType.ERROR);
381  }
382  }
383  for (KeywordList over : overwritten) {
384  try {
385  changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, over.getName());
386  } catch (Exception e) {
387  LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
388  MessageNotifyUtil.Notify.show(
389  NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.moduleErr"),
390  NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.saveList.errMsg2.msg"),
391  MessageNotifyUtil.MessageType.ERROR);
392  }
393  }
394  }
395 
396  return saved;
397  }
398 
406  boolean writeLists(List<KeywordList> lists) {
407  List<KeywordList> overwritten = new ArrayList<>();
408  List<KeywordList> newLists = new ArrayList<>();
409  for (KeywordList list : lists) {
410  if (this.listExists(list.getName())) {
411  overwritten.add(list);
412  } else {
413  newLists.add(list);
414  }
415  theLists.put(list.getName(), list);
416  }
417 
418  for (KeywordList list : newLists) {
419 
420  try {
421  changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, list.getName());
422  } catch (Exception e) {
423  LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
424  MessageNotifyUtil.Notify.show(
425  NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.moduleErr"),
426  NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.writeLists.errMsg1.msg"),
427  MessageNotifyUtil.MessageType.ERROR);
428  }
429  }
430 
431  for (KeywordList over : overwritten) {
432 
433  try {
434  changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, over.getName());
435  } catch (Exception e) {
436  LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
437  MessageNotifyUtil.Notify.show(
438  NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.moduleErr"),
439  NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.writeLists.errMsg2.msg"),
440  MessageNotifyUtil.MessageType.ERROR);
441  }
442  }
443 
444  return true;
445  }
446 
454  boolean deleteList(String name) {
455  KeywordList delList = getList(name);
456  if (delList != null && !delList.isEditable()) {
457  theLists.remove(name);
458  }
459 
460  try {
461  changeSupport.firePropertyChange(ListsEvt.LIST_DELETED.toString(), null, name);
462  } catch (Exception e) {
463  LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
464  MessageNotifyUtil.Notify.show(
465  NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.moduleErr"),
466  NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.deleteList.errMsg1.msg"),
467  MessageNotifyUtil.MessageType.ERROR);
468  }
469 
470  return true;
471  }
472 
476  public abstract boolean save();
477 
484  public abstract boolean save(boolean isExport);
485 
489  public abstract boolean load();
490 
491  private boolean listFileExists() {
492  File f = new File(filePath);
493  return f.exists() && f.canRead() && f.canWrite();
494  }
495 
496  public void setUseForIngest(String key, boolean flag) {
497  theLists.get(key).setUseForIngest(flag);
498  }
499 }

Copyright © 2012-2016 Basis Technology. Generated on: Mon Apr 24 2017
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.