19 package org.sleuthkit.autopsy.keywordsearch;
21 import java.beans.PropertyChangeListener;
22 import java.beans.PropertyChangeSupport;
24 import java.util.ArrayList;
25 import java.util.Date;
26 import java.util.LinkedHashMap;
27 import java.util.List;
29 import java.util.logging.Level;
30 import org.openide.util.NbBundle;
38 abstract class KeywordSearchList {
40 protected static final Logger LOGGER = Logger.getLogger(KeywordSearchList.class.getName());
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;
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;
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}";
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\\.\\,\\;\\?\\'\\\\+&%\\$#\\=~_\\-]+))*";
61 private static final String CCN_REGEX =
"(%?)(B?)([0-9][ \\-]*?){12,19}(\\^?)";
63 protected String filePath;
64 Map<String, KeywordList> theLists;
66 PropertyChangeSupport changeSupport;
67 protected List<String> lockedLists;
69 KeywordSearchList(String filePath) {
70 this.filePath = filePath;
71 theLists =
new LinkedHashMap<>();
72 lockedLists =
new ArrayList<>();
73 changeSupport =
new PropertyChangeSupport(
this);
94 void fireLanguagesEvent(LanguagesEvent event) {
96 changeSupport.firePropertyChange(event.toString(), null, null);
97 }
catch (Exception e) {
98 LOGGER.log(Level.SEVERE,
"KeywordSearchListsAbstract listener threw exception", e);
102 public void addPropertyChangeListener(PropertyChangeListener listener) {
103 changeSupport.addPropertyChangeListener(listener);
106 public void removePropertyChangeListener(PropertyChangeListener listener) {
107 changeSupport.removePropertyChangeListener(listener);
110 private void prepopulateLists() {
111 if (!theLists.isEmpty()) {
115 List<Keyword> phones =
new ArrayList<>();
116 phones.add(
new Keyword(PHONE_NUMBER_REGEX,
false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER));
117 lockedLists.add(
"Phone Numbers");
118 addList(
"Phone Numbers", phones,
false,
false,
true);
121 List<Keyword> ips =
new ArrayList<>();
122 ips.add(
new Keyword(IP_ADDRESS_REGEX,
false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IP_ADDRESS));
123 lockedLists.add(
"IP Addresses");
124 addList(
"IP Addresses", ips,
false,
false,
true);
127 List<Keyword> emails =
new ArrayList<>();
128 emails.add(
new Keyword(EMAIL_ADDRESS_REGEX,
false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL));
129 lockedLists.add(
"Email Addresses");
130 addList(
"Email Addresses", emails,
true,
false,
true);
133 List<Keyword> urls =
new ArrayList<>();
134 urls.add(
new Keyword(URL_REGEX,
false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL));
135 lockedLists.add(
"URLs");
136 addList(
"URLs", urls,
false,
false,
true);
139 List<Keyword> ccns =
new ArrayList<>();
140 ccns.add(
new Keyword(CCN_REGEX,
false, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER));
141 lockedLists.add(
"Credit Card Numbers");
142 addList(
"Credit Card Numbers", ccns,
false,
false,
true);
148 public void reload() {
149 boolean created =
false;
157 List<String> toClear =
new ArrayList<>();
158 for (String list : theLists.keySet()) {
159 if (theLists.get(list).isEditable() ==
false) {
163 for (String clearList : toClear) {
164 theLists.remove(clearList);
167 if (!listFileExists()) {
174 if (!load() && !created) {
180 public List<KeywordList> getListsL() {
181 List<KeywordList> ret =
new ArrayList<>();
182 for (KeywordList list : theLists.values()) {
188 public List<KeywordList> getListsL(
boolean locked) {
189 List<KeywordList> ret =
new ArrayList<>();
190 for (KeywordList list : theLists.values()) {
191 if (list.isEditable().equals(locked)) {
203 public List<String> getListNames() {
204 return new ArrayList<>(theLists.keySet());
214 public List<String> getListNames(
boolean locked) {
215 ArrayList<String> lists =
new ArrayList<>();
216 for (String listName : theLists.keySet()) {
217 KeywordList list = theLists.get(listName);
218 if (locked == list.isEditable()) {
233 public KeywordList getListWithKeyword(String keyword) {
234 KeywordList found = null;
235 for (KeywordList list : theLists.values()) {
236 if (list.hasSearchTerm(keyword)) {
249 int getNumberLists() {
250 return theLists.size();
260 public int getNumberLists(
boolean locked) {
262 for (String listName : theLists.keySet()) {
263 KeywordList list = theLists.get(listName);
264 if (locked == list.isEditable()) {
278 public KeywordList getList(String name) {
279 return theLists.get(name);
289 boolean listExists(String name) {
290 return getList(name) != null;
303 boolean addList(String name, List<Keyword> newList,
boolean useForIngest,
boolean ingestMessages,
boolean locked) {
304 boolean replaced =
false;
305 KeywordList curList = getList(name);
306 final Date now =
new Date();
308 if (curList == null) {
309 theLists.put(name,
new KeywordList(name, now, now, useForIngest, ingestMessages, newList, locked));
311 changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, name);
312 }
catch (Exception e) {
313 LOGGER.log(Level.SEVERE,
"KeywordSearchListsAbstract listener threw exception", e);
314 MessageNotifyUtil.Notify.show(
315 NbBundle.getMessage(
this.getClass(),
"KeywordSearchListsAbstract.moduleErr"),
316 NbBundle.getMessage(
this.getClass(),
"KeywordSearchListsAbstract.addList.errMsg1.msg"),
317 MessageNotifyUtil.MessageType.ERROR);
320 theLists.put(name,
new KeywordList(name, curList.getDateCreated(), now, useForIngest, ingestMessages, newList, locked));
324 changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, name);
325 }
catch (Exception e) {
326 LOGGER.log(Level.SEVERE,
"KeywordSearchListsAbstract listener threw exception", e);
327 MessageNotifyUtil.Notify.show(
328 NbBundle.getMessage(
this.getClass(),
"KeywordSearchListsAbstract.moduleErr"),
329 NbBundle.getMessage(
this.getClass(),
"KeywordSearchListsAbstract.addList.errMsg2.msg"),
330 MessageNotifyUtil.MessageType.ERROR);
337 boolean addList(String name, List<Keyword> newList,
boolean useForIngest,
boolean ingestMessages) {
339 boolean isLocked = this.lockedLists.contains(name);
340 return addList(name, newList, useForIngest, ingestMessages, isLocked);
343 boolean addList(String name, List<Keyword> newList) {
344 return addList(name, newList,
true,
true);
347 boolean addList(KeywordList list) {
348 return addList(list.getName(), list.getKeywords(), list.getUseForIngest(), list.getIngestMessages(), list.isEditable());
358 boolean saveLists(List<KeywordList> lists) {
359 List<KeywordList> overwritten =
new ArrayList<>();
360 List<KeywordList> newLists =
new ArrayList<>();
361 for (KeywordList list : lists) {
362 if (this.listExists(list.getName())) {
363 overwritten.add(list);
367 theLists.put(list.getName(), list);
369 boolean saved = save(
true);
371 for (KeywordList list : newLists) {
373 changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, list.getName());
374 }
catch (Exception e) {
375 LOGGER.log(Level.SEVERE,
"KeywordSearchListsAbstract listener threw exception", e);
376 MessageNotifyUtil.Notify.show(
377 NbBundle.getMessage(
this.getClass(),
"KeywordSearchListsAbstract.moduleErr"),
378 NbBundle.getMessage(
this.getClass(),
"KeywordSearchListsAbstract.saveList.errMsg1.msg"),
379 MessageNotifyUtil.MessageType.ERROR);
382 for (KeywordList over : overwritten) {
384 changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, over.getName());
385 }
catch (Exception e) {
386 LOGGER.log(Level.SEVERE,
"KeywordSearchListsAbstract listener threw exception", e);
387 MessageNotifyUtil.Notify.show(
388 NbBundle.getMessage(
this.getClass(),
"KeywordSearchListsAbstract.moduleErr"),
389 NbBundle.getMessage(
this.getClass(),
"KeywordSearchListsAbstract.saveList.errMsg2.msg"),
390 MessageNotifyUtil.MessageType.ERROR);
405 boolean writeLists(List<KeywordList> lists) {
406 List<KeywordList> overwritten =
new ArrayList<>();
407 List<KeywordList> newLists =
new ArrayList<>();
408 for (KeywordList list : lists) {
409 if (this.listExists(list.getName())) {
410 overwritten.add(list);
414 theLists.put(list.getName(), list);
417 for (KeywordList list : newLists) {
420 changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, list.getName());
421 }
catch (Exception e) {
422 LOGGER.log(Level.SEVERE,
"KeywordSearchListsAbstract listener threw exception", e);
423 MessageNotifyUtil.Notify.show(
424 NbBundle.getMessage(
this.getClass(),
"KeywordSearchListsAbstract.moduleErr"),
425 NbBundle.getMessage(
this.getClass(),
"KeywordSearchListsAbstract.writeLists.errMsg1.msg"),
426 MessageNotifyUtil.MessageType.ERROR);
430 for (KeywordList over : overwritten) {
433 changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, over.getName());
434 }
catch (Exception e) {
435 LOGGER.log(Level.SEVERE,
"KeywordSearchListsAbstract listener threw exception", e);
436 MessageNotifyUtil.Notify.show(
437 NbBundle.getMessage(
this.getClass(),
"KeywordSearchListsAbstract.moduleErr"),
438 NbBundle.getMessage(
this.getClass(),
"KeywordSearchListsAbstract.writeLists.errMsg2.msg"),
439 MessageNotifyUtil.MessageType.ERROR);
453 boolean deleteList(String name) {
454 KeywordList delList = getList(name);
455 if (delList != null && !delList.isEditable()) {
456 theLists.remove(name);
460 changeSupport.firePropertyChange(ListsEvt.LIST_DELETED.toString(), null, name);
461 }
catch (Exception e) {
462 LOGGER.log(Level.SEVERE,
"KeywordSearchListsAbstract listener threw exception", e);
463 MessageNotifyUtil.Notify.show(
464 NbBundle.getMessage(
this.getClass(),
"KeywordSearchListsAbstract.moduleErr"),
465 NbBundle.getMessage(
this.getClass(),
"KeywordSearchListsAbstract.deleteList.errMsg1.msg"),
466 MessageNotifyUtil.MessageType.ERROR);
475 public abstract boolean save();
483 public abstract boolean save(
boolean isExport);
488 public abstract boolean load();
490 private boolean listFileExists() {
491 File f =
new File(filePath);
492 return f.exists() && f.canRead() && f.canWrite();
495 public void setUseForIngest(String key,
boolean flag) {
496 theLists.get(key).setUseForIngest(flag);