diff --git a/Core/build.xml b/Core/build.xml
index 13952d37ae..79e328cef9 100644
--- a/Core/build.xml
+++ b/Core/build.xml
@@ -32,7 +32,7 @@
ignoreerrors="true"
verbose="true"/>
-
+
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java
index 6a6cc516c8..9a8d8b0f8e 100644
--- a/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/Accounts.java
@@ -76,18 +76,29 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
private static final Logger LOGGER = Logger.getLogger(Accounts.class.getName());
private static final BlackboardArtifact.Type CREDIT_CARD_ACCOUNT_TYPE = new BlackboardArtifact.Type(TSK_CREDIT_CARD_ACCOUNT);
+ @NbBundle.Messages("AccountsRootNode.name=Accounts")
+ final public static String NAME = Bundle.AccountsRootNode_name();
/**
* Range Map from a (ranges of) B/IINs to data model object with details of
* the B/IIN, ie, bank name, phone, url, visa/amex/mastercard/...,
*/
@GuardedBy("Accounts.class")
- private final static RangeMap iinRanges = TreeRangeMap.create();
+ private final static RangeMap iinRanges = TreeRangeMap.create();
+
+ /**
+ * Flag for if we have loaded the IINs from the file already.
+ */
@GuardedBy("Accounts.class")
private static boolean iinsLoaded = false;
private SleuthkitCase skCase;
+ /**
+ * Should rejected accounts be shown in the accounts section of the tree.
+ */
+ private boolean showRejected = false;
+
/**
* Load the IIN range information from disk. If the map has already been
* initialized, don't load again.
@@ -95,7 +106,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
synchronized private static void loadIINRanges() {
if (iinsLoaded == false) {
try {
- InputStreamReader in = new InputStreamReader(Accounts.class.getResourceAsStream("ranges.csv"));
+ InputStreamReader in = new InputStreamReader(Accounts.class.getResourceAsStream("ranges.csv")); //NON-NLS
CSVParser rangesParser = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(in);
//parse each row and add to range map
@@ -106,50 +117,70 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
* IINs, but we need a consistent length for the range map,
* we pad all the numbers out to 8 digits
*/
- String start = StringUtils.rightPad(record.get("iin_start"), 8, "0"); //pad start with 0's
+ String start = StringUtils.rightPad(record.get("iin_start"), 8, "0"); //pad start with 0's //NON-NLS
//if there is no end listed, use start, since ranges will be closed.
- String end = StringUtils.defaultIfBlank(record.get("iin_end"), start);
- end = StringUtils.rightPad(end, 8, "99"); //pad end with 9's
+ String end = StringUtils.defaultIfBlank(record.get("iin_end"), start); //NON-NLS
+ end = StringUtils.rightPad(end, 8, "99"); //pad end with 9's //NON-NLS
- final String numberLength = record.get("number_length");
+ final String numberLength = record.get("number_length"); //NON-NLS
try {
- IINInfo iinRange = new IINInfo(Integer.parseInt(start),
+ IINRange iinRange = new IINRange(Integer.parseInt(start),
Integer.parseInt(end),
StringUtils.isBlank(numberLength) ? null : Integer.valueOf(numberLength),
- record.get("scheme"),
- record.get("brand"),
- record.get("type"),
- record.get("country"),
- record.get("bank_name"),
- record.get("bank_url"),
- record.get("bank_phone"),
- record.get("bank_city"));
+ record.get("scheme"), //NON-NLS
+ record.get("brand"), //NON-NLS
+ record.get("type"), //NON-NLS
+ record.get("country"), //NON-NLS
+ record.get("bank_name"), //NON-NLS
+ record.get("bank_url"), //NON-NLS
+ record.get("bank_phone"), //NON-NLS
+ record.get("bank_city")); //NON-NLS
iinRanges.put(Range.closed(iinRange.getIINstart(), iinRange.getIINend()), iinRange);
} catch (NumberFormatException numberFormatException) {
- LOGGER.log(Level.WARNING, "Failed to parse IIN range: " + record.toString(), numberFormatException);
+ LOGGER.log(Level.WARNING, "Failed to parse IIN range: " + record.toString(), numberFormatException); //NON-NLS
}
iinsLoaded = true;
}
} catch (IOException ex) {
- LOGGER.log(Level.WARNING, "Failed to load IIN ranges form ranges.csv", ex);
+ LOGGER.log(Level.WARNING, "Failed to load IIN ranges form ranges.csv", ex); //NON-NLS
MessageNotifyUtil.Notify.warn("Credit Card Number Discovery", "There was an error loading Bank Identification Number information. Accounts will not have their BINs identified.");
}
}
}
+ /**
+ * Constructor
+ *
+ * @param skCase The SleuthkitCase object to use for db queries.
+ */
+ Accounts(SleuthkitCase skCase) {
+ this.skCase = skCase;
+ }
+
+ /**
+ * Get the clause that should be used in order to (not) filter out rejected
+ * results from db queries.
+ *
+ * @return A clause that will or will not filter out rejected artifacts
+ * based on the state of showRejected.
+ */
+ private String getRejectedArtifactFilterClause() {
+ return showRejected ? "" : " AND blackboard_artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID(); //NON-NLS
+ }
+
+ /**
+ * Notify all observers that something has changed, causing a refresh of the
+ * accounts section of the tree.
+ */
private void update() {
setChanged();
notifyObservers();
}
- Accounts(SleuthkitCase skCase) {
- this.skCase = skCase;
- }
-
/**
* Are there details available about the given IIN?
*
@@ -179,6 +210,211 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
return v.visit(this);
}
+ /**
+ * Gets a new Action that when invoked toggles showing rejected artifacts on
+ * or off.
+ *
+ * @return An Action that will toggle whether rejected artifacts are shown
+ * in the tree rooted by this Accounts instance.
+ */
+ public Action newToggleShowRejectedAction() {
+ return new ToggleShowRejected();
+ }
+
+ //Interface for objects that provide details about one or more IINs.
+ static public interface IINInfo {
+
+ /**
+ * Get the city of the issuer.
+ *
+ * @return the city of the issuer.
+ */
+ Optional getBankCity();
+
+ /**
+ * Get the name of the issuer.
+ *
+ * @return the name of the issuer.
+ */
+ Optional getBankName();
+
+ /**
+ * Get the phone number of the issuer.
+ *
+ * @return the phone number of the issuer.
+ */
+ Optional getBankPhoneNumber();
+
+ /**
+ * Get the URL of the issuer.
+ *
+ * @return the URL of the issuer.
+ */
+ Optional getBankURL();
+
+ /**
+ * Get the brand of this IIN range.
+ *
+ * @return the brand of this IIN range.
+ */
+ Optional getBrand();
+
+ /**
+ * Get the type of card (credit vs debit) for this IIN range.
+ *
+ * @return the type of cards in this IIN range.
+ */
+ Optional getCardType();
+
+ /**
+ * Get the country of the issuer.
+ *
+ * @return the country of the issuer.
+ */
+ Optional getCountry();
+
+ /**
+ * Get the length of account numbers in this IIN range.
+ *
+ * NOTE: the length is currently unused, and not in the data file for
+ * any ranges. It could be quite helpfull for validation...
+ *
+ * @return the length of account numbers in this IIN range. Or an empty
+ * Optional if the length is unknown.
+ *
+ */
+ Optional getNumberLength();
+
+ /**
+ * Get the scheme this IIN range uses to, eg amex,visa,mastercard, etc
+ *
+ * @return the scheme this IIN range uses.
+ */
+ Optional getScheme();
+ }
+
+ /**
+ * Details of a range of Issuer/Bank Identifiaction Number(s) (IIN/BIN) used
+ * by a bank.
+ */
+ static private class IINRange implements IINInfo {
+
+ private final int IINStart; //start of IIN range, 8 digits
+ private final int IINEnd; // end (incluse ) of IIN rnage, 8 digits
+
+ private final Integer numberLength; // the length of accounts numbers with this IIN, currently unused
+
+ /**
+ * AMEX, VISA, MASTERCARD, DINERS, DISCOVER, UNIONPAY
+ */
+ private final String scheme;
+ private final String brand;
+
+ /**
+ * DEBIT, CREDIT
+ */
+ private final String cardType;
+ private final String country;
+ private final String bankName;
+ private final String bankCity;
+ private final String bankURL;
+ private final String bankPhoneNumber;
+
+ /**
+ * Constructor
+ *
+ * @param IIN_start the first IIN in the range, must be 8 digits
+ * @param IIN_end the last(inclusive) IIN in the range, must be 8
+ * digits
+ * @param number_length the length of account numbers in this IIN range
+ * @param scheme amex/visa/mastercard/etc
+ * @param brand the brand of this IIN range
+ * @param type credit vs debit
+ * @param country the country of the issuer
+ * @param bank_name the name of the issuer
+ * @param bank_url the url of the issuer
+ * @param bank_phone the phone number of the issuer
+ * @param bank_city the city of the issuer
+ */
+ private IINRange(int IIN_start, int IIN_end, Integer number_length, String scheme, String brand, String type, String country, String bank_name, String bank_url, String bank_phone, String bank_city) {
+ this.IINStart = IIN_start;
+ this.IINEnd = IIN_end;
+
+ this.numberLength = number_length;
+ this.scheme = StringUtils.defaultIfBlank(scheme, null);
+ this.brand = StringUtils.defaultIfBlank(brand, null);
+ this.cardType = StringUtils.defaultIfBlank(type, null);
+ this.country = StringUtils.defaultIfBlank(country, null);
+ this.bankName = StringUtils.defaultIfBlank(bank_name, null);
+ this.bankURL = StringUtils.defaultIfBlank(bank_url, null);
+ this.bankPhoneNumber = StringUtils.defaultIfBlank(bank_phone, null);
+ this.bankCity = StringUtils.defaultIfBlank(bank_city, null);
+ }
+
+ /**
+ * Get the first IIN in this range
+ *
+ * @return the first IIN in this range.
+ */
+ int getIINstart() {
+ return IINStart;
+ }
+
+ /**
+ * Get the last (inclusive) IIN in this range.
+ *
+ * @return the last (inclusive) IIN in this range.
+ */
+ int getIINend() {
+ return IINEnd;
+ }
+
+ @Override
+ public Optional getNumberLength() {
+ return Optional.ofNullable(numberLength);
+ }
+
+ @Override
+ public Optional getScheme() {
+ return Optional.ofNullable(scheme);
+ }
+
+ @Override
+ public Optional getBrand() {
+ return Optional.ofNullable(brand);
+ }
+
+ @Override
+ public Optional getCardType() {
+ return Optional.ofNullable(cardType);
+ }
+
+ @Override
+ public Optional getCountry() {
+ return Optional.ofNullable(country);
+ }
+
+ @Override
+ public Optional getBankName() {
+ return Optional.ofNullable(bankName);
+ }
+
+ @Override
+ public Optional getBankURL() {
+ return Optional.ofNullable(bankURL);
+ }
+
+ @Override
+ public Optional getBankPhoneNumber() {
+ return Optional.ofNullable(bankPhoneNumber);
+ }
+
+ @Override
+ public Optional getBankCity() {
+ return Optional.ofNullable(bankCity);
+ }
+ }
+
/**
* Base class for factories that are also observers.
*
@@ -194,13 +430,13 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
@Override
protected void removeNotify() {
super.removeNotify();
- deleteObserver(this);
+ Accounts.this.deleteObserver(this);
}
@Override
protected void addNotify() {
super.addNotify();
- addObserver(this);
+ Accounts.this.addObserver(this);
}
}
@@ -211,8 +447,8 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
public class AccountsRootNode extends DisplayableItemNode {
AccountsRootNode() {
- super(Children.create(new AccountTypeFactory(), true));
- super.setName("Accounts"); //NON-NLS
+ super(Children.create(new AccountTypeFactory(), true), Lookups.singleton(Accounts.this));
+ super.setName(Accounts.NAME);
super.setDisplayName(Bundle.Accounts_RootNode_displayName());
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account_menu.png"); //NON-NLS
}
@@ -226,6 +462,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
public T accept(DisplayableItemNodeVisitor v) {
return v.visit(this);
}
+
}
/**
@@ -345,7 +582,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
/**
* Enum for the children under the credit card AccountTypeNode.
*/
- static private enum CreditCardViewMode {
+ private enum CreditCardViewMode {
BY_FILE,
BY_BIN;
}
@@ -440,7 +677,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
"# {0} - number of children",
"Accounts.ByBINNode.displayName=By BIN ({0})"})
private void updateDisplayName() {
- ArrayList keys = new ArrayList<>();
+ ArrayList keys = new ArrayList<>();
binFactory.createKeys(keys);
setDisplayName(Bundle.Accounts_ByBINNode_displayName(keys.size()));
}
@@ -520,7 +757,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
*/
static List unGroupConcat(String groupConcat, Function mapper) {
return StringUtils.isBlank(groupConcat) ? Collections.emptyList()
- : Stream.of(groupConcat.split(","))
+ : Stream.of(groupConcat.split(",")) //NON-NLS
.map(mapper::apply)
.collect(Collectors.toList());
}
@@ -542,7 +779,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
+ " LEFT JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SOLR_DOCUMENT_ID.getTypeID() //NON-NLS
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT.getTypeID() //NON-NLS
- + " AND blackboard_artifacts.review_status_id != " + BlackboardArtifact.ReviewStatus.REJECTED.getID() //NON-NLS
+ + getRejectedArtifactFilterClause()
+ " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS
+ " ORDER BY hits DESC "; //NON-NLS
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
@@ -564,7 +801,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
@Override
protected Node createNodeForKey(FileWithCCN key) {
- //add all account artifacts for the file and the file itself to th elookup
+ //add all account artifacts for the file and the file itself to the lookup
try {
List
+
diff --git a/KeywordSearch/nbproject/project.properties b/KeywordSearch/nbproject/project.properties
index 0ae8001684..ac11234f18 100644
--- a/KeywordSearch/nbproject/project.properties
+++ b/KeywordSearch/nbproject/project.properties
@@ -51,6 +51,7 @@ file.reference.vorbis-java-tika-0.1.jar=release/modules/ext/vorbis-java-tika-0.1
file.reference.wstx-asl-3.2.7.jar=release/modules/ext/wstx-asl-3.2.7.jar
file.reference.xmlbeans-2.3.0.jar=release/modules/ext/xmlbeans-2.3.0.jar
file.reference.xmpcore-5.1.2.jar=release/modules/ext/xmpcore-5.1.2.jar
+file.reference.xmpcore-5.1.2.jar=release/modules/ext/xmpcore-5.1.2.jar
javac.source=1.8
javac.compilerargs=-Xlint -Xlint:-serial
license.file=../LICENSE-2.0.txt
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchList.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchList.java
index 5c7044e2ab..ab06fc0cbc 100755
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchList.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchList.java
@@ -43,7 +43,7 @@ abstract class KeywordSearchList {
private static final String IP_ADDRESS_REGEX = "(([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])"; //NON-NLS
private static final String EMAIL_ADDRESS_REGEX = "(?=.{8})[a-z0-9%+_-]+(?:\\.[a-z0-9%+_-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z]{2,4}(? theLists; //the keyword data
diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java
index ab5cee98ed..4a4b8cf6d9 100644
--- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java
+++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/TermComponentQuery.java
@@ -19,6 +19,7 @@
//
package org.sleuthkit.autopsy.keywordsearch;
+import com.google.common.base.CharMatcher;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
@@ -65,7 +66,7 @@ final class TermComponentQuery implements KeywordSearchQuery {
*/
private static final Pattern TRACK2_PATTERN = Pattern.compile(
"[:;<=>?]?" //(optional)start sentinel //NON-NLS
- + "(?[3456]\\d{11,18})" //12-19 digit ccn, first digit is 3, 4, 5, or 6 //NON-NLS
+ + "(?[3456]([ -]?\\d){11,18})" //12-19 digits, with possible single spaces or dashes in between. first digit is 3,4,5, or 6 //NON-NLS
+ "(?:[:;<=>?]" //separator //NON-NLS
+ "(?:(?\\d{4})" //4 digit expiration date YYMM //NON-NLS
+ "(?:(?\\d{3})" //3 digit service code //NON-NLS
@@ -85,7 +86,7 @@ final class TermComponentQuery implements KeywordSearchQuery {
"(?:" //begin nested optinal group //NON-NLS
+ "%?" //optional start sentinal: % //NON-NLS
+ "B)?" //format code //NON-NLS
- + "(?[3456]\\d{11,18})" //12-19 digit ccn, first digit is 3, 4, 5, or 6 //NON-NLS
+ + "(?[3456]([ -]?\\d){11,18})" //12-19 digits, with possible single spaces or dashes in between. first digit is 3,4,5, or 6 //NON-NLS
+ "\\^" //separator //NON-NLS
+ "(?[^^]{2,26})" //2-26 charachter name, not containing ^ //NON-NLS
+ "(?:\\^" //separator //NON-NLS
@@ -95,7 +96,7 @@ final class TermComponentQuery implements KeywordSearchQuery {
+ "(?:\\?" // end sentinal: ? //NON-NLS
+ "(?.)" //longitudinal redundancy check //NON-NLS
+ "?)?)?)?)?)?");//close nested optional groups //NON-NLS
- private static final Pattern CCN_PATTERN = Pattern.compile("(?[3456]\\d{11,18})"); //12-19 digit ccn, first digit is 3, 4, 5, or 6 //NON-NLS
+ private static final Pattern CCN_PATTERN = Pattern.compile("(?[3456]([ -]?\\d){11,18})"); //12-19 digits, with possible single spaces or dashes in between. first digit is 3,4,5, or 6 //NON-NLS
private static final LuhnCheckDigit LUHN_CHECK = new LuhnCheckDigit();
//corresponds to field in Solr schema, analyzed with white-space tokenizer only
@@ -114,7 +115,6 @@ final class TermComponentQuery implements KeywordSearchQuery {
TermComponentQuery(KeywordList keywordList, Keyword keyword) {
this.keyword = keyword;
-
this.keywordList = keywordList;
this.escapedQuery = keyword.getQuery();
}
@@ -209,28 +209,26 @@ final class TermComponentQuery implements KeywordSearchQuery {
String ccn = newArtifact.getAttribute(ACCOUNT_NUMBER_TYPE).getValueString();
final int iin = Integer.parseInt(ccn.substring(0, 8));
- Accounts.IINInfo iinRange = Accounts.getIINInfo(iin);
- newArtifact.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CREDIT_CARD_SCHEME, MODULE_NAME, iinRange.getScheme()));
- newArtifact.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PAYMENT_CARD_TYPE, MODULE_NAME, iinRange.getCardType()));
- if (StringUtils.isNotBlank(iinRange.getBrand())) {
- newArtifact.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BRAND, MODULE_NAME, iinRange.getBrand()));
- }
- if (StringUtils.isNotBlank(iinRange.getBankName())) {
- newArtifact.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, iinRange.getBankName()));
- }
- if (StringUtils.isNotBlank(iinRange.getBankPhoneNumber())) {
- newArtifact.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, iinRange.getBankPhoneNumber()));
- }
- if (StringUtils.isNotBlank(iinRange.getBankURL())) {
- newArtifact.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, iinRange.getBankURL()));
- }
- if (StringUtils.isNotBlank(iinRange.getCountry())) {
- newArtifact.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, iinRange.getCountry()));
- }
- if (StringUtils.isNotBlank(iinRange.getBankCity())) {
- newArtifact.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, iinRange.getBankCity()));
- }
+ Accounts.IINInfo iinInfo = Accounts.getIINInfo(iin);
+ if (iinInfo != null) {
+ iinInfo.getScheme().ifPresent(scheme
+ -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_SCHEME, scheme));
+ iinInfo.getCardType().ifPresent(cardType
+ -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_PAYMENT_CARD_TYPE, cardType));
+ iinInfo.getBrand().ifPresent(brand
+ -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_BRAND, brand));
+ iinInfo.getBankName().ifPresent(bankName
+ -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_BANK_NAME, bankName));
+ iinInfo.getBankPhoneNumber().ifPresent(phoneNumber
+ -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, phoneNumber));
+ iinInfo.getBankURL().ifPresent(url
+ -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_URL, url));
+ iinInfo.getCountry().ifPresent(country
+ -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_COUNTRY, country));
+ iinInfo.getBankCity().ifPresent(city
+ -> addAttributeSafe(newArtifact, ATTRIBUTE_TYPE.TSK_CITY, city));
+ }
} else {
//make keyword hit artifact
newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
@@ -269,6 +267,22 @@ final class TermComponentQuery implements KeywordSearchQuery {
}
}
+ /**
+ * Add an attribute of the given type and value to the given artifact,
+ * catching and logging any exceptions.
+ *
+ * @param newArtifact The artifact to add an attribute to.
+ * @param AtributeType The type of attribute to add.
+ * @param attributeValue The value of the attribute to add.
+ */
+ static private void addAttributeSafe(BlackboardArtifact newArtifact, ATTRIBUTE_TYPE AtributeType, String attributeValue) {
+ try {
+ newArtifact.addAttribute(new BlackboardAttribute(AtributeType, MODULE_NAME, attributeValue));
+ } catch (IllegalArgumentException | TskCoreException ex) {
+ LOGGER.log(Level.SEVERE, "Error adding bb attribute to artifact", ex); //NON-NLS
+ }
+ }
+
@Override
public QueryResults performQuery() throws NoOpenCoreException {
/*
@@ -311,7 +325,7 @@ final class TermComponentQuery implements KeywordSearchQuery {
//If the keyword is a credit card number, pass it through luhn validator
Matcher matcher = CCN_PATTERN.matcher(term.getTerm());
matcher.find();
- final String ccn = matcher.group("ccn");
+ final String ccn = CharMatcher.anyOf(" -").removeFrom(matcher.group("ccn"));
if (false == LUHN_CHECK.isValid(ccn)) {
continue; //if the hit does not pass the luhn check, skip it.
}
@@ -371,6 +385,9 @@ final class TermComponentQuery implements KeywordSearchQuery {
BlackboardAttribute.Type type = new BlackboardAttribute.Type(attrType);
if (artifact.getAttribute(type) == null) {
String value = matcher.group(groupName);
+ if (attrType.equals(ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER)) {
+ value = CharMatcher.anyOf(" -").removeFrom(value);
+ }
if (StringUtils.isNotBlank(value)) {
artifact.addAttribute(new BlackboardAttribute(type, MODULE_NAME, value));
}