/*
* Autopsy Forensic Browser
*
* Copyright 2013 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.modules.stix;
import java.util.ArrayList;
import java.util.List;
import org.mitre.cybox.common_2.ConditionApplicationEnum;
import org.mitre.cybox.common_2.ConditionTypeEnum;
import org.mitre.cybox.common_2.StringObjectPropertyType;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
/**
*
*/
abstract class EvaluatableObject {
private String warnings;
protected String id;
protected String spacing;
abstract public ObservableResult evaluate();
/**
* Set the warnings string to the given value.
*
* @param a_warnings
*/
public void setWarnings(String a_warnings) {
warnings = a_warnings;
}
/**
* Get the warnings string. This should not be used to print the final
* version of the warnings.
*
* @return
*/
public String getWarnings() {
return warnings;
}
/**
* Add to the warnings string.
*
* @param a_newWarning
*/
public void addWarning(String a_newWarning) {
if ((warnings == null) || warnings.isEmpty()) {
warnings = a_newWarning;
return;
}
warnings = warnings + ", " + a_newWarning;
}
/**
* Find a list of artifacts with the given attribute type that contain the
* String Object. All comparisons will look for substrings of the Blackboard
* artifacts that match the String Object.
*
* @param item
* @param attrType
*
* @return
*
* @throws TskCoreException
*/
public List<BlackboardArtifact> findArtifactsBySubstring(StringObjectPropertyType item,
BlackboardAttribute.ATTRIBUTE_TYPE attrType) throws TskCoreException {
if (item.getValue() == null) {
throw new TskCoreException("Error: Value field is null"); //NON-NLS
}
if (item.getCondition() == null) {
addWarning("Warning: No condition given for " + attrType.getDisplayName() + " field, using substring comparison"); //NON-NLS
} else if (item.getCondition() != ConditionTypeEnum.CONTAINS) {
addWarning("Warning: Ignoring condition " + item.getCondition() + " for " //NON-NLS
+ attrType.getDisplayName() + " field and doing substring comparison"); //NON-NLS
}
List<BlackboardArtifact> hits = null;
try {
Case case1 = Case.getCurrentCase();
SleuthkitCase sleuthkitCase = case1.getSleuthkitCase();
String[] parts = item.getValue().toString().split("##comma##"); //NON-NLS
if ((item.getApplyCondition() == null)
|| (item.getApplyCondition() == ConditionApplicationEnum.ANY)) {
for (String part : parts) {
if (hits == null) {
// Note that this searches for artifacts with "part" as a substring
hits = sleuthkitCase.getBlackboardArtifacts(
attrType,
part, false);
} else {
hits.addAll(sleuthkitCase.getBlackboardArtifacts(
attrType,
part, false));
}
}
} else if ((item.getApplyCondition() != null)
|| (item.getApplyCondition() == ConditionApplicationEnum.ALL)) {
boolean firstRound = true;
for (String part : parts) {
if (firstRound) {
hits = sleuthkitCase.getBlackboardArtifacts(
attrType,
part, false);
firstRound = false;
} else if (hits != null) {
hits.retainAll(sleuthkitCase.getBlackboardArtifacts(
attrType,
part, false));
} else {
// After first round; hits is still null
// I don't think this should happen but if it does we're done
return new ArrayList<BlackboardArtifact>();
}
}
} else {
throw new TskCoreException("Error: Can not apply NONE condition in search"); //NON-NLS
}
} catch (TskCoreException ex) {
addWarning(ex.getLocalizedMessage());
}
return hits;
}
/**
* Compare a CybOX String Object with a given string.
*
* @param stringObj The CybOX String Object
* @param strField The string to compare against
*
* @return true if strField is a match for the CybOX object
*
* @throws TskCoreException
*/
public static boolean compareStringObject(StringObjectPropertyType stringObj, String strField)
throws TskCoreException {
if (stringObj.getValue() == null) {
throw new TskCoreException("Error: Value field is null"); //NON-NLS
}
String valueStr = stringObj.getValue().toString();
ConditionTypeEnum condition = stringObj.getCondition();
ConditionApplicationEnum applyCondition = stringObj.getApplyCondition();
return compareStringObject(valueStr, condition, applyCondition, strField);
}
/**
* Compare a string with CybOX conditions to a given string.
*
* @param valueStr The CybOX string
* @param condition EQUALS, CONTAINS, STARTS_WITH, etc
* @param applyCondition ANY, ALL, NONE
* @param strField The string to compare against
*
* @return true if strField is a match for the CybOX valueStr and conditions
*
* @throws TskCoreException
*/
public static boolean compareStringObject(String valueStr, ConditionTypeEnum condition,
ConditionApplicationEnum applyCondition, String strField)
throws TskCoreException {
if (valueStr == null) {
throw new TskCoreException("Error: Value field is null"); //NON-NLS
}
String[] parts = valueStr.split("##comma##"); //NON-NLS
String lowerFieldName = strField.toLowerCase();
for (String value : parts) {
boolean partialResult;
if ((condition == null)
|| (condition == ConditionTypeEnum.EQUALS)) {
partialResult = value.equalsIgnoreCase(strField);
} else if (condition == ConditionTypeEnum.DOES_NOT_EQUAL) {
partialResult = !value.equalsIgnoreCase(strField);
} else if (condition == ConditionTypeEnum.CONTAINS) {
partialResult = lowerFieldName.contains(value.toLowerCase());
} else if (condition == ConditionTypeEnum.DOES_NOT_CONTAIN) {
partialResult = !lowerFieldName.contains(value.toLowerCase());
} else if (condition == ConditionTypeEnum.STARTS_WITH) {
partialResult = lowerFieldName.startsWith(value.toLowerCase());
} else if (condition == ConditionTypeEnum.ENDS_WITH) {
partialResult = lowerFieldName.endsWith(value.toLowerCase());
} else {
throw new TskCoreException("Could not process condition " + condition.value() + " on " + value); //NON-NLS
}
// Do all the short-circuiting
if (applyCondition == ConditionApplicationEnum.NONE) {
if (partialResult == true) {
// Failed
return false;
}
} else if (applyCondition == ConditionApplicationEnum.ALL) {
if (partialResult == false) {
// Failed
return false;
}
} else {
// Default is "any"
if (partialResult == true) {
return true;
}
}
}
// At this point we're done and didn't short-circuit, so ALL or NONE conditions were true,
// and ANY was false
if ((applyCondition == ConditionApplicationEnum.NONE)
|| (applyCondition == ConditionApplicationEnum.ALL)) {
return true;
}
return false;
}
/**
* Format the warnings that will be printed. Basically, just put parentheses
* around them if the string isn't empty.
*
* @return
*/
public String getPrintableWarnings() {
String warningsToPrint = "";
if ((getWarnings() != null)
&& (!getWarnings().isEmpty())) {
warningsToPrint = " (" + getWarnings() + ")";
}
return warningsToPrint;
}
}