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 */
19 package org.sleuthkit.autopsy.datamodel.accounts;
20
21 import com.google.common.collect.Range;
22 import com.google.common.collect.RangeMap;
23 import com.google.common.collect.TreeRangeMap;
24 import com.google.common.eventbus.EventBus;
25 import com.google.common.eventbus.Subscribe;
26 import java.awt.event.ActionEvent;
27 import java.beans.PropertyChangeEvent;
28 import java.beans.PropertyChangeListener;
29 import java.sql.ResultSet;
30 import java.sql.SQLException;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collection;
34 import java.util.Collections;
35 import java.util.HashSet;
36 import java.util.List;
37 import java.util.Objects;
38 import java.util.Optional;
39 import java.util.Set;
40 import java.util.function.Function;
41 import java.util.logging.Level;
42 import java.util.logging.Logger;
43 import java.util.stream.Collectors;
44 import java.util.stream.Stream;
45 import javax.annotation.Nonnull;
46 import javax.annotation.concurrent.Immutable;
47 import javax.swing.AbstractAction;
48 import javax.swing.Action;
49 import org.apache.commons.lang3.StringUtils;
50 import org.openide.nodes.Children;
51 import org.openide.nodes.Node;
52 import org.openide.nodes.NodeNotFoundException;
53 import org.openide.nodes.NodeOp;
54 import org.openide.nodes.Sheet;
55 import org.openide.util.NbBundle;
56 import org.openide.util.Utilities;
57 import org.openide.util.lookup.Lookups;
80
86
87 private static final Logger
LOGGER = Logger.getLogger(
Accounts.class.getName());
88
89 @NbBundle.Messages("AccountsRootNode.name=Accounts")
90 final public static String
NAME = Bundle.AccountsRootNode_name();
91
94
99
102
110
113 }
114
115 @Override
117 return v.
visit(
this);
118 }
119
129 }
130
140 }
141
149
155 super(true);
156 }
157
162 abstract protected Collection<X>
createKeys();
163
167 void refreshKeys() {
169 }
170
176 @Subscribe
178
179 @Subscribe
181
182 @Override
184 super.removeNotify();
186 }
187
188 @Override
190 super.addNotify();
191 refreshKeys();
193 }
194 }
195
199 @NbBundle.Messages({"Accounts.RootNode.displayName=Accounts"})
201
206
207 /*
208 * The pcl is in this class because it has the easiest mechanisms to
209 * add and remove itself during its life cycles.
210 */
211 private final PropertyChangeListener pcl =
new PropertyChangeListener() {
212 @Override
213 public void propertyChange(PropertyChangeEvent evt) {
214 String eventType = evt.getPropertyName();
222 try {
232 if (null != eventData
234 reviewStatusBus.post(eventData);
235 }
236 } catch (IllegalStateException notUsed) {
237 // Case is closed, do nothing.
238 }
247 try {
249 refreshKeys();
250 } catch (IllegalStateException notUsed) {
251 // Case is closed, do nothing.
252 }
254 // case was closed. Remove listeners so that we don't get called with a stale case handle
255 if (evt.getNewValue() == null) {
256 removeNotify();
257 skCase = null;
258 }
259 }
260 }
261 };
262
263 @Subscribe
264 @Override
266 refreshKeys();
267 }
268
269 @Subscribe
270 @Override
272 refreshKeys();
273 }
274
275 @Override
277 List<String> list = new ArrayList<>();
279 "SELECT DISTINCT blackboard_attributes.value_text as account_type "
280 + " FROM blackboard_attributes "
283 while (resultSet.next()) {
284 String accountType = resultSet.getString("account_type");
285 list.add(accountType);
286 }
288 LOGGER.log(Level.SEVERE, "Error querying for account_types", ex);
289 }
290 return list;
291 }
292
293 @Override
295 try {
297 switch (accountType) {
298 case CREDIT_CARD:
300 default:
302 }
303 } catch (IllegalArgumentException ex) {
304 LOGGER.log(Level.WARNING, "Unknown account type: {0}", key);
305 //Flesh out what happens with other account types here.
307 }
308 }
309
310 @Override
315 super.removeNotify();
316 }
317
318 @Override
323 super.addNotify();
324 refreshKeys();
325 }
326
327 }
328
330 super(Children.LEAF, Lookups.singleton(
Accounts.this));
331 setChildren(Children.createLazy(AccountTypeFactory::new));
333 setDisplayName(Bundle.Accounts_RootNode_displayName());
334 this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/accounts.png"); //NON-NLS
335 }
336
337 @Override
339 return false;
340 }
341
342 @Override
344 return v.
visit(
this);
345 }
346
347 @Override
349 return getClass().getName();
350 }
351 }
352
358
360
362
364 }
365
366 @Override
368 List<Long> list = new ArrayList<>();
369 String query
370 = "SELECT blackboard_artifacts.artifact_id " //NON-NLS
371 + " FROM blackboard_artifacts " //NON-NLS
372 + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
375 + " AND blackboard_attributes.value_text = '" + accountTypeName + "'" //NON-NLS
379 while (rs.next()) {
380 list.add(rs.getLong("artifact_id")); //NON-NLS
381 }
383 LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS
384 }
385 return list;
386 }
387
388 @Override
390 try {
393 LOGGER.log(Level.SEVERE, "Error get black board artifact with id " + t, ex);
394 return new Node[0];
395 }
396 }
397
398 @Subscribe
399 @Override
401 refreshKeys();
402 }
403
404 @Subscribe
405 @Override
407 refreshKeys();
408 }
409 }
410
412 super(Children.LEAF);
414 setChildren(Children.createLazy(DefaultAccountFactory::new));
415 setName(accountTypeName);
416 this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS
417 }
418
419 @Override
421 return true;
422 }
423
424 @Override
426 return v.
visit(
this);
427 }
428
429 @Override
431 return getClass().getName();
432 }
433 }
434
441 }
442
447
453
454 @Override
456 }
457
458 @Override
460 }
461
465 @Override
468
469 }
470
471 @Override
473 switch (key) {
474 case BY_BIN:
476 case BY_FILE:
478 default:
479 return new Node[0];
480 }
481 }
482 }
483
485 super(Children.LEAF);
488 this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/credit-cards.png"); //NON-NLS
489 }
490
491 @Override
493 return false;
494 }
495
496 @Override
498 return v.
visit(
this);
499 }
500
501 @Override
503 return getClass().getName();
504 }
505 }
506
512
517
518 @Subscribe
519 @Override
521 refreshKeys();
522 }
523
524 @Subscribe
525 @Override
527 refreshKeys();
528 }
529
530 @Override
532 List<FileWithCCN> list = new ArrayList<>();
533 String query
534 = "SELECT blackboard_artifacts.obj_id," //NON-NLS
535 + " solr_attribute.value_text AS solr_document_id, "; //NON-NLS
537 query += " string_agg(blackboard_artifacts.artifact_id::character varying, ',') AS artifact_IDs, " //NON-NLS
538 + " string_agg(blackboard_artifacts.review_status_id::character varying, ',') AS review_status_ids, ";
539 } else {
540 query += " GROUP_CONCAT(blackboard_artifacts.artifact_id) AS artifact_IDs, " //NON-NLS
541 + " GROUP_CONCAT(blackboard_artifacts.review_status_id) AS review_status_ids, ";
542 }
543 query += " COUNT( blackboard_artifacts.artifact_id) AS hits " //NON-NLS
544 + " FROM blackboard_artifacts " //NON-NLS
545 + " LEFT JOIN blackboard_attributes as solr_attribute ON blackboard_artifacts.artifact_id = solr_attribute.artifact_id " //NON-NLS
547 + " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS
552 + " GROUP BY blackboard_artifacts.obj_id, solr_document_id " //NON-NLS
553 + " ORDER BY hits DESC "; //NON-NLS
556 while (rs.next()) {
558 rs.getLong("obj_id"), //NON-NLS
559 rs.getString("solr_document_id"), //NON-NLS
560 unGroupConcat(rs.getString("artifact_IDs"), Long::valueOf), //NON-NLS
561 rs.getLong("hits"), //NON-NLS
563 }
565 LOGGER.log(Level.SEVERE, "Error querying for files with ccn hits.", ex); //NON-NLS
566
567 }
568 return list;
569 }
570
571 @Override
573 //add all account artifacts for the file and the file itself to the lookup
574 try {
575 List<Object> lookupContents = new ArrayList<>();
578 }
580 lookupContents.add(abstractFileById);
581 return new Node[]{
new FileWithCCNNode(key, abstractFileById, lookupContents.toArray())};
583 LOGGER.log(Level.SEVERE, "Error getting content for file with ccn hits.", ex); //NON-NLS
584 return new Node[0];
585 }
586 }
587 }
588
590 super(Children.LEAF);
591 setChildren(Children.createLazy(FileWithCCNFactory::new));
592 setName("By File"); //NON-NLS
593 updateDisplayName();
594 this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon.png"); //NON-NLS
595 reviewStatusBus.register(this);
596 }
597
598 @NbBundle.Messages({
599 "# {0} - number of children",
600 "Accounts.ByFileNode.displayName=By File ({0})"})
602 String query
603 = "SELECT count(*) FROM ( SELECT count(*) AS documents "
604 + " FROM blackboard_artifacts " //NON-NLS
605 + " LEFT JOIN blackboard_attributes as solr_attribute ON blackboard_artifacts.artifact_id = solr_attribute.artifact_id " //NON-NLS
607 + " LEFT JOIN blackboard_attributes as account_type ON blackboard_artifacts.artifact_id = account_type.artifact_id " //NON-NLS
612 + " GROUP BY blackboard_artifacts.obj_id, solr_attribute.value_text ) AS foo";
615 while (rs.next()) {
617 setDisplayName(Bundle.Accounts_ByFileNode_displayName(rs.getLong("count")));
618 } else {
619 setDisplayName(Bundle.Accounts_ByFileNode_displayName(rs.getLong("count(*)")));
620 }
621 }
623 LOGGER.log(Level.SEVERE, "Error querying for files with ccn hits.", ex); //NON-NLS
624
625 }
626 }
627
628 @Override
630 return true;
631 }
632
633 @Override
635 return v.
visit(
this);
636 }
637
638 @Override
640 return getClass().getName();
641 }
642
643 @Subscribe
645 updateDisplayName();
646 }
647
648 @Subscribe
650 updateDisplayName();
651 }
652 }
653
659
664
665 @Subscribe
666 @Override
668 refreshKeys();
669 }
670
671 @Subscribe
672 @Override
674 refreshKeys();
675 }
676
677 @Override
679 List<BinResult> list = new ArrayList<>();
680
681 RangeMap<Integer, BinResult> binRanges = TreeRangeMap.create();
682
683 String query
684 = "SELECT SUBSTR(blackboard_attributes.value_text,1,8) AS BIN, " //NON-NLS
685 + " COUNT(blackboard_artifacts.artifact_id) AS count " //NON-NLS
686 + " FROM blackboard_artifacts " //NON-NLS
687 + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS
691 + " GROUP BY BIN " //NON-NLS
692 + " ORDER BY BIN "; //NON-NLS
694 ResultSet resultSet = results.getResultSet();
695 //sort all te individual bins in to the ranges
696 while (resultSet.next()) {
697 final Integer bin = Integer.valueOf(resultSet.getString("BIN"));
698 long count = resultSet.getLong("count");
699
701 BinResult previousResult = binRanges.get(bin);
702
703 if (previousResult != null) {
704 binRanges.remove(Range.closed(previousResult.getBINStart(), previousResult.getBINEnd()));
705 count += previousResult.getCount();
706 }
707
708 if (binRange != null) {
710 } else {
711 binRanges.put(Range.closed(bin, bin),
new BinResult(count, bin, bin));
712 }
713 }
714 binRanges.asMapOfRanges().values().forEach(list::add);
716 LOGGER.log(Level.SEVERE, "Error querying for BINs.", ex); //NON-NLS
717
718 }
719 return list;
720 }
721
722 @Override
724 return new Node[]{
new BINNode(key)};
725 }
726 }
727
729 super(Children.LEAF);
730 setChildren(Children.createLazy(BINFactory::new));
731 setName("By BIN"); //NON-NLS
732 updateDisplayName();
733 this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/bank.png"); //NON-NLS
734 reviewStatusBus.register(this);
735 }
736
737 @NbBundle.Messages({
738 "# {0} - number of children",
739 "Accounts.ByBINNode.displayName=By BIN ({0})"})
741 String query
742 = "SELECT count(distinct SUBSTR(blackboard_attributes.value_text,1,8)) AS BINs " //NON-NLS
743 + " FROM blackboard_artifacts " //NON-NLS
744 + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id" //NON-NLS
749 ResultSet resultSet = results.getResultSet();
750 while (resultSet.next()) {
751 setDisplayName(Bundle.Accounts_ByBINNode_displayName(resultSet.getLong("BINs")));
752 }
754 LOGGER.log(Level.SEVERE, "Error querying for BINs.", ex); //NON-NLS
755 }
756 }
757
758 @Override
760 return false;
761 }
762
763 @Override
765 return v.
visit(
this);
766 }
767
768 @Override
770 return getClass().getName();
771 }
772
773 @Subscribe
775 updateDisplayName();
776 }
777
778 @Subscribe
780 updateDisplayName();
781 }
782 }
783
788 @Immutable
790
791 @Override
793 int hash = 5;
794 hash = 79 * hash + (int) (this.objID ^ (this.objID >>> 32));
795 hash = 79 * hash + Objects.hashCode(this.keywordSearchDocID);
796 hash = 79 * hash + Objects.hashCode(this.artifactIDs);
797 hash = 79 * hash + (int) (this.hits ^ (this.hits >>> 32));
798 hash = 79 * hash + Objects.hashCode(this.statuses);
799 return hash;
800 }
801
802 @Override
804 if (this == obj) {
805 return true;
806 }
807 if (obj == null) {
808 return false;
809 }
810 if (getClass() != obj.getClass()) {
811 return false;
812 }
814 if (this.objID != other.
objID) {
815 return false;
816 }
817 if (this.hits != other.
hits) {
818 return false;
819 }
821 return false;
822 }
823 if (!Objects.equals(
this.artifactIDs, other.
artifactIDs)) {
824 return false;
825 }
826 if (!Objects.equals(
this.statuses, other.
statuses)) {
827 return false;
828 }
829 return true;
830 }
831
837
838 private FileWithCCN(
long objID, String solrDocID, List<Long> artifactIDs,
long hits, Set<BlackboardArtifact.ReviewStatus> statuses) {
839 this.objID = objID;
840 this.keywordSearchDocID = solrDocID;
841 this.artifactIDs = artifactIDs;
842 this.hits = hits;
843 this.statuses = statuses;
844 }
845
852 return objID;
853 }
854
862 return keywordSearchDocID;
863 }
864
871 return artifactIDs;
872 }
873
880 return hits;
881 }
882
889 return statuses;
890 }
891 }
892
909 static <X> List<X> unGroupConcat(String groupConcat, Function<String, X> mapper) {
910 return StringUtils.isBlank(groupConcat) ? Collections.emptyList()
911 : Stream.of(groupConcat.split(",")) //NON-NLS
912 .map(mapper::apply)
913 .collect(Collectors.toList());
914 }
915
920
923
933 @NbBundle.Messages({
934 "# {0} - raw file name",
935 "# {1} - solr chunk id",
936 "Accounts.FileWithCCNNode.unallocatedSpaceFile.displayName={0}_chunk_{1}"})
938 super(Children.LEAF, Lookups.fixed(lookupContents));
939 this.fileKey = key;
942 : Bundle.Accounts_FileWithCCNNode_unallocatedSpaceFile_displayName(content.
getName(), StringUtils.substringAfter(key.
getkeywordSearchDocID(),
"_"));
//NON-NLS
944 setDisplayName(fileName);
945 }
946
947 @Override
949 return true;
950 }
951
952 @Override
954 return v.
visit(
this);
955 }
956
957 @Override
959 return getClass().getName();
960 }
961
962 @Override
963 @NbBundle.Messages({
964 "Accounts.FileWithCCNNode.nameProperty.displayName=File",
965 "Accounts.FileWithCCNNode.accountsProperty.displayName=Accounts",
966 "Accounts.FileWithCCNNode.statusProperty.displayName=Status",
967 "Accounts.FileWithCCNNode.noDescription=no description"})
969 Sheet s = super.createSheet();
970 Sheet.Set ss = s.get(Sheet.PROPERTIES);
971 if (ss == null) {
972 ss = Sheet.createPropertiesSet();
973 s.put(ss);
974 }
975
976 ss.put(
new NodeProperty<>(Bundle.Accounts_FileWithCCNNode_nameProperty_displayName(),
977 Bundle.Accounts_FileWithCCNNode_nameProperty_displayName(),
978 Bundle.Accounts_FileWithCCNNode_noDescription(),
979 fileName));
980 ss.put(
new NodeProperty<>(Bundle.Accounts_FileWithCCNNode_accountsProperty_displayName(),
981 Bundle.Accounts_FileWithCCNNode_accountsProperty_displayName(),
982 Bundle.Accounts_FileWithCCNNode_noDescription(),
984 ss.put(
new NodeProperty<>(Bundle.Accounts_FileWithCCNNode_statusProperty_displayName(),
985 Bundle.Accounts_FileWithCCNNode_statusProperty_displayName(),
986 Bundle.Accounts_FileWithCCNNode_noDescription(),
989 .collect(Collectors.joining(", ")))); //NON-NLS
990
991 return s;
992 }
993
994 @Override
996 Action[] actions = super.getActions(context);
997 ArrayList<Action> arrayList = new ArrayList<>();
998 arrayList.addAll(Arrays.asList(actions));
999 try {
1002 LOGGER.log(Level.SEVERE, "Error gettung content by id", ex);
1003 }
1004
1005 arrayList.add(approveActionInstance);
1006 arrayList.add(rejectActionInstance);
1007
1008 return arrayList.toArray(new Action[arrayList.size()]);
1009 }
1010 }
1011
1013
1018
1019 @Subscribe
1020 @Override
1022 refreshKeys();
1023 //make sure to refresh the nodes for artifacts that changed statuses.
1025 }
1026
1027 @Subscribe
1028 @Override
1030 refreshKeys();
1031 }
1032
1033 @Override
1035 List<Long> list = new ArrayList<>();
1036
1037 String query
1038 = "SELECT blackboard_artifacts.artifact_id " //NON-NLS
1039 + " FROM blackboard_artifacts " //NON-NLS
1040 + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
1043 + " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS
1045 + " ORDER BY blackboard_attributes.value_text"; //NON-NLS
1048 while (rs.next()) {
1049 list.add(rs.getLong("artifact_id")); //NON-NLS
1050 }
1052 LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS
1053
1054 }
1055 return list;
1056 }
1057
1058 @Override
1060 if (skCase == null) {
1061 return new Node[0];
1062 }
1063
1064 try {
1068 LOGGER.log(Level.WARNING, "Error creating BlackboardArtifactNode for artifact with ID " + artifactID, ex); //NON-NLS
1069 return new Node[0];
1070 }
1071 }
1072 }
1074
1076 super(Children.LEAF);
1077 this.bin = bin;
1078 setChildren(Children.createLazy(CreditCardNumberFactory::new));
1079 setName(getBinRangeString());
1080 updateDisplayName();
1081 this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/bank.png"); //NON-NLS
1082 reviewStatusBus.register(this);
1083 }
1084
1085 @Subscribe
1087 updateDisplayName();
1088 }
1089
1090 @Subscribe
1092 updateDisplayName();
1093 }
1094
1096 String query
1097 = "SELECT count(blackboard_artifacts.artifact_id ) AS count" //NON-NLS
1098 + " FROM blackboard_artifacts " //NON-NLS
1099 + " JOIN blackboard_attributes ON blackboard_artifacts.artifact_id = blackboard_attributes.artifact_id " //NON-NLS
1102 + " AND blackboard_attributes.value_text >= '" + bin.getBINStart() + "' AND blackboard_attributes.value_text < '" + (bin.getBINEnd() + 1) + "'" //NON-NLS
1106 while (rs.next()) {
1107 setDisplayName(getBinRangeString() + " (" + rs.getLong("count") + ")"); //NON-NLS
1108 }
1110 LOGGER.log(Level.SEVERE, "Error querying for account artifacts.", ex); //NON-NLS
1111
1112 }
1113
1114 }
1115
1117 if (bin.getBINStart() == bin.getBINEnd()) {
1118 return Integer.toString(bin.getBINStart());
1119 } else {
1120 return bin.getBINStart() + "-" + StringUtils.difference(bin.getBINStart() + "", bin.getBINEnd() + "");
1121 }
1122 }
1123
1124 @Override
1126 return true;
1127 }
1128
1129 @Override
1131 return v.
visit(
this);
1132 }
1133
1134 @Override
1136 return getClass().getName();
1137 }
1138
1140 Sheet.Set ss = s.get(Sheet.PROPERTIES);
1141 if (ss == null) {
1142 ss = Sheet.createPropertiesSet();
1143 s.put(ss);
1144 }
1145 return ss;
1146 }
1147
1148 @Override
1149 @NbBundle.Messages({
1150 "Accounts.BINNode.binProperty.displayName=Bank Identifier Number",
1151 "Accounts.BINNode.accountsProperty.displayName=Accounts",
1152 "Accounts.BINNode.cardTypeProperty.displayName=Payment Card Type",
1153 "Accounts.BINNode.schemeProperty.displayName=Credit Card Scheme",
1154 "Accounts.BINNode.brandProperty.displayName=Brand",
1155 "Accounts.BINNode.bankProperty.displayName=Bank",
1156 "Accounts.BINNode.bankCityProperty.displayName=Bank City",
1157 "Accounts.BINNode.bankCountryProperty.displayName=Bank Country",
1158 "Accounts.BINNode.bankPhoneProperty.displayName=Bank Phone #",
1159 "Accounts.BINNode.bankURLProperty.displayName=Bank URL",
1160 "Accounts.BINNode.noDescription=no description"})
1162 Sheet sheet = super.createSheet();
1163 Sheet.Set properties = getPropertySet(sheet);
1164
1165 properties.put(
new NodeProperty<>(Bundle.Accounts_BINNode_binProperty_displayName(),
1166 Bundle.Accounts_BINNode_binProperty_displayName(),
1167 Bundle.Accounts_BINNode_noDescription(),
1168 getBinRangeString()));
1169 properties.put(
new NodeProperty<>(Bundle.Accounts_BINNode_accountsProperty_displayName(),
1170 Bundle.Accounts_BINNode_accountsProperty_displayName(), Bundle.Accounts_BINNode_noDescription(),
1171 bin.getCount()));
1172
1173 //add optional properties if they are available
1174 if (bin.hasDetails()) {
1175 bin.
getCardType().ifPresent(cardType -> properties.put(
new NodeProperty<>(Bundle.Accounts_BINNode_cardTypeProperty_displayName(),
1176 Bundle.Accounts_BINNode_cardTypeProperty_displayName(), Bundle.Accounts_BINNode_noDescription(),
1177 cardType)));
1178 bin.
getScheme().ifPresent(scheme -> properties.put(
new NodeProperty<>(Bundle.Accounts_BINNode_schemeProperty_displayName(),
1179 Bundle.Accounts_BINNode_schemeProperty_displayName(), Bundle.Accounts_BINNode_noDescription(),
1180 scheme)));
1181 bin.
getBrand().ifPresent(brand -> properties.put(
new NodeProperty<>(Bundle.Accounts_BINNode_brandProperty_displayName(),
1182 Bundle.Accounts_BINNode_brandProperty_displayName(), Bundle.Accounts_BINNode_noDescription(),
1183 brand)));
1184 bin.
getBankName().ifPresent(bankName -> properties.put(
new NodeProperty<>(Bundle.Accounts_BINNode_bankProperty_displayName(),
1185 Bundle.Accounts_BINNode_bankProperty_displayName(), Bundle.Accounts_BINNode_noDescription(),
1186 bankName)));
1187 bin.
getBankCity().ifPresent(bankCity -> properties.put(
new NodeProperty<>(Bundle.Accounts_BINNode_bankCityProperty_displayName(),
1188 Bundle.Accounts_BINNode_bankCityProperty_displayName(), Bundle.Accounts_BINNode_noDescription(),
1189 bankCity)));
1190 bin.
getCountry().ifPresent(country -> properties.put(
new NodeProperty<>(Bundle.Accounts_BINNode_bankCountryProperty_displayName(),
1191 Bundle.Accounts_BINNode_bankCountryProperty_displayName(), Bundle.Accounts_BINNode_noDescription(),
1192 country)));
1194 Bundle.Accounts_BINNode_bankPhoneProperty_displayName(), Bundle.Accounts_BINNode_noDescription(),
1195 phoneNumber)));
1196 bin.
getBankURL().ifPresent(url -> properties.put(
new NodeProperty<>(Bundle.Accounts_BINNode_bankURLProperty_displayName(),
1197 Bundle.Accounts_BINNode_bankURLProperty_displayName(), Bundle.Accounts_BINNode_noDescription(),
1198 url)));
1199 }
1200 return sheet;
1201 }
1202 }
1203
1208 @Immutable
1210
1211 @Override
1213 int hash = 3;
1214 hash = 97 * hash + this.binEnd;
1215 hash = 97 * hash + this.binStart;
1216 return hash;
1217 }
1218
1219 @Override
1221 if (this == obj) {
1222 return true;
1223 }
1224 if (obj == null) {
1225 return false;
1226 }
1227 if (getClass() != obj.getClass()) {
1228 return false;
1229 }
1231 if (this.binEnd != other.
binEnd) {
1232 return false;
1233 }
1234 if (this.binStart != other.
binStart) {
1235 return false;
1236 }
1237 return true;
1238 }
1239
1244
1248
1250 this.count = count;
1251 this.binRange = binRange;
1252 binStart = binRange.getBINstart();
1253 binEnd = binRange.getBINend();
1254 }
1255
1257 this.count = count;
1258 this.binRange = null;
1259 binStart = start;
1260 binEnd = end;
1261 }
1262
1263 int getBINStart() {
1264 return binStart;
1265 }
1266
1267 int getBINEnd() {
1268 return binEnd;
1269 }
1270
1271 long getCount() {
1272 return count;
1273 }
1274
1275 boolean hasDetails() {
1276 return binRange != null;
1277 }
1278
1279 @Override
1282 }
1283
1284 @Override
1287 }
1288
1289 @Override
1292 }
1293
1294 @Override
1297 }
1298
1299 @Override
1302 }
1303
1304 @Override
1307 }
1308
1309 @Override
1312 }
1313
1314 @Override
1317 }
1318
1319 @Override
1322 }
1323 }
1324
1326
1328
1330 super(artifact, "org/sleuthkit/autopsy/images/credit-card.png"); //NON-NLS
1331 this.artifact = artifact;
1333 }
1334
1335 @Override
1337 List<Action> actionsList = new ArrayList<>();
1338 actionsList.addAll(Arrays.asList(super.getActions(context)));
1339
1340 actionsList.add(approveActionInstance);
1341 actionsList.add(rejectActionInstance);
1342
1343 return actionsList.toArray(new Action[actionsList.size()]);
1344 }
1345
1346 @Override
1348 Sheet sheet = super.createSheet();
1349 Sheet.Set properties = sheet.get(Sheet.PROPERTIES);
1350 if (properties == null) {
1351 properties = Sheet.createPropertiesSet();
1352 sheet.put(properties);
1353 }
1354 properties.put(
new NodeProperty<>(Bundle.Accounts_FileWithCCNNode_statusProperty_displayName(),
1355 Bundle.Accounts_FileWithCCNNode_statusProperty_displayName(),
1356 Bundle.Accounts_FileWithCCNNode_noDescription(),
1358
1359 return sheet;
1360 }
1361 }
1362
1364
1365 @NbBundle.Messages("ToggleShowRejected.name=Show Rejected Results")
1367 super(Bundle.ToggleShowRejected_name());
1368 }
1369
1370 @Override
1374 }
1375 }
1376
1378
1380
1382 super(displayName);
1383 this.newStatus = newStatus;
1384
1385 }
1386
1387 @Override
1389
1390 /* get paths for selected nodes to reselect after applying review
1391 * status change */
1392 List<String[]> selectedPaths = Utilities.actionsGlobalContext().lookupAll(Node.class).stream()
1393 .map(node -> {
1394 String[] createPath;
1395 /*
1396 * If the we are rejecting and not showing rejected
1397 * results, then the selected node, won't exist any
1398 * more, so we select the previous one in stead.
1399 */
1401 List<Node> siblings = Arrays.asList(node.getParentNode().getChildren().getNodes());
1402 if (siblings.size() > 1) {
1403 int indexOf = siblings.indexOf(node);
1404 //there is no previous for the first node, so instead we select the next one
1405 Node sibling = indexOf > 0
1406 ? siblings.get(indexOf - 1)
1407 : siblings.get(Integer.max(indexOf + 1, siblings.size() - 1));
1408 createPath = NodeOp.createPath(sibling, null);
1409 } else {
1410 /* if there are no other siblings to select,
1411 * just return null, but note we need to filter
1412 * this out of stream below */
1413 return null;
1414 }
1415 } else {
1416 createPath = NodeOp.createPath(node, null);
1417 }
1418 //for the reselect to work we need to strip off the first part of the path.
1419 return Arrays.copyOfRange(createPath, 1, createPath.length);
1420 })
1421 .filter(Objects::nonNull)
1422 .collect(Collectors.toList());
1423
1424 //change status of selected artifacts
1425 final Collection<? extends BlackboardArtifact> artifacts = Utilities.actionsGlobalContext().lookupAll(
BlackboardArtifact.class);
1426 artifacts.forEach(artifact -> {
1427 try {
1430 LOGGER.log(Level.SEVERE, "Error changing artifact review status.", ex); //NON-NLS
1431 }
1432 });
1433 //post event
1434 reviewStatusBus.post(new ReviewStatusChangeEvent(artifacts, newStatus));
1435
1436 final DataResultTopComponent directoryListing = DirectoryTreeTopComponent.findInstance().getDirectoryListing();
1437 final Node rootNode = directoryListing.getRootNode();
1438
1439 //convert paths back to nodes
1440 List<Node> toArray = new ArrayList<>();
1441 selectedPaths.forEach(path -> {
1442 try {
1443 toArray.add(NodeOp.findPath(rootNode, path));
1444 } catch (NodeNotFoundException ex) {
1445 //just ingnore paths taht don't exist. this is expected since we are rejecting
1446 }
1447 });
1448 //select nodes
1449 directoryListing.setSelectedNodes(toArray.toArray(new Node[toArray.size()]));
1450 }
1451 }
1452
1454
1455 @NbBundle.Messages({"ApproveAccountsAction.name=Approve Accounts"})
1458 }
1459 }
1460
1462
1463 @NbBundle.Messages({"RejectAccountsAction.name=Reject Accounts"})
1466 }
1467 }
1468
1470
1471 Collection<? extends BlackboardArtifact> artifacts;
1473
1475 this.artifacts = artifacts;
1476 this.newReviewStatus = newReviewStatus;
1477 }
1478 }
1479 }
List< CreditCardViewMode > createKeys()
final BlackboardArtifact.ReviewStatus newStatus
BlackboardArtifact.Type getBlackboardArtifactType()
void removeIngestModuleEventListener(final PropertyChangeListener listener)
Optional< Integer > getNumberLength()
Optional< String > getCountry()
Node[] createNodes(FileWithCCN key)
final BlackboardArtifact artifact
abstract Collection< X > createKeys()
static synchronized IngestManager getInstance()
List< Long > createKeys()
static final Logger LOGGER
Optional< String > getBankPhoneNumber()
Set< BlackboardArtifact.ReviewStatus > getStatuses()
Optional< String > getCountry()
Optional< String > getBankCity()
final String keywordSearchDocID
static List< Action > getActions(File file, boolean isArtifactSource)
Optional< String > getBankName()
static void removePropertyChangeListener(PropertyChangeListener listener)
final EventBus reviewStatusBus
String getRejectedArtifactFilterClause()
final String accountTypeName
Sheet.Set getPropertySet(Sheet s)
final RejectAccounts rejectActionInstance
List< Long > getArtifactIDs()
Content getContentById(long id)
AccountArtifactNode(BlackboardArtifact artifact)
static synchronized BankIdentificationNumber getBINInfo(int bin)
TSK_KEYWORD_SEARCH_DOCUMENT_ID
Action[] getActions(boolean context)
ReviewStatus getReviewStatus()
Optional< String > getBankURL()
Node[] createNodes(BinResult key)
final ApproveAccounts approveActionInstance
BlackboardArtifact getBlackboardArtifact(long artifactID)
T visit(DataSourcesNode in)
AbstractFile getAbstractFileById(long id)
List< BinResult > createKeys()
void removeIngestJobEventListener(final PropertyChangeListener listener)
Optional< String > getScheme()
Node[] createNodes(String key)
final Set< BlackboardArtifact.ReviewStatus > statuses
Optional< String > getBrand()
Collection< Long > createKeys()
Node[] createNodes(Long t)
boolean equals(Object obj)
CreditCardNumberAccountTypeNode()
void addIngestJobEventListener(final PropertyChangeListener listener)
Optional< String > getBankURL()
String getkeywordSearchDocID()
ReviewStatusChangeEvent(Collection<?extends BlackboardArtifact > artifacts, BlackboardArtifact.ReviewStatus newReviewStatus)
Optional< Integer > getNumberLength()
BinResult(long count,@Nonnull BINRange binRange)
Action newToggleShowRejectedAction()
Optional< String > getBrand()
String getBinRangeString()
static void addPropertyChangeListener(PropertyChangeListener listener)
FileWithCCNNode(FileWithCCN key, Content content, Object[] lookupContents)
Action[] getActions(boolean context)
final List< Long > artifactIDs
DefaultAccountTypeNode(String accountTypeName)
Node[] createNodes(Long artifactID)
FileWithCCN(long objID, String solrDocID, List< Long > artifactIDs, long hits, Set< BlackboardArtifact.ReviewStatus > statuses)
List< FileWithCCN > createKeys()
void actionPerformed(ActionEvent e)
Optional< String > getBankCity()
Node[] createNodes(CreditCardViewMode key)
Optional< String > getCardType()
final FileWithCCN fileKey
BinResult(long count, int start, int end)
void addIngestModuleEventListener(final PropertyChangeListener listener)
static Case getCurrentCase()
List< String > createKeys()
boolean equals(Object obj)
ReviewStatusAction(String displayName, BlackboardArtifact.ReviewStatus newStatus)
void actionPerformed(ActionEvent e)
static ReviewStatus withID(int id)
Optional< String > getScheme()
Optional< String > getBankName()
Optional< String > getBankPhoneNumber()
CaseDbQuery executeQuery(String query)
void setReviewStatus(BlackboardArtifact artifact, BlackboardArtifact.ReviewStatus newStatus)
Optional< String > getCardType()
Accounts(SleuthkitCase skCase)