Autopsy 4.22.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 */
19package org.sleuthkit.autopsy.keywordsearch;
20
21import java.beans.PropertyChangeListener;
22import java.beans.PropertyChangeSupport;
23import java.io.File;
24import java.util.ArrayList;
25import java.util.Date;
26import java.util.LinkedHashMap;
27import java.util.List;
28import java.util.Map;
29import java.util.logging.Level;
30import org.openide.util.NbBundle;
31import org.sleuthkit.autopsy.coreutils.Logger;
32import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
33import org.sleuthkit.datamodel.BlackboardAttribute;
34
38abstract 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 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
61 private static final String CCN_REGEX = "(%?)(B?)([0-9][ \\-]*?){12,19}(\\^?)"; //NON-NLS
62
63 protected String filePath;
64 Map<String, KeywordList> theLists; //the keyword data
65
66 PropertyChangeSupport changeSupport;
67 protected List<String> lockedLists;
68
69 KeywordSearchList(String filePath) {
70 this.filePath = filePath;
71 theLists = new LinkedHashMap<>();
72 lockedLists = new ArrayList<>();
73 changeSupport = new PropertyChangeSupport(this);
74 }
75
87
93
94 void fireLanguagesEvent(LanguagesEvent event) {
95 try {
96 changeSupport.firePropertyChange(event.toString(), null, null);
97 } catch (Exception e) {
98 LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
99 }
100 }
101
102 public void addPropertyChangeListener(PropertyChangeListener listener) {
103 changeSupport.addPropertyChangeListener(listener);
104 }
105
106 public void removePropertyChangeListener(PropertyChangeListener listener) {
107 changeSupport.removePropertyChangeListener(listener);
108 }
109
110 private void prepopulateLists() {
111 if (!theLists.isEmpty()) {
112 return;
113 }
114 //phone number
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);
119
120 //IP address
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);
125
126 //email
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);
131
132 //URL
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);
137
138 //CCN
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);
143 }
144
148 public void reload() {
149 boolean created = false;
150
151 //theLists.clear();
152 //populate only the first time
153 prepopulateLists();
154
155 //reset all the lists other than locked lists (we don't save them to XML)
156 //we want to preserve state of locked lists
157 List<String> toClear = new ArrayList<>();
158 for (String list : theLists.keySet()) {
159 if (theLists.get(list).isEditable() == false) {
160 toClear.add(list);
161 }
162 }
163 for (String clearList : toClear) {
164 theLists.remove(clearList);
165 }
166
167 if (!listFileExists()) {
168 //create new if it doesn't exist
169 save();
170 created = true;
171 }
172
173 //load, if fails to load create new
174 if (!load() && !created) {
175 //create new if failed to load
176 save();
177 }
178 }
179
180 public List<KeywordList> getListsL() {
181 List<KeywordList> ret = new ArrayList<>();
182 for (KeywordList list : theLists.values()) {
183 ret.add(list);
184 }
185 return ret;
186 }
187
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)) {
192 ret.add(list);
193 }
194 }
195 return ret;
196 }
197
203 public List<String> getListNames() {
204 return new ArrayList<>(theLists.keySet());
205 }
206
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()) {
219 lists.add(listName);
220 }
221 }
222
223 return lists;
224 }
225
233 public KeywordList getListWithKeyword(String keyword) {
234 KeywordList found = null;
235 for (KeywordList list : theLists.values()) {
236 if (list.hasSearchTerm(keyword)) {
237 found = list;
238 break;
239 }
240 }
241 return found;
242 }
243
249 int getNumberLists() {
250 return theLists.size();
251 }
252
260 public int getNumberLists(boolean locked) {
261 int numLists = 0;
262 for (String listName : theLists.keySet()) {
263 KeywordList list = theLists.get(listName);
264 if (locked == list.isEditable()) {
265 ++numLists;
266 }
267 }
268 return numLists;
269 }
270
278 public KeywordList getList(String name) {
279 return theLists.get(name);
280 }
281
289 boolean listExists(String name) {
290 return getList(name) != null;
291 }
292
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();
307
308 if (curList == null) {
309 theLists.put(name, new KeywordList(name, now, now, useForIngest, ingestMessages, newList, locked));
310 try {
311 changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, name);
312 } catch (Exception e) {
313 LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
314 MessageNotifyUtil.Notify.show(
315 NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.moduleErr"),
316 NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.addList.errMsg1.msg"),
317 MessageNotifyUtil.MessageType.ERROR);
318 }
319 } else {
320 theLists.put(name, new KeywordList(name, curList.getDateCreated(), now, useForIngest, ingestMessages, newList, locked));
321 replaced = true;
322
323 try {
324 changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, name);
325 } catch (Exception e) {
326 LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
327 MessageNotifyUtil.Notify.show(
328 NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.moduleErr"),
329 NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.addList.errMsg2.msg"),
330 MessageNotifyUtil.MessageType.ERROR);
331 }
332 }
333
334 return replaced;
335 }
336
337 boolean addList(String name, List<Keyword> newList, boolean useForIngest, boolean ingestMessages) {
338 //make sure that the list is readded as a locked/built in list
339 boolean isLocked = this.lockedLists.contains(name);
340 return addList(name, newList, useForIngest, ingestMessages, isLocked);
341 }
342
343 boolean addList(String name, List<Keyword> newList) {
344 return addList(name, newList, true, true);
345 }
346
347 boolean addList(KeywordList list) {
348 return addList(list.getName(), list.getKeywords(), list.getUseForIngest(), list.getIngestMessages(), list.isEditable());
349 }
350
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);
364 } else {
365 newLists.add(list);
366 }
367 theLists.put(list.getName(), list);
368 }
369 boolean saved = save(true);
370 if (saved) {
371 for (KeywordList list : newLists) {
372 try {
373 changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, list.getName());
374 } catch (Exception e) {
375 LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
376 MessageNotifyUtil.Notify.show(
377 NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.moduleErr"),
378 NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.saveList.errMsg1.msg"),
379 MessageNotifyUtil.MessageType.ERROR);
380 }
381 }
382 for (KeywordList over : overwritten) {
383 try {
384 changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, over.getName());
385 } catch (Exception e) {
386 LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
387 MessageNotifyUtil.Notify.show(
388 NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.moduleErr"),
389 NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.saveList.errMsg2.msg"),
390 MessageNotifyUtil.MessageType.ERROR);
391 }
392 }
393 }
394
395 return saved;
396 }
397
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);
411 } else {
412 newLists.add(list);
413 }
414 theLists.put(list.getName(), list);
415 }
416
417 for (KeywordList list : newLists) {
418
419 try {
420 changeSupport.firePropertyChange(ListsEvt.LIST_ADDED.toString(), null, list.getName());
421 } catch (Exception e) {
422 LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
423 MessageNotifyUtil.Notify.show(
424 NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.moduleErr"),
425 NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.writeLists.errMsg1.msg"),
426 MessageNotifyUtil.MessageType.ERROR);
427 }
428 }
429
430 for (KeywordList over : overwritten) {
431
432 try {
433 changeSupport.firePropertyChange(ListsEvt.LIST_UPDATED.toString(), null, over.getName());
434 } catch (Exception e) {
435 LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
436 MessageNotifyUtil.Notify.show(
437 NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.moduleErr"),
438 NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.writeLists.errMsg2.msg"),
439 MessageNotifyUtil.MessageType.ERROR);
440 }
441 }
442
443 return true;
444 }
445
453 boolean deleteList(String name) {
454 KeywordList delList = getList(name);
455 if (delList != null && !delList.isEditable()) {
456 theLists.remove(name);
457 }
458
459 try {
460 changeSupport.firePropertyChange(ListsEvt.LIST_DELETED.toString(), null, name);
461 } catch (Exception e) {
462 LOGGER.log(Level.SEVERE, "KeywordSearchListsAbstract listener threw exception", e); //NON-NLS
463 MessageNotifyUtil.Notify.show(
464 NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.moduleErr"),
465 NbBundle.getMessage(this.getClass(), "KeywordSearchListsAbstract.deleteList.errMsg1.msg"),
466 MessageNotifyUtil.MessageType.ERROR);
467 }
468
469 return true;
470 }
471
475 public abstract boolean save();
476
483 public abstract boolean save(boolean isExport);
484
488 public abstract boolean load();
489
490 private boolean listFileExists() {
491 File f = new File(filePath);
492 return f.exists() && f.canRead() && f.canWrite();
493 }
494
495 public void setUseForIngest(String key, boolean flag) {
496 theLists.get(key).setUseForIngest(flag);
497 }
498}

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.