/** * Check file extension and return appropriate input options for SevenZip.openInArchive() * * @param archiveFile file to check file extension * @return input parameter for SevenZip.openInArchive() */ private ArchiveFormat get7ZipOptions(AbstractFile archiveFile) { // try to get the file type from the BB String detectedFormat = null; try { ArrayList<BlackboardAttribute> attributes = archiveFile.getGenInfoAttributes(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG); for (BlackboardAttribute attribute : attributes) { detectedFormat = attribute.getValueString(); break; } } catch (TskCoreException ex) { logger.log( Level.WARNING, "Couldn't obtain file attributes for file: " + archiveFile.toString(), ex); // NON-NLS } if (detectedFormat == null) { logger.log(Level.WARNING, "Could not detect format for file: " + archiveFile); // NON-NLS // if we don't have attribute info then use file extension String extension = archiveFile.getNameExtension(); if ("rar".equals(extension)) // NON-NLS { // for RAR files we need to open them explicitly as RAR. Otherwise, if there is a ZIP // archive inside RAR archive // it will be opened incorrectly when using 7zip's built-in auto-detect functionality return RAR; } // Otherwise open the archive using 7zip's built-in auto-detect functionality return null; } else if (detectedFormat.contains("application/x-rar-compressed")) // NON-NLS { // for RAR files we need to open them explicitly as RAR. Otherwise, if there is a ZIP archive // inside RAR archive // it will be opened incorrectly when using 7zip's built-in auto-detect functionality return RAR; } // Otherwise open the archive using 7zip's built-in auto-detect functionality return null; }
private void initData() { try { // Get all file and artifact tags // init data tags = new EnumMap<BlackboardArtifact.ARTIFACT_TYPE, Map<String, List<BlackboardArtifact>>>( BlackboardArtifact.ARTIFACT_TYPE.class); tags.put( BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE, new HashMap<String, List<BlackboardArtifact>>()); tags.put( BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT, new HashMap<String, List<BlackboardArtifact>>()); // populate for (BlackboardArtifact.ARTIFACT_TYPE artType : tags.keySet()) { final Map<String, List<BlackboardArtifact>> artTags = tags.get(artType); for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(artType)) { for (BlackboardAttribute attribute : artifact.getAttributes()) { if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) { String tagName = attribute.getValueString(); if (artTags.containsKey(tagName)) { List<BlackboardArtifact> artifacts = artTags.get(tagName); artifacts.add(artifact); } else { List<BlackboardArtifact> artifacts = new ArrayList<BlackboardArtifact>(); artifacts.add(artifact); artTags.put(tagName, artifacts); } break; } } } } } catch (TskCoreException ex) { logger.log(Level.WARNING, "Count not initialize tag nodes, ", ex); } }
/** * Get the tag comment for a specified tag. * * @param tagArtifactId artifact id of the tag * @return the tag comment */ static String getCommentFromTag(long tagArtifactId) { try { Case currentCase = Case.getCurrentCase(); SleuthkitCase skCase = currentCase.getSleuthkitCase(); BlackboardArtifact artifact = skCase.getBlackboardArtifact(tagArtifactId); if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() || artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { List<BlackboardAttribute> attributes = artifact.getAttributes(); for (BlackboardAttribute att : attributes) { if (att.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID()) { return att.getValueString(); } } } } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Failed to get artifact " + tagArtifactId + " from case."); } return EMPTY_COMMENT; }
/** * Can a thumbnail be generated for the content? * * @param content * @return */ public static boolean thumbnailSupported(Content content) { if (content instanceof AbstractFile == false) { return false; } AbstractFile f = (AbstractFile) content; if (f.getSize() == 0) { return false; } // check the blackboard for a file type attribute try { ArrayList<BlackboardAttribute> attributes = f.getGenInfoAttributes(ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG); for (BlackboardAttribute attribute : attributes) { if (SUPP_MIME_TYPES.contains(attribute.getValueString())) { return true; } } } catch (TskCoreException ex) { logger.log( Level.WARNING, "Error while getting file signature from blackboard.", ex); // NON-NLS } final String extension = f.getNameExtension(); // if we have an extension, check it if (extension.equals("") == false) { // Note: thumbnail generator only supports JPG, GIF, and PNG for now if (SUPP_EXTENSIONS.contains(extension)) { return true; } } // if no extension or one that is not for an image, then read the content return isJpegFileHeader(f); }
/** * Looks up the tag names associated with either a tagged artifact or a tag artifact. * * @param artifactID The ID of the artifact * @param artifactTypeID The ID of the artifact type * @return A set of unique tag names */ public static HashSet<String> getUniqueTagNames(long artifactID, int artifactTypeID) { HashSet<String> tagNames = new HashSet<>(); try { ArrayList<Long> tagArtifactIDs = new ArrayList<>(); if (artifactTypeID == ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() || artifactTypeID == ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { tagArtifactIDs.add(artifactID); } else { List<BlackboardArtifact> tags = Case.getCurrentCase() .getSleuthkitCase() .getBlackboardArtifacts(ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT, artifactID); for (BlackboardArtifact tag : tags) { tagArtifactIDs.add(tag.getArtifactID()); } } for (Long tagArtifactID : tagArtifactIDs) { String whereClause = "WHERE artifact_id = " + tagArtifactID + " AND attribute_type_id = " + ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID(); List<BlackboardAttribute> attributes = Case.getCurrentCase().getSleuthkitCase().getMatchingAttributes(whereClause); for (BlackboardAttribute attr : attributes) { tagNames.add(attr.getValueString()); } } } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Failed to get tags for artifact " + artifactID, ex); } return tagNames; }
@Override public void viewArtifact(final BlackboardArtifact art) { BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(art.getArtifactTypeID()); Children rootChilds = em.getRootContext().getChildren(); Node treeNode = null; Node resultsNode = rootChilds.findChild(ResultsNode.NAME); Children resultsChilds = resultsNode.getChildren(); if (type.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT)) { Node hashsetRootNode = resultsChilds.findChild(type.getLabel()); Children hashsetRootChilds = hashsetRootNode.getChildren(); try { String setName = null; List<BlackboardAttribute> attributes = art.getAttributes(); for (BlackboardAttribute att : attributes) { int typeId = att.getAttributeTypeID(); if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { setName = att.getValueString(); } } treeNode = hashsetRootChilds.findChild(setName); } catch (TskException ex) { logger.log(Level.WARNING, "Error retrieving attributes", ex); // NON-NLS } } else if (type.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT)) { Node keywordRootNode = resultsChilds.findChild(type.getLabel()); Children keywordRootChilds = keywordRootNode.getChildren(); try { String listName = null; String keywordName = null; List<BlackboardAttribute> attributes = art.getAttributes(); for (BlackboardAttribute att : attributes) { int typeId = att.getAttributeTypeID(); if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { listName = att.getValueString(); } else if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) { keywordName = att.getValueString(); } } Node listNode = keywordRootChilds.findChild(listName); Children listChildren = listNode.getChildren(); treeNode = listChildren.findChild(keywordName); } catch (TskException ex) { logger.log(Level.WARNING, "Error retrieving attributes", ex); // NON-NLS } } else if (type.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT) || type.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT)) { Node interestingItemsRootNode = resultsChilds.findChild(type.getLabel()); Children interestingItemsRootChildren = interestingItemsRootNode.getChildren(); try { String setName = null; List<BlackboardAttribute> attributes = art.getAttributes(); for (BlackboardAttribute att : attributes) { int typeId = att.getAttributeTypeID(); if (typeId == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) { setName = att.getValueString(); } } treeNode = interestingItemsRootChildren.findChild(setName); } catch (TskException ex) { logger.log(Level.WARNING, "Error retrieving attributes", ex); // NON-NLS } } else { Node extractedContent = resultsChilds.findChild(ExtractedContent.NAME); Children extractedChilds = extractedContent.getChildren(); treeNode = extractedChilds.findChild(type.getLabel()); } try { em.setExploredContextAndSelection(treeNode, new Node[] {treeNode}); } catch (PropertyVetoException ex) { logger.log(Level.WARNING, "Property Veto: ", ex); // NON-NLS } // Another thread is needed because we have to wait for dataResult to populate EventQueue.invokeLater( new Runnable() { @Override public void run() { Children resultChilds = dataResult.getRootNode().getChildren(); Node select = resultChilds.findChild(Long.toString(art.getArtifactID())); if (select != null) { dataResult.requestActive(); dataResult.setSelectedNodes(new Node[] {select}); fireViewerComplete(); } } }); }
@Override public synchronized ObservableResult evaluate() { setWarnings(""); if (obj.getAddressValue() == null) { return new ObservableResult( id, "AddressObject: No address value field found", // NON-NLS spacing, ObservableResult.ObservableState.INDETERMINATE, null); } String origAddressStr = obj.getAddressValue().getValue().toString(); // For now, we don't support "NONE" because it honestly doesn't seem like it // would ever appear in practice. if (((obj.getAddressValue().getApplyCondition() != null) && (obj.getAddressValue().getApplyCondition() == ConditionApplicationEnum.NONE))) { return new ObservableResult( id, "AddressObject: Can not process apply condition " + obj.getAddressValue().getApplyCondition().toString() // NON-NLS + " on Address object", spacing, ObservableResult.ObservableState.INDETERMINATE, null); // NON-NLS } // Set warnings for any unsupported fields setUnsupportedFieldWarnings(); Case case1 = Case.getCurrentCase(); SleuthkitCase sleuthkitCase = case1.getSleuthkitCase(); try { // Need to check that every part of the string had at least one match // in the AND case boolean everyPartMatched = true; List<BlackboardArtifact> combinedArts = new ArrayList<BlackboardArtifact>(); String searchString = ""; String[] parts = origAddressStr.split("##comma##"); // NON-NLS for (String addressStr : parts) { // Update the string to show in the results if (!searchString.isEmpty()) { if ((obj.getAddressValue().getApplyCondition() != null) && (obj.getAddressValue().getApplyCondition() == ConditionApplicationEnum.ALL)) { searchString += " AND "; // NON-NLS } else { searchString += " OR "; // NON-NLS } } searchString += addressStr; if ((obj.getAddressValue().getCondition() == null) || (obj.getAddressValue().getCondition() == ConditionTypeEnum.EQUALS)) { List<BlackboardArtifact> arts = sleuthkitCase.getBlackboardArtifacts( BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, addressStr); if (arts.isEmpty()) { everyPartMatched = false; } else { combinedArts.addAll(arts); } } else { // This is inefficient, but the easiest way to do it. List<BlackboardArtifact> finalHits = new ArrayList<BlackboardArtifact>(); // Get all the URL artifacts List<BlackboardArtifact> artList = sleuthkitCase.getBlackboardArtifacts( BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT); for (BlackboardArtifact art : artList) { for (BlackboardAttribute attr : art.getAttributes()) { if (attr.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) { if (compareStringObject( addressStr, obj.getAddressValue().getCondition(), obj.getAddressValue().getApplyCondition(), attr.getValueString())) { finalHits.add(art); } } } } if (finalHits.isEmpty()) { everyPartMatched = false; } else { combinedArts.addAll(finalHits); } } } // If we're in the ALL case, make sure every piece matched if ((obj.getAddressValue().getApplyCondition() != null) && (obj.getAddressValue().getApplyCondition() == ConditionApplicationEnum.ALL) && (!everyPartMatched)) { return new ObservableResult( id, "AddressObject: No matches for " + searchString, // NON-NLS spacing, ObservableResult.ObservableState.FALSE, null); } if (!combinedArts.isEmpty()) { List<StixArtifactData> artData = new ArrayList<StixArtifactData>(); for (BlackboardArtifact a : combinedArts) { artData.add(new StixArtifactData(a.getObjectID(), id, "AddressObject")); // NON-NLS } return new ObservableResult( id, "AddressObject: Found a match for " + searchString, // NON-NLS spacing, ObservableResult.ObservableState.TRUE, artData); } return new ObservableResult( id, "AddressObject: Found no matches for " + searchString, // NON-NLS spacing, ObservableResult.ObservableState.FALSE, null); } catch (TskCoreException ex) { return new ObservableResult( id, "AddressObject: Exception during evaluation: " + ex.getLocalizedMessage(), // NON-NLS spacing, ObservableResult.ObservableState.INDETERMINATE, null); } }
@Override protected Object doInBackground() throws Exception { logger.log(Level.INFO, "Pending start of new searcher"); final String displayName = "Keyword Search" + (finalRun ? " - Finalizing" : ""); progress = ProgressHandleFactory.createHandle( displayName + (" (Pending)"), new Cancellable() { @Override public boolean cancel() { logger.log(Level.INFO, "Cancelling the searcher by user."); if (progress != null) { progress.setDisplayName(displayName + " (Cancelling...)"); } return Searcher.this.cancel(true); } }); progress.start(); progress.switchToIndeterminate(); // block to ensure previous searcher is completely done with doInBackground() // even after previous searcher cancellation, we need to check this searcherLock.lock(); try { logger.log(Level.INFO, "Started a new searcher"); progress.setDisplayName(displayName); // make sure other searchers are not spawned searcherDone = false; runSearcher = false; if (searchTimer.isRunning()) { searchTimer.stop(); } int numSearched = 0; updateKeywords(); progress.switchToDeterminate(keywords.size()); for (Keyword keywordQuery : keywords) { if (this.isCancelled()) { logger.log( Level.INFO, "Cancel detected, bailing before new keyword processed: " + keywordQuery.getQuery()); return null; } final String queryStr = keywordQuery.getQuery(); final KeywordSearchList list = keywordToList.get(queryStr); final String listName = list.getName(); // DEBUG // logger.log(Level.INFO, "Searching: " + queryStr); progress.progress(queryStr, numSearched); KeywordSearchQuery del = null; boolean isRegex = !keywordQuery.isLiteral(); if (!isRegex) { del = new LuceneQuery(keywordQuery); del.escape(); } else { del = new TermComponentQuery(keywordQuery); } Map<String, List<ContentHit>> queryResult = null; try { queryResult = del.performQuery(); } catch (NoOpenCoreException ex) { logger.log(Level.WARNING, "Error performing query: " + keywordQuery.getQuery(), ex); // no reason to continue with next query if recovery failed // or wait for recovery to kick in and run again later // likely case has closed and threads are being interrupted return null; } catch (CancellationException e) { logger.log( Level.INFO, "Cancel detected, bailing during keyword query: " + keywordQuery.getQuery()); return null; } catch (Exception e) { logger.log(Level.WARNING, "Error performing query: " + keywordQuery.getQuery(), e); continue; } // calculate new results but substracting results already obtained in this run Map<Keyword, List<ContentHit>> newResults = new HashMap<Keyword, List<ContentHit>>(); for (String termResult : queryResult.keySet()) { List<ContentHit> queryTermResults = queryResult.get(termResult); Keyword termResultK = new Keyword(termResult, !isRegex); List<ContentHit> curTermResults = currentResults.get(termResultK); if (curTermResults == null) { currentResults.put(termResultK, queryTermResults); newResults.put(termResultK, queryTermResults); } else { // some AbstractFile hits already exist for this keyword for (ContentHit res : queryTermResults) { if (!previouslyHit(curTermResults, res)) { // add to new results List<ContentHit> newResultsFs = newResults.get(termResultK); if (newResultsFs == null) { newResultsFs = new ArrayList<ContentHit>(); newResults.put(termResultK, newResultsFs); } newResultsFs.add(res); curTermResults.add(res); } } } } if (!newResults.isEmpty()) { // write results to BB // new artifacts created, to report to listeners Collection<BlackboardArtifact> newArtifacts = new ArrayList<BlackboardArtifact>(); for (final Keyword hitTerm : newResults.keySet()) { List<ContentHit> contentHitsAll = newResults.get(hitTerm); Map<AbstractFile, Integer> contentHitsFlattened = ContentHit.flattenResults(contentHitsAll); for (final AbstractFile hitFile : contentHitsFlattened.keySet()) { String snippet = null; final String snippetQuery = KeywordSearchUtil.escapeLuceneQuery(hitTerm.getQuery(), true, false); int chunkId = contentHitsFlattened.get(hitFile); try { snippet = LuceneQuery.querySnippet( snippetQuery, hitFile.getId(), chunkId, isRegex, true); } catch (NoOpenCoreException e) { logger.log(Level.WARNING, "Error querying snippet: " + snippetQuery, e); // no reason to continue return null; } catch (Exception e) { logger.log(Level.WARNING, "Error querying snippet: " + snippetQuery, e); continue; } KeywordWriteResult written = del.writeToBlackBoard(hitTerm.getQuery(), hitFile, snippet, listName); if (written == null) { logger.log( Level.WARNING, "BB artifact for keyword hit not written, file: " + hitFile + ", hit: " + hitTerm.toString()); continue; } newArtifacts.add(written.getArtifact()); // generate a data message for each artifact StringBuilder subjectSb = new StringBuilder(); StringBuilder detailsSb = new StringBuilder(); // final int hitFiles = newResults.size(); if (!keywordQuery.isLiteral()) { subjectSb.append("RegExp hit: "); } else { subjectSb.append("Keyword hit: "); } // subjectSb.append("<"); String uniqueKey = null; BlackboardAttribute attr = written.getAttribute( BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()); if (attr != null) { final String keyword = attr.getValueString(); subjectSb.append(keyword); uniqueKey = keyword.toLowerCase(); } // subjectSb.append(">"); // String uniqueKey = queryStr; // details detailsSb.append("<table border='0' cellpadding='4' width='280'>"); // hit detailsSb.append("<tr>"); detailsSb.append("<th>Keyword hit</th>"); detailsSb .append("<td>") .append(StringEscapeUtils.escapeHtml(attr.getValueString())) .append("</td>"); detailsSb.append("</tr>"); // preview attr = written.getAttribute( BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW.getTypeID()); if (attr != null) { detailsSb.append("<tr>"); detailsSb.append("<th>Preview</th>"); detailsSb .append("<td>") .append(StringEscapeUtils.escapeHtml(attr.getValueString())) .append("</td>"); detailsSb.append("</tr>"); } // file detailsSb.append("<tr>"); detailsSb.append("<th>File</th>"); if (hitFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) { detailsSb .append("<td>") .append(((FsContent) hitFile).getParentPath()) .append(hitFile.getName()) .append("</td>"); } else { detailsSb.append("<td>").append(hitFile.getName()).append("</td>"); } detailsSb.append("</tr>"); // list attr = written.getAttribute( BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()); detailsSb.append("<tr>"); detailsSb.append("<th>List</th>"); detailsSb.append("<td>").append(attr.getValueString()).append("</td>"); detailsSb.append("</tr>"); // regex if (!keywordQuery.isLiteral()) { attr = written.getAttribute( BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()); if (attr != null) { detailsSb.append("<tr>"); detailsSb.append("<th>RegEx</th>"); detailsSb.append("<td>").append(attr.getValueString()).append("</td>"); detailsSb.append("</tr>"); } } detailsSb.append("</table>"); // check if should send messages on hits on this list if (list.getIngestMessages()) // post ingest inbox msg { managerProxy.postMessage( IngestMessage.createDataMessage( ++messageID, instance, subjectSb.toString(), detailsSb.toString(), uniqueKey, written.getArtifact())); } } // for each term hit } // for each file hit // update artifact browser if (!newArtifacts.isEmpty()) { IngestManager.fireServiceDataEvent( new ServiceDataEvent(MODULE_NAME, ARTIFACT_TYPE.TSK_KEYWORD_HIT, newArtifacts)); } } progress.progress(queryStr, ++numSearched); } } // end try block catch (Exception ex) { logger.log(Level.WARNING, "searcher exception occurred", ex); } finally { finalizeSearcher(); searcherLock.unlock(); } return null; }
@Override public KeywordCachedArtifact writeSingleFileHitsToBlackBoard( String termHit, KeywordHit hit, String snippet, String listName) { BlackboardArtifact newArtifact; Collection<BlackboardAttribute> attributes = new ArrayList<>(); if (keyword.getType() == ATTRIBUTE_TYPE.TSK_CARD_NUMBER) { attributes.add( new BlackboardAttribute( ATTRIBUTE_TYPE.TSK_ACCOUNT_TYPE, MODULE_NAME, Account.Type.CREDIT_CARD.name())); Map<BlackboardAttribute.Type, BlackboardAttribute> parsedTrackAttributeMap = new HashMap<>(); // try to match it against the track 1 regex Matcher matcher = TRACK1_PATTERN.matcher(hit.getSnippet()); if (matcher.find()) { parseTrack1Data(parsedTrackAttributeMap, matcher); } // then try to match it against the track 2 regex matcher = TRACK2_PATTERN.matcher(hit.getSnippet()); if (matcher.find()) { parseTrack2Data(parsedTrackAttributeMap, matcher); } // if we couldn't parse the CCN abort this artifact final BlackboardAttribute ccnAttribute = parsedTrackAttributeMap.get(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_CARD_NUMBER)); if (ccnAttribute == null || StringUtils.isBlank(ccnAttribute.getValueString())) { if (hit.isArtifactHit()) { LOGGER.log( Level.SEVERE, String.format( "Failed to parse credit card account number for artifact keyword hit: term = %s, snippet = '%s', artifact id = %d", termHit, hit.getSnippet(), hit.getArtifact().getArtifactID())); } else { LOGGER.log( Level.SEVERE, String.format( "Failed to parse credit card account number for content keyword hit: term = %s, snippet = '%s', object id = %d", termHit, hit.getSnippet(), hit.getContent().getId())); } return null; } attributes.addAll(parsedTrackAttributeMap.values()); // look up the bank name, schem, etc from the BIN final int bin = Integer.parseInt(ccnAttribute.getValueString().substring(0, 8)); CreditCards.BankIdentificationNumber binInfo = CreditCards.getBINInfo(bin); if (binInfo != null) { binInfo .getScheme() .ifPresent( scheme -> attributes.add( new BlackboardAttribute( ATTRIBUTE_TYPE.TSK_CARD_SCHEME, MODULE_NAME, scheme))); binInfo .getCardType() .ifPresent( cardType -> attributes.add( new BlackboardAttribute( ATTRIBUTE_TYPE.TSK_CARD_TYPE, MODULE_NAME, cardType))); binInfo .getBrand() .ifPresent( brand -> attributes.add( new BlackboardAttribute( ATTRIBUTE_TYPE.TSK_BRAND_NAME, MODULE_NAME, brand))); binInfo .getBankName() .ifPresent( bankName -> attributes.add( new BlackboardAttribute( ATTRIBUTE_TYPE.TSK_BANK_NAME, MODULE_NAME, bankName))); binInfo .getBankPhoneNumber() .ifPresent( phoneNumber -> attributes.add( new BlackboardAttribute( ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, MODULE_NAME, phoneNumber))); binInfo .getBankURL() .ifPresent( url -> attributes.add( new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_URL, MODULE_NAME, url))); binInfo .getCountry() .ifPresent( country -> attributes.add( new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COUNTRY, MODULE_NAME, country))); binInfo .getBankCity() .ifPresent( city -> attributes.add( new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_CITY, MODULE_NAME, city))); } /* if the hit is from unused or unalocated blocks, record the * KEYWORD_SEARCH_DOCUMENT_ID, so we can show just that chunk in the * UI */ 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) { attributes.add( new BlackboardAttribute( KEYWORD_SEARCH_DOCUMENT_ID, MODULE_NAME, hit.getSolrDocumentId())); } } // make account artifact try { newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_ACCOUNT); } catch (TskCoreException tskCoreException) { LOGGER.log( Level.SEVERE, "Error adding bb artifact for account", tskCoreException); // NON-NLS return null; } } else { // regex match attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD, MODULE_NAME, termHit)); // regex keyword attributes.add( new BlackboardAttribute( ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP, MODULE_NAME, keyword.getQuery())); // make keyword hit artifact try { newArtifact = hit.getContent().newArtifact(ARTIFACT_TYPE.TSK_KEYWORD_HIT); } catch (TskCoreException tskCoreException) { LOGGER.log( Level.SEVERE, "Error adding bb artifact for keyword hit", tskCoreException); // NON-NLS return null; } } if (StringUtils.isNotBlank(listName)) { attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, listName)); } // preview if (snippet != null) { attributes.add( new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_KEYWORD_PREVIEW, MODULE_NAME, snippet)); } if (hit.isArtifactHit()) { attributes.add( new BlackboardAttribute( ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, hit.getArtifact().getArtifactID())); } try { // TODO: do we still/really need this KeywordCachedArtifact class? newArtifact.addAttributes(attributes); KeywordCachedArtifact writeResult = new KeywordCachedArtifact(newArtifact); writeResult.add(attributes); return writeResult; } catch (TskCoreException e) { LOGGER.log( Level.SEVERE, "Error adding bb attributes for terms search artifact", e); // NON-NLS return null; } }