mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 10:17:41 +00:00
SOLR_DOCUMENT_IDs working in query; cleanup and comments in Accounts.java
This commit is contained in:
parent
ba308fb5da
commit
762f62bc7c
@ -22,6 +22,7 @@ import java.beans.PropertyChangeEvent;
|
|||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -37,7 +38,6 @@ import org.openide.nodes.ChildFactory;
|
|||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.openide.util.Exceptions;
|
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
@ -75,6 +75,11 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for factories that are also observers.
|
||||||
|
*
|
||||||
|
* @param <X> The type of keys used by this factory.
|
||||||
|
*/
|
||||||
private abstract class ObservingChildFactory<X> extends ChildFactory.Detachable<X> implements Observer {
|
private abstract class ObservingChildFactory<X> extends ChildFactory.Detachable<X> implements Observer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -103,9 +108,9 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
AccountsRootNode() {
|
AccountsRootNode() {
|
||||||
super(Children.create(new AccountTypeFactory(), true));
|
super(Children.create(new AccountTypeFactory(), true));
|
||||||
super.setName("Accounts"); //NON-NLS
|
super.setName("Accounts"); //NON-NLS
|
||||||
super.setDisplayName(Bundle.Accounts_RootNode_displayName());
|
super.setDisplayName(Bundle.Accounts_RootNode_displayName());
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account_menu.png");
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account_menu.png"); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -126,7 +131,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
private class AccountTypeFactory extends ObservingChildFactory<String> {
|
private class AccountTypeFactory extends ObservingChildFactory<String> {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The pcl is in the class because it has the easiest mechanisms to add
|
* The pcl is in this class because it has the easiest mechanisms to add
|
||||||
* and remove itself during its life cycles.
|
* and remove itself during its life cycles.
|
||||||
*/
|
*/
|
||||||
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
private final PropertyChangeListener pcl = new PropertyChangeListener() {
|
||||||
@ -219,7 +224,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
private AccountTypeNode(String accountTypeName) {
|
private AccountTypeNode(String accountTypeName) {
|
||||||
super(Children.create(new ViewModeFactory(), true));
|
super(Children.create(new ViewModeFactory(), true));
|
||||||
super.setName(accountTypeName);
|
super.setName(accountTypeName);
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -241,6 +246,10 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
BY_BIN;
|
BY_BIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ChildFactory that makes nodes for the different account organizations (by
|
||||||
|
* file, by BIN)
|
||||||
|
*/
|
||||||
private class ViewModeFactory extends ObservingChildFactory<CreditCardViewMode> {
|
private class ViewModeFactory extends ObservingChildFactory<CreditCardViewMode> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -262,20 +271,31 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ByFileNode extends DisplayableItemNode {
|
/**
|
||||||
|
* Node that is the root of the "by file" accounts tree. Its children are
|
||||||
|
* FileWithCCNNodes.
|
||||||
|
*/
|
||||||
|
public class ByFileNode extends DisplayableItemNode implements Observer {
|
||||||
|
|
||||||
|
private final FileWithCCNFactory fileFactory;
|
||||||
|
|
||||||
private ByFileNode() {
|
private ByFileNode() {
|
||||||
super(Children.create(new FileFactory(), true));
|
super(Children.LEAF);
|
||||||
setName("By File");
|
fileFactory = new FileWithCCNFactory();
|
||||||
|
setChildren(Children.create(fileFactory, true));
|
||||||
|
setName("By File"); //NON-NLS
|
||||||
updateDisplayName();
|
updateDisplayName();
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon.png"); //NON-NLS
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon.png"); //NON-NLS
|
||||||
|
Accounts.this.addObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@NbBundle.Messages({
|
||||||
* TODO: Update the count in the display name
|
"# {0} - number of children",
|
||||||
*/
|
"Accounts.ByFileNode.displayName=By File ({0})"})
|
||||||
private void updateDisplayName() {
|
private void updateDisplayName() {
|
||||||
setDisplayName("By File");
|
ArrayList<FileWithCCN> keys = new ArrayList<>();
|
||||||
|
fileFactory.createKeys(keys);
|
||||||
|
setDisplayName(Bundle.Accounts_ByFileNode_displayName(keys.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -287,16 +307,38 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
updateDisplayName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ByBINNode extends DisplayableItemNode {
|
/**
|
||||||
|
* Node that is the root of the "By BIN" accounts tree. Its children are
|
||||||
|
* BINNodes.
|
||||||
|
*/
|
||||||
|
public class ByBINNode extends DisplayableItemNode implements Observer {
|
||||||
|
|
||||||
|
private final BINFactory binFactory;
|
||||||
|
|
||||||
private ByBINNode() {
|
private ByBINNode() {
|
||||||
super(Children.create(new BINFactory(), true));
|
super(Children.LEAF);
|
||||||
setName("By BIN");
|
binFactory = new BINFactory();
|
||||||
|
setChildren(Children.create(binFactory, true));
|
||||||
|
setName("By BIN"); //NON-NLS
|
||||||
updateDisplayName();
|
updateDisplayName();
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/bank.png"); //NON-NLS
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/bank.png"); //NON-NLS
|
||||||
|
Accounts.this.addObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"# {0} - number of children",
|
||||||
|
"Accounts.ByBINNode.displayName=By BIN ({0})"})
|
||||||
|
private void updateDisplayName() {
|
||||||
|
ArrayList<BINInfo> keys = new ArrayList<>();
|
||||||
|
binFactory.createKeys(keys);
|
||||||
|
setDisplayName(Bundle.Accounts_ByBINNode_displayName(keys.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -309,31 +351,29 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* TODO: Update the count in the display name
|
public void update(Observable o, Object arg) {
|
||||||
*/
|
updateDisplayName();
|
||||||
private void updateDisplayName() {
|
|
||||||
setDisplayName("By BIN");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DataModel for a child of the ByFileNode. Represents a file(chunk) and its
|
||||||
|
* associated accounts.
|
||||||
|
*/
|
||||||
private static class FileWithCCN {
|
private static class FileWithCCN {
|
||||||
|
|
||||||
final long objID;
|
private final long objID;
|
||||||
final long chunkID;
|
private final String solrDocumentId;
|
||||||
final List<Long> artifactIDS;
|
private final List<Long> artifactIDS;
|
||||||
final long hits;
|
private final long hits;
|
||||||
final long accepted;
|
|
||||||
private final String status;
|
private final String status;
|
||||||
|
|
||||||
private FileWithCCN(long objID, long chunkID, List<Long> artifactIDS, long hits, long accepted, String status) {
|
private FileWithCCN(long objID, String solrDocID, List<Long> artifactIDS, long hits, String status) {
|
||||||
|
|
||||||
this.objID = objID;
|
this.objID = objID;
|
||||||
this.chunkID = chunkID;
|
this.solrDocumentId = solrDocID;
|
||||||
this.artifactIDS = artifactIDS;
|
this.artifactIDS = artifactIDS;
|
||||||
this.hits = hits;
|
this.hits = hits;
|
||||||
this.accepted = accepted;
|
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,8 +381,8 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
return objID;
|
return objID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getChunkID() {
|
public String getSolrDocmentID() {
|
||||||
return chunkID;
|
return solrDocumentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Long> getArtifactIDS() {
|
public List<Long> getArtifactIDS() {
|
||||||
@ -353,10 +393,6 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
return hits;
|
return hits;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getAccepted() {
|
|
||||||
return accepted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getStatus() {
|
public String getStatus() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -386,38 +422,37 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FileFactory extends ObservingChildFactory<FileWithCCN> {
|
/**
|
||||||
|
* Factory for the children of the ByFiles Node.
|
||||||
|
*/
|
||||||
|
private class FileWithCCNFactory extends ObservingChildFactory<FileWithCCN> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<FileWithCCN> list) {
|
protected boolean createKeys(List<FileWithCCN> list) {
|
||||||
String query =
|
String query =
|
||||||
"select distinct blackboard_artifacts.obj_id as obj_id,"
|
"SELECT blackboard_artifacts.obj_id," //NON-NLS
|
||||||
+ " blackboard_attributes.value_int32 as solr_document_id,"
|
+ " blackboard_attributes.value_text AS solr_document_id, " //NON-NLS
|
||||||
+ " group_concat(blackboard_artifacts.artifact_id),"
|
+ " GROUP_CONCAT(blackboard_artifacts.artifact_id) AS artifact_IDs, " //NON-NLS
|
||||||
+ " count(blackboard_artifacts.artifact_id) as hits "
|
+ " COUNT( blackboard_artifacts.artifact_id) AS hits " //NON-NLS
|
||||||
// + " count (case when blackboard_artifacts.status like \"accepted\" then 1 else Null end) as accepted"
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " from blackboard_artifacts, "
|
+ " LEFT JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
|
||||||
+ " blackboard_attributes "
|
+ " 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()
|
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT.getTypeID() //NON-NLS
|
||||||
// + " and not (blackboard_artifacts.status like \"rejected\") "
|
+ " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS
|
||||||
+ " and blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id "
|
+ " ORDER BY hits DESC "; //NON-NLS
|
||||||
+ " and blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SOLR_DOCUMENT_ID.getTypeID()
|
|
||||||
+ " group by blackboard_artifacts.obj_id, solr_document_id"
|
|
||||||
+ " order by hits desc";//, accepted desc";
|
|
||||||
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
|
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
|
||||||
ResultSet rs = results.getResultSet();) {
|
ResultSet rs = results.getResultSet();) {
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
list.add(new FileWithCCN(
|
list.add(new FileWithCCN(
|
||||||
rs.getLong("obj_id"),
|
rs.getLong("obj_id"), //NON-NLS
|
||||||
rs.getLong("solr_document_id"),
|
rs.getString("solr_document_id"), //NON-NLS
|
||||||
unGroupConcat(rs.getString("group_concat(blackboard_artifacts.artifact_id)"), Long::valueOf),
|
unGroupConcat(rs.getString("artifact_IDs"), Long::valueOf), //NON-NLS
|
||||||
rs.getLong("hits"),
|
rs.getLong("hits"), //NON-NLS
|
||||||
0,
|
"unreviewed")); //NON-NLS
|
||||||
"unreviewed"));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (TskCoreException | SQLException ex) {
|
} catch (TskCoreException | SQLException ex) {
|
||||||
Exceptions.printStackTrace(ex);
|
LOGGER.log(Level.SEVERE, "Error querying for files with ccn hits.", ex); //NON-NLS
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -427,6 +462,7 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
try {
|
try {
|
||||||
return new FileWithCCNNode(key, skCase.getAbstractFileById(key.getObjID()));
|
return new FileWithCCNNode(key, skCase.getAbstractFileById(key.getObjID()));
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Error getting content for file with ccn hits.", ex); //NON-NLS
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -437,17 +473,26 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node that represents a file or chunk of an unallocated space file.
|
||||||
|
*/
|
||||||
public class FileWithCCNNode extends DisplayableItemNode {
|
public class FileWithCCNNode extends DisplayableItemNode {
|
||||||
|
|
||||||
private final FileWithCCN key;
|
private final FileWithCCN fileKey;
|
||||||
private final Content content;
|
private final String fileName;
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"# {0} - raw file name",
|
||||||
|
"# {1} - solr chunk id",
|
||||||
|
"Accounts.FileWithCCNNode.unallocatedSpaceFile.displayName={0}_chunk_{1}"})
|
||||||
private FileWithCCNNode(FileWithCCN key, Content content) {
|
private FileWithCCNNode(FileWithCCN key, Content content) {
|
||||||
super(Children.LEAF, Lookups.singleton(content));
|
super(Children.LEAF, Lookups.singleton(content));
|
||||||
|
this.fileKey = key;
|
||||||
setName(content.getName() + "_" + key.getChunkID());
|
this.fileName = (key.getSolrDocmentID() == null)
|
||||||
this.key = key;
|
? content.getName()
|
||||||
this.content = content;
|
: Bundle.Accounts_FileWithCCNNode_unallocatedSpaceFile_displayName(content.getName(), StringUtils.substringAfter(key.getSolrDocmentID(), "_"));
|
||||||
|
setName(fileName);
|
||||||
|
setDisplayName(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -461,6 +506,11 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"Accounts.FileWithCCNNode.nameProperty.displayName=File",
|
||||||
|
"Accounts.FileWithCCNNode.accountsProperty.displayName=Accounts",
|
||||||
|
"Accounts.FileWithCCNNode.statusProperty.displayName=Status",
|
||||||
|
"Accounts.FileWithCCNNode.noDescription=no description"})
|
||||||
protected Sheet createSheet() {
|
protected Sheet createSheet() {
|
||||||
Sheet s = super.createSheet();
|
Sheet s = super.createSheet();
|
||||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||||
@ -469,25 +519,51 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
s.put(ss);
|
s.put(ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
ss.put(new NodeProperty<>("File Name", "File Name", "no description", content.getName() + "_" + key.getChunkID()));
|
ss.put(new NodeProperty<>(Bundle.Accounts_FileWithCCNNode_nameProperty_displayName(),
|
||||||
ss.put(new NodeProperty<>("Hits", "Hits", "no description", key.getHits()));
|
Bundle.Accounts_FileWithCCNNode_nameProperty_displayName(),
|
||||||
ss.put(new NodeProperty<>("Accepted", "Accepted", "no description", key.getAccepted()));
|
Bundle.Accounts_FileWithCCNNode_noDescription(),
|
||||||
ss.put(new NodeProperty<>("Status", "Status", "no description", key.getStatus()));
|
fileName));
|
||||||
|
ss.put(new NodeProperty<>(Bundle.Accounts_FileWithCCNNode_accountsProperty_displayName(),
|
||||||
|
Bundle.Accounts_FileWithCCNNode_accountsProperty_displayName(),
|
||||||
|
Bundle.Accounts_FileWithCCNNode_noDescription(),
|
||||||
|
fileKey.getHits()));
|
||||||
|
ss.put(new NodeProperty<>(Bundle.Accounts_FileWithCCNNode_statusProperty_displayName(),
|
||||||
|
Bundle.Accounts_FileWithCCNNode_statusProperty_displayName(),
|
||||||
|
Bundle.Accounts_FileWithCCNNode_noDescription(),
|
||||||
|
fileKey.getStatus()));
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class BINNode extends DisplayableItemNode {
|
/**
|
||||||
|
* Node that represents a BIN (Bank Identification Number)
|
||||||
|
*/
|
||||||
|
public class BINNode extends DisplayableItemNode implements Observer {
|
||||||
|
|
||||||
private final BIN bin;
|
private final BINInfo bin;
|
||||||
|
private final AccountFactory accountFactory;
|
||||||
|
|
||||||
private BINNode(BIN key) {
|
private BINNode(BINInfo bin) {
|
||||||
super(Children.create(new AccountFactory(key), true));
|
super(Children.LEAF);
|
||||||
this.bin = key;
|
this.bin = bin;
|
||||||
setName(key.toString());
|
accountFactory = new AccountFactory(bin);
|
||||||
setDisplayName(key.getBIN().toString() + " (" + key.getCount() + ")");
|
setChildren(Children.create(accountFactory, true));
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/bank.png"); //NON-NLS
|
setName(bin.toString());
|
||||||
|
updateDisplayName();
|
||||||
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/bank.png"); //NON-NLS
|
||||||
|
Accounts.this.addObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Observable o, Object arg) {
|
||||||
|
updateDisplayName();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDisplayName() {
|
||||||
|
ArrayList<Long> keys = new ArrayList<>();
|
||||||
|
accountFactory.createKeys(keys);
|
||||||
|
setDisplayName(bin.getBIN().toString() + " (" + keys.size() + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -501,6 +577,10 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"Accounts.BINNode.binProperty.displayName=Bank Identifier Number",
|
||||||
|
"Accounts.BINNode.accountsProperty.displayName=Accounts",
|
||||||
|
"Accounts.BINNode.noDescription=no description"})
|
||||||
protected Sheet createSheet() {
|
protected Sheet createSheet() {
|
||||||
Sheet s = super.createSheet();
|
Sheet s = super.createSheet();
|
||||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
||||||
@ -509,51 +589,66 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
s.put(ss);
|
s.put(ss);
|
||||||
}
|
}
|
||||||
|
|
||||||
ss.put(new NodeProperty<>("Bank Identifier Number", "Bank Identifier Number", "no description", bin.getBIN()));
|
ss.put(new NodeProperty<>(Bundle.Accounts_BINNode_binProperty_displayName(),
|
||||||
ss.put(new NodeProperty<>("Accounts ", "Accounts", "no description", bin.getCount()));
|
Bundle.Accounts_BINNode_binProperty_displayName(),
|
||||||
|
Bundle.Accounts_BINNode_noDescription(),
|
||||||
|
bin.getBIN()));
|
||||||
|
ss.put(new NodeProperty<>(Bundle.Accounts_BINNode_accountsProperty_displayName(),
|
||||||
|
Bundle.Accounts_BINNode_accountsProperty_displayName(), Bundle.Accounts_BINNode_noDescription(),
|
||||||
|
bin.getCount()));
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BINFactory extends ObservingChildFactory<BIN> {
|
/**
|
||||||
|
* Factory that generates the children of the ByBin node.
|
||||||
|
*/
|
||||||
|
private class BINFactory extends ObservingChildFactory<BINInfo> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<BIN> list) {
|
protected boolean createKeys(List<BINInfo> list) {
|
||||||
String query =
|
String query =
|
||||||
"select substr(blackboard_attributes.value_text,1,6) as BIN, "
|
"SELECT SUBSTR(blackboard_attributes.value_text,1,6) AS BIN, " //NON-NLS
|
||||||
+ " count(blackboard_artifacts.artifact_type_id) as count "
|
+ " COUNT(blackboard_artifacts.artifact_id) AS count " //NON-NLS
|
||||||
+ " from blackboard_artifacts,"
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " blackboard_attributes "
|
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS
|
||||||
+ " where blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT.getTypeID()
|
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT.getTypeID() //NON-NLS
|
||||||
+ " and blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id "
|
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER.getTypeID() //NON-NLS
|
||||||
+ " and blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER.getTypeID()
|
+ " GROUP BY BIN " //NON-NLS
|
||||||
+ " GROUP BY BIN "
|
+ " ORDER BY BIN "; //NON-NLS
|
||||||
+ " ORDER BY BIN ";
|
|
||||||
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query)) {
|
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query)) {
|
||||||
ResultSet resultSet = results.getResultSet();
|
ResultSet resultSet = results.getResultSet();
|
||||||
while (resultSet.next()) {
|
while (resultSet.next()) {
|
||||||
list.add(new BIN(Integer.valueOf(resultSet.getString("BIN")),
|
list.add(new BINInfo(Integer.valueOf(resultSet.getString("BIN")), //NON-NLS
|
||||||
resultSet.getLong("count")));
|
resultSet.getLong("count"))); //NON-NLS
|
||||||
}
|
}
|
||||||
} catch (TskCoreException | SQLException ex) {
|
} catch (TskCoreException | SQLException ex) {
|
||||||
Exceptions.printStackTrace(ex);
|
LOGGER.log(Level.SEVERE, "Error querying for BINs.", ex); //NON-NLS
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Node createNodeForKey(BIN key) {
|
protected Node createNodeForKey(BINInfo key) {
|
||||||
return new BINNode(key);
|
return new BINNode(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BIN {
|
/**
|
||||||
|
* Data model item to back the BINNodes in the tree. Has basic info about a
|
||||||
|
* BIN.
|
||||||
|
*/
|
||||||
|
private class BINInfo {
|
||||||
|
|
||||||
private final Integer bin;
|
private final Integer bin;
|
||||||
|
/**
|
||||||
|
* The number of accounts with this BIN
|
||||||
|
*/
|
||||||
private final Long count;
|
private final Long count;
|
||||||
|
|
||||||
private BIN(Integer bin, Long count) {
|
private BINInfo(Integer bin, Long count) {
|
||||||
this.bin = bin;
|
this.bin = bin;
|
||||||
this.count = count;
|
this.count = count;
|
||||||
}
|
}
|
||||||
@ -572,47 +667,47 @@ public class Accounts extends Observable implements AutopsyVisitableItem {
|
|||||||
*/
|
*/
|
||||||
private class AccountFactory extends ObservingChildFactory<Long> {
|
private class AccountFactory extends ObservingChildFactory<Long> {
|
||||||
|
|
||||||
private final BIN bin;
|
private final BINInfo bin;
|
||||||
|
|
||||||
private AccountFactory(BIN bin) {
|
private AccountFactory(BINInfo bin) {
|
||||||
this.bin = bin;
|
this.bin = bin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<Long> list) {
|
protected boolean createKeys(List<Long> list) {
|
||||||
String query =
|
String query =
|
||||||
"select blackboard_artifacts.artifact_id "
|
"SELECT blackboard_artifacts.artifact_id " //NON-NLS
|
||||||
+ " from blackboard_artifacts, "
|
+ " FROM blackboard_artifacts " //NON-NLS
|
||||||
+ " blackboard_attributes "
|
+ " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
|
||||||
+ " where blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT.getTypeID()
|
+ " WHERE blackboard_artifacts.artifact_type_id = " + BlackboardArtifact.ARTIFACT_TYPE.TSK_CREDIT_CARD_ACCOUNT.getTypeID() //NON-NLS
|
||||||
+ " and blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id "
|
+ " AND blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER.getTypeID() //NON-NLS
|
||||||
+ " and blackboard_attributes.attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER.getTypeID()
|
+ " AND blackboard_attributes.value_text LIKE \"" + bin.getBIN() + "%\" " //NON-NLS
|
||||||
+ " and blackboard_attributes.value_text LIKE \"" + bin.getBIN() + "%\" "
|
+ " ORDER BY blackboard_attributes.value_text"; //NON-NLS
|
||||||
+ " ORDER BY blackboard_attributes.value_text";
|
|
||||||
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
|
try (SleuthkitCase.CaseDbQuery results = skCase.executeQuery(query);
|
||||||
ResultSet rs = results.getResultSet();) {
|
ResultSet rs = results.getResultSet();) {
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
list.add(rs.getLong("artifact_id"));
|
list.add(rs.getLong("artifact_id")); //NON-NLS
|
||||||
}
|
}
|
||||||
} catch (TskCoreException | SQLException ex) {
|
} catch (TskCoreException | SQLException ex) {
|
||||||
Exceptions.printStackTrace(ex);
|
LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Node createNodeForKey(Long id) {
|
protected Node createNodeForKey(Long artifactID) {
|
||||||
if (skCase == null) {
|
if (skCase == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
BlackboardArtifact art = skCase.getBlackboardArtifact(id);
|
BlackboardArtifact art = skCase.getBlackboardArtifact(artifactID);
|
||||||
return new BlackboardArtifactNode(art, "org/sleuthkit/autopsy/images/credit-card.png");
|
return new BlackboardArtifactNode(art, "org/sleuthkit/autopsy/images/credit-card.png"); //NON-NLS
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
LOGGER.log(Level.WARNING, "TSK Exception occurred", ex); //NON-NLS
|
LOGGER.log(Level.WARNING, "Error creating BlackboardArtifactNode for artifact with ID " + artifactID, ex); //NON-NLS
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,11 +33,13 @@ import org.apache.solr.client.solrj.SolrQuery;
|
|||||||
import org.apache.solr.client.solrj.response.TermsResponse.Term;
|
import org.apache.solr.client.solrj.response.TermsResponse.Term;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.coreutils.Version;
|
import org.sleuthkit.autopsy.coreutils.Version;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a regular expression query to the SOLR/Lucene instance.
|
* Performs a regular expression query to the SOLR/Lucene instance.
|
||||||
@ -185,12 +187,19 @@ final class TermComponentQuery implements KeywordSearchQuery {
|
|||||||
//try to match it against the track 1 regex
|
//try to match it against the track 1 regex
|
||||||
Matcher matcher = TRACK1_PATTERN.matcher(hit.getSnippet());
|
Matcher matcher = TRACK1_PATTERN.matcher(hit.getSnippet());
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
parseTrack1Data(bba, matcher, hit);
|
parseTrack1Data(bba, matcher);
|
||||||
}
|
}
|
||||||
//then try to match it against the track 2 regex
|
//then try to match it against the track 2 regex
|
||||||
matcher = TRACK2_PATTERN.matcher(hit.getSnippet());
|
matcher = TRACK2_PATTERN.matcher(hit.getSnippet());
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
parseTrack2Data(bba, matcher, hit);
|
parseTrack2Data(bba, matcher);
|
||||||
|
}
|
||||||
|
if (hit.getContent() instanceof AbstractFile) {
|
||||||
|
AbstractFile file = (AbstractFile) hit.getContent();
|
||||||
|
if (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS
|
||||||
|
|| file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) {
|
||||||
|
bba.addAttribute(new BlackboardAttribute(SOLR_DOCUMENT_ID_TYPE, MODULE_NAME, hit.getSolrDocumentId()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//make keyword hit artifact
|
//make keyword hit artifact
|
||||||
@ -344,7 +353,7 @@ final class TermComponentQuery implements KeywordSearchQuery {
|
|||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
* @throws TskCoreException
|
* @throws TskCoreException
|
||||||
*/
|
*/
|
||||||
static private void parseTrack2Data(BlackboardArtifact artifact, Matcher matcher, KeywordHit hit) throws IllegalArgumentException, TskCoreException {
|
static private void parseTrack2Data(BlackboardArtifact artifact, Matcher matcher) throws IllegalArgumentException, TskCoreException {
|
||||||
//try to add all the attrributes common to track 1 and 2
|
//try to add all the attrributes common to track 1 and 2
|
||||||
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER, "accountNumber", matcher);
|
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_ACCOUNT_NUMBER, "accountNumber", matcher);
|
||||||
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_EXPIRATION, "expiration", matcher);
|
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_EXPIRATION, "expiration", matcher);
|
||||||
@ -352,9 +361,6 @@ final class TermComponentQuery implements KeywordSearchQuery {
|
|||||||
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_DISCRETIONARY, "discretionary", matcher);
|
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_DISCRETIONARY, "discretionary", matcher);
|
||||||
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_LRC, "LRC", matcher);
|
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_CREDIT_CARD_LRC, "LRC", matcher);
|
||||||
|
|
||||||
if (artifact.getAttribute(SOLR_DOCUMENT_ID_TYPE) == null) {
|
|
||||||
artifact.addAttribute(new BlackboardAttribute(SOLR_DOCUMENT_ID_TYPE, MODULE_NAME, hit.getSolrDocumentId()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -368,9 +374,9 @@ final class TermComponentQuery implements KeywordSearchQuery {
|
|||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
* @throws TskCoreException
|
* @throws TskCoreException
|
||||||
*/
|
*/
|
||||||
static private void parseTrack1Data(BlackboardArtifact artifact, Matcher matcher, KeywordHit hit) throws IllegalArgumentException, TskCoreException {
|
static private void parseTrack1Data(BlackboardArtifact artifact, Matcher matcher) throws IllegalArgumentException, TskCoreException {
|
||||||
// track 1 has all the fields present in track 2
|
// track 1 has all the fields present in track 2
|
||||||
parseTrack2Data(artifact, matcher, hit);
|
parseTrack2Data(artifact, matcher);
|
||||||
//plus it also has the account holders name
|
//plus it also has the account holders name
|
||||||
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_NAME_PERSON, "name", matcher);
|
addAttributeIfNotAlreadyCaptured(artifact, ATTRIBUTE_TYPE.TSK_NAME_PERSON, "name", matcher);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user