Exemple #1
0
  /**
   * Create a tag for an artifact with TSK_TAG_NAME as tagName.
   *
   * @param artifact to create tag for
   * @param tagName TSK_TAG_NAME
   * @param comment the tag comment or null if not present
   */
  public static void createTag(BlackboardArtifact artifact, String tagName, String comment) {
    try {
      Case currentCase = Case.getCurrentCase();
      SleuthkitCase skCase = currentCase.getSleuthkitCase();

      AbstractFile file = skCase.getAbstractFileById(artifact.getObjectID());
      final BlackboardArtifact bookArt =
          file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT);
      List<BlackboardAttribute> attrs = new ArrayList<BlackboardAttribute>();

      BlackboardAttribute attr1 =
          new BlackboardAttribute(
              BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID(), "", tagName);

      if (comment != null && !comment.isEmpty()) {
        BlackboardAttribute attr2 =
            new BlackboardAttribute(
                BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(), "", comment);
        attrs.add(attr2);
      }

      BlackboardAttribute attr3 =
          new BlackboardAttribute(
              BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID(),
              "",
              artifact.getArtifactID());
      attrs.add(attr1);

      attrs.add(attr3);
      bookArt.addAttributes(attrs);
    } catch (TskCoreException ex) {
      logger.log(Level.SEVERE, "Failed to create tag for artifact " + artifact.getArtifactID());
    }
  }
 @Override
 public boolean isPreferred(Node node, boolean isSupported) {
   BlackboardArtifact art = node.getLookup().lookup(BlackboardArtifact.class);
   return isSupported
       && (art == null
           || art.getArtifactTypeID()
               == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID());
 }
Exemple #3
0
  /**
   * Generic method for adding a blackboard artifact to the blackboard
   *
   * @param type is a blackboard.artifact_type enum to determine which type the artifact should be
   * @param content is the FsContent object that needs to have the artifact added for it
   * @param bbattributes is the collection of blackboard attributes that need to be added to the
   *     artifact after the artifact has been created
   */
  public void addArtifact(
      BlackboardArtifact.ARTIFACT_TYPE type,
      FsContent content,
      Collection<BlackboardAttribute> bbattributes) {

    try {
      BlackboardArtifact bbart = content.newArtifact(type);
      bbart.addAttributes(bbattributes);
    } catch (TskException ex) {
      logger.log(Level.SEVERE, "Error while trying to add an artifact: " + ex);
    }
  }
Exemple #4
0
  /**
   * Generic method for adding a blackboard artifact to the blackboard
   *
   * @param type is a blackboard.artifact_type enum to determine which type the artifact should be
   * @param content is the FsContent object that needs to have the artifact added for it
   * @param bbattributes is the collection of blackboard attributes that need to be added to the
   *     artifact after the artifact has been created
   */
  public void addArtifact(
      BlackboardArtifact.ARTIFACT_TYPE type,
      FsContent content,
      Collection<BlackboardAttribute> bbattributes) {

    try {
      BlackboardArtifact bbart = content.newArtifact(type);
      bbart.addAttributes(bbattributes);
    } catch (TskException ex) {
      logger.log(Level.WARNING, "Error while trying to add an artifact: " + ex);
      this.addErrorMessage(
          this.getName()
              + ": Error while trying to add artifact to case for file:"
              + content.getName());
    }
  }
Exemple #5
0
    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);
      }
    }
Exemple #6
0
  /**
   * Create a tag for a file with TSK_TAG_NAME as tagName.
   *
   * @param file to create tag for
   * @param tagName TSK_TAG_NAME
   * @param comment the tag comment, or null if not present
   */
  public static void createTag(AbstractFile file, String tagName, String comment) {
    try {
      final BlackboardArtifact bookArt =
          file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
      List<BlackboardAttribute> attrs = new ArrayList<BlackboardAttribute>();

      BlackboardAttribute attr1 =
          new BlackboardAttribute(
              BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID(), "", tagName);
      attrs.add(attr1);

      if (comment != null && !comment.isEmpty()) {
        BlackboardAttribute attr2 =
            new BlackboardAttribute(
                BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(), "", comment);
        attrs.add(attr2);
      }
      bookArt.addAttributes(attrs);
    } catch (TskCoreException ex) {
      logger.log(Level.SEVERE, "Failed to create tag for " + file.getName());
    }
  }
Exemple #7
0
  /**
   * Get the artifact for a result tag.
   *
   * @param tagArtifactId artifact id of the tag
   * @return the tag's artifact
   */
  static BlackboardArtifact getArtifactFromTag(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_TAGGED_ARTIFACT.getTypeID()) {
            return skCase.getBlackboardArtifact(att.getValueLong());
          }
        }
      }
    } catch (TskCoreException ex) {
      logger.log(Level.SEVERE, "Failed to get artifact " + tagArtifactId + " from case.");
    }

    return null;
  }
Exemple #8
0
  /**
   * 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;
  }
Exemple #9
0
  /** Search for bookmark files and make artifacts. */
  private void getBookmark() {
    FileManager fileManager = currentCase.getServices().getFileManager();
    List<AbstractFile> bookmarkFiles = null;
    try {
      bookmarkFiles = fileManager.findFiles(dataSource, "Bookmarks", "Chrome"); // NON-NLS
    } catch (TskCoreException ex) {
      String msg =
          NbBundle.getMessage(this.getClass(), "Chrome.getBookmark.errMsg.errGettingFiles");
      logger.log(Level.SEVERE, msg, ex);
      this.addErrorMessage(this.getName() + ": " + msg);
      return;
    }

    if (bookmarkFiles.isEmpty()) {
      logger.log(Level.INFO, "Didn't find any Chrome bookmark files."); // NON-NLS
      return;
    }

    dataFound = true;
    int j = 0;

    while (j < bookmarkFiles.size()) {
      AbstractFile bookmarkFile = bookmarkFiles.get(j++);
      if (bookmarkFile.getSize() == 0) {
        continue;
      }
      String temps =
          RAImageIngestModule.getRATempPath(currentCase, "chrome")
              + File.separator
              + bookmarkFile.getName().toString()
              + j
              + ".db"; // NON-NLS
      try {
        ContentUtils.writeToFile(bookmarkFile, new File(temps));
      } catch (IOException ex) {
        logger.log(
            Level.SEVERE,
            "Error writing temp sqlite db for Chrome bookmark artifacts.{0}",
            ex); // NON-NLS
        this.addErrorMessage(
            NbBundle.getMessage(
                this.getClass(),
                "Chrome.getBookmark.errMsg.errAnalyzingFile",
                this.getName(),
                bookmarkFile.getName()));
        continue;
      }

      logger.log(
          Level.INFO,
          "{0}- Now getting Bookmarks from {1}",
          new Object[] {moduleName, temps}); // NON-NLS
      File dbFile = new File(temps);
      if (context.dataSourceIngestIsCancelled()) {
        dbFile.delete();
        break;
      }

      FileReader tempReader;
      try {
        tempReader = new FileReader(temps);
      } catch (FileNotFoundException ex) {
        logger.log(
            Level.SEVERE,
            "Error while trying to read into the Bookmarks for Chrome.",
            ex); // NON-NLS
        this.addErrorMessage(
            NbBundle.getMessage(
                this.getClass(),
                "Chrome.getBookmark.errMsg.errAnalyzeFile",
                this.getName(),
                bookmarkFile.getName()));
        continue;
      }

      final JsonParser parser = new JsonParser();
      JsonElement jsonElement;
      JsonObject jElement, jRoot, jBookmark;
      JsonArray jBookmarkArray;

      try {
        jsonElement = parser.parse(tempReader);
        jElement = jsonElement.getAsJsonObject();
        jRoot = jElement.get("roots").getAsJsonObject(); // NON-NLS
        jBookmark = jRoot.get("bookmark_bar").getAsJsonObject(); // NON-NLS
        jBookmarkArray = jBookmark.getAsJsonArray("children"); // NON-NLS
      } catch (JsonIOException | JsonSyntaxException | IllegalStateException ex) {
        logger.log(Level.WARNING, "Error parsing Json from Chrome Bookmark.", ex); // NON-NLS
        this.addErrorMessage(
            NbBundle.getMessage(
                this.getClass(),
                "Chrome.getBookmark.errMsg.errAnalyzingFile3",
                this.getName(),
                bookmarkFile.getName()));
        continue;
      }

      for (JsonElement result : jBookmarkArray) {
        JsonObject address = result.getAsJsonObject();
        if (address == null) {
          continue;
        }
        JsonElement urlEl = address.get("url"); // NON-NLS
        String url;
        if (urlEl != null) {
          url = urlEl.getAsString();
        } else {
          url = "";
        }
        String name;
        JsonElement nameEl = address.get("name"); // NON-NLS
        if (nameEl != null) {
          name = nameEl.getAsString();
        } else {
          name = "";
        }
        Long date;
        JsonElement dateEl = address.get("date_added"); // NON-NLS
        if (dateEl != null) {
          date = dateEl.getAsLong();
        } else {
          date = Long.valueOf(0);
        }
        String domain = Util.extractDomain(url);
        try {
          BlackboardArtifact bbart = bookmarkFile.newArtifact(ARTIFACT_TYPE.TSK_WEB_BOOKMARK);
          Collection<BlackboardAttribute> bbattributes = new ArrayList<>();
          // TODO Revisit usage of deprecated constructor as per TSK-583
          bbattributes.add(
              new BlackboardAttribute(
                  ATTRIBUTE_TYPE.TSK_URL.getTypeID(),
                  NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
                  url));
          bbattributes.add(
              new BlackboardAttribute(
                  ATTRIBUTE_TYPE.TSK_TITLE.getTypeID(),
                  NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
                  name));
          bbattributes.add(
              new BlackboardAttribute(
                  ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID(),
                  NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
                  (date / 1000000) - Long.valueOf("11644473600")));
          bbattributes.add(
              new BlackboardAttribute(
                  ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID(),
                  NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
                  NbBundle.getMessage(this.getClass(), "Chrome.moduleName")));
          bbattributes.add(
              new BlackboardAttribute(
                  ATTRIBUTE_TYPE.TSK_DOMAIN.getTypeID(),
                  NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
                  domain));
          bbart.addAttributes(bbattributes);
        } catch (TskCoreException ex) {
          logger.log(
              Level.SEVERE,
              "Error while trying to insert Chrome bookmark artifact{0}",
              ex); // NON-NLS
          this.addErrorMessage(
              NbBundle.getMessage(
                  this.getClass(),
                  "Chrome.getBookmark.errMsg.errAnalyzingFile4",
                  this.getName(),
                  bookmarkFile.getName()));
        }
      }
      dbFile.delete();
    }

    IngestServices.getInstance()
        .fireModuleDataEvent(
            new ModuleDataEvent(
                NbBundle.getMessage(this.getClass(), "Chrome.parentModuleName"),
                BlackboardArtifact.ARTIFACT_TYPE.TSK_WEB_BOOKMARK));
  }
Exemple #10
0
 /**
  * Looks up the tag names associated with either a tagged artifact or a tag artifact.
  *
  * @param artifact The artifact
  * @return A set of unique tag names
  */
 public static HashSet<String> getUniqueTagNames(BlackboardArtifact artifact) {
   return getUniqueTagNames(artifact.getArtifactID(), artifact.getArtifactTypeID());
 }
  @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;
    }
  }
Exemple #12
0
    @Override
    protected Node createNodeForKey(final BlackboardArtifact artifact) {
      // create node with action
      BlackboardArtifactNode tagNode = null;

      String iconPath;
      if (tagName.equals(BOOKMARK_TAG_NAME)) {
        iconPath = BOOKMARK_ICON_PATH;
      } else {
        iconPath = TAG_ICON_PATH;
      }

      // create actions here where Tag logic belongs
      // instead of DataResultFilterNode w/visitors, which is much less pluggable and cluttered
      if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) {
        // in case of result tag, add a action by sublcassing bb art node
        // this action will be merged with other actions set  DataResultFIlterNode
        // otherwise in case of
        tagNode =
            new BlackboardArtifactNode(artifact, iconPath) {
              @Override
              public Action[] getActions(boolean bln) {
                // Action [] actions = super.getActions(bln); //To change body of generated methods,
                // choose Tools | Templates.
                Action[] actions = new Action[1];
                actions[0] =
                    new AbstractAction("View Source Result") {
                      @Override
                      public void actionPerformed(ActionEvent e) {
                        // open the source artifact in dir tree
                        BlackboardArtifact sourceArt =
                            Tags.getArtifactFromTag(artifact.getArtifactID());
                        if (sourceArt != null) {
                          BlackboardResultViewer v =
                              Lookup.getDefault().lookup(BlackboardResultViewer.class);
                          v.viewArtifact(sourceArt);
                        }
                      }
                    };
                return actions;
              }
            };
      } else {
        // for file tag, don't subclass to add the additional actions
        tagNode = new BlackboardArtifactNode(artifact, iconPath);
      }

      // add some additional node properties
      int artifactTypeID = artifact.getArtifactTypeID();
      final String NO_DESCR = "no description";
      if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
        BlackboardArtifact sourceResult = Tags.getArtifactFromTag(artifact.getArtifactID());
        String resultType = sourceResult.getDisplayName();

        NodeProperty resultTypeProp =
            new NodeProperty("Source Result Type", "Result Type", NO_DESCR, resultType);

        tagNode.addNodeProperty(resultTypeProp);
      }
      try {
        // add source path property
        final AbstractFile sourceFile = skCase.getAbstractFileById(artifact.getObjectID());
        final String sourcePath = sourceFile.getUniquePath();
        NodeProperty sourcePathProp =
            new NodeProperty("Source File Path", "Source File Path", NO_DESCR, sourcePath);

        tagNode.addNodeProperty(sourcePathProp);
      } catch (TskCoreException ex) {
        logger.log(
            Level.SEVERE,
            "Error getting a file from artifact to get source file path for a tag, ",
            ex);
      }

      return tagNode;
    }
  /**
   * Unpack the file to local folder and return a list of derived files
   *
   * @param pipelineContext current ingest context
   * @param archiveFile file to unpack
   * @return list of unpacked derived files
   */
  void unpack(AbstractFile archiveFile) {
    String archiveFilePath;
    try {
      archiveFilePath = archiveFile.getUniquePath();
    } catch (TskCoreException ex) {
      archiveFilePath = archiveFile.getParentPath() + archiveFile.getName();
    }

    // check if already has derived files, skip
    try {
      if (archiveFile.hasChildren()) {
        // check if local unpacked dir exists
        if (new File(EmbeddedFileExtractorIngestModule.getUniqueName(archiveFile)).exists()) {
          logger.log(
              Level.INFO,
              "File already has been processed as it has children and local unpacked file, skipping: {0}",
              archiveFilePath); // NON-NLS
          return;
        }
      }
    } catch (TskCoreException e) {
      logger.log(
          Level.INFO,
          "Error checking if file already has been processed, skipping: {0}",
          archiveFilePath); // NON-NLS
      return;
    }

    List<AbstractFile> unpackedFiles = Collections.<AbstractFile>emptyList();

    // recursion depth check for zip bomb
    final long archiveId = archiveFile.getId();
    SevenZipExtractor.ArchiveDepthCountTree.Archive parentAr =
        archiveDepthCountTree.findArchive(archiveId);
    if (parentAr == null) {
      parentAr = archiveDepthCountTree.addArchive(null, archiveId);
    } else if (parentAr.getDepth() == MAX_DEPTH) {
      String msg =
          NbBundle.getMessage(
              this.getClass(),
              "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnMsg.zipBomb",
              archiveFile.getName());
      String details =
          NbBundle.getMessage(
              this.getClass(),
              "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnDetails.zipBomb",
              parentAr.getDepth(),
              archiveFilePath);
      // MessageNotifyUtil.Notify.error(msg, details);
      services.postMessage(
          IngestMessage.createWarningMessage(
              EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
      return;
    }

    boolean hasEncrypted = false;
    boolean fullEncryption = true;

    ISevenZipInArchive inArchive = null;
    SevenZipContentReadStream stream = null;

    final ProgressHandle progress =
        ProgressHandleFactory.createHandle(
            NbBundle.getMessage(
                this.getClass(), "EmbeddedFileExtractorIngestModule.ArchiveExtractor.moduleName"));
    int processedItems = 0;

    boolean progressStarted = false;
    try {
      stream = new SevenZipContentReadStream(new ReadContentInputStream(archiveFile));

      // 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.
      // All other archive formats are still opened using 7zip built-in auto-detect functionality.
      ArchiveFormat options = get7ZipOptions(archiveFile);
      inArchive = SevenZip.openInArchive(options, stream);

      int numItems = inArchive.getNumberOfItems();
      logger.log(
          Level.INFO,
          "Count of items in archive: {0}: {1}",
          new Object[] {archiveFilePath, numItems}); // NON-NLS
      progress.start(numItems);
      progressStarted = true;

      final ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface();

      // setup the archive local root folder
      final String uniqueArchiveFileName =
          EmbeddedFileExtractorIngestModule.getUniqueName(archiveFile);
      final String localRootAbsPath = getLocalRootAbsPath(uniqueArchiveFileName);
      final File localRoot = new File(localRootAbsPath);
      if (!localRoot.exists()) {
        try {
          localRoot.mkdirs();
        } catch (SecurityException e) {
          logger.log(
              Level.SEVERE,
              "Error setting up output path for archive root: {0}",
              localRootAbsPath); // NON-NLS
          // bail
          return;
        }
      }

      // initialize tree hierarchy to keep track of unpacked file structure
      SevenZipExtractor.UnpackedTree unpackedTree =
          new SevenZipExtractor.UnpackedTree(
              moduleDirRelative + "/" + uniqueArchiveFileName, archiveFile);

      long freeDiskSpace = services.getFreeDiskSpace();

      // unpack and process every item in archive
      int itemNumber = 0;
      for (ISimpleInArchiveItem item : simpleInArchive.getArchiveItems()) {
        String pathInArchive = item.getPath();

        if (pathInArchive == null || pathInArchive.isEmpty()) {
          // some formats (.tar.gz) may not be handled correctly -- file in archive has no name/path
          // handle this for .tar.gz and tgz but assuming the child is tar,
          // otherwise, unpack using itemNumber as name

          // TODO this should really be signature based, not extension based
          String archName = archiveFile.getName();
          int dotI = archName.lastIndexOf(".");
          String useName = null;
          if (dotI != -1) {
            String base = archName.substring(0, dotI);
            String ext = archName.substring(dotI);
            switch (ext) {
              case ".gz": // NON-NLS
                useName = base;
                break;
              case ".tgz": // NON-NLS
                useName = base + ".tar"; // NON-NLS
                break;
            }
          }

          if (useName == null) {
            pathInArchive = "/" + archName + "/" + Integer.toString(itemNumber);
          } else {
            pathInArchive = "/" + useName;
          }

          String msg =
              NbBundle.getMessage(
                  this.getClass(),
                  "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.unknownPath.msg",
                  archiveFilePath,
                  pathInArchive);
          logger.log(Level.WARNING, msg);
        }
        ++itemNumber;
        logger.log(Level.INFO, "Extracted item path: {0}", pathInArchive); // NON-NLS

        // check if possible zip bomb
        if (isZipBombArchiveItemCheck(archiveFile, item)) {
          continue; // skip the item
        }

        // find this node in the hierarchy, create if needed
        SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode =
            unpackedTree.addNode(pathInArchive);

        String fileName = unpackedNode.getFileName();

        // update progress bar
        progress.progress(archiveFile.getName() + ": " + fileName, processedItems);

        final boolean isEncrypted = item.isEncrypted();
        final boolean isDir = item.isFolder();

        if (isEncrypted) {
          logger.log(
              Level.WARNING, "Skipping encrypted file in archive: {0}", pathInArchive); // NON-NLS
          hasEncrypted = true;
          continue;
        } else {
          fullEncryption = false;
        }

        final Long size = item.getSize();
        if (size == null) {
          // If the size property cannot be determined, out-of-disk-space
          // situations cannot be ascertained.
          // Hence skip this file.
          logger.log(
              Level.WARNING,
              "Size cannot be determined. Skipping file in archive: {0}",
              pathInArchive); // NON-NLS
          continue;
        }

        // check if unpacking this file will result in out of disk space
        // this is additional to zip bomb prevention mechanism
        if (freeDiskSpace != IngestMonitor.DISK_FREE_SPACE_UNKNOWN
            && size > 0) { // if known free space and file not empty
          long newDiskSpace = freeDiskSpace - size;
          if (newDiskSpace < MIN_FREE_DISK_SPACE) {
            String msg =
                NbBundle.getMessage(
                    this.getClass(),
                    "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.msg",
                    archiveFilePath,
                    fileName);
            String details =
                NbBundle.getMessage(
                    this.getClass(),
                    "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.details");
            // MessageNotifyUtil.Notify.error(msg, details);
            services.postMessage(
                IngestMessage.createErrorMessage(
                    EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
            logger.log(
                Level.INFO,
                "Skipping archive item due to insufficient disk space: {0}, {1}",
                new Object[] {archiveFilePath, fileName}); // NON-NLS
            logger.log(
                Level.INFO, "Available disk space: {0}", new Object[] {freeDiskSpace}); // NON-NLS
            continue; // skip this file
          } else {
            // update est. disk space during this archive, so we don't need to poll for every file
            // extracted
            freeDiskSpace = newDiskSpace;
          }
        }

        final String uniqueExtractedName =
            uniqueArchiveFileName
                + File.separator
                + (item.getItemIndex() / 1000)
                + File.separator
                + item.getItemIndex()
                + new File(pathInArchive).getName();

        // final String localRelPath = unpackDir + File.separator + localFileRelPath;
        final String localRelPath = moduleDirRelative + File.separator + uniqueExtractedName;
        final String localAbsPath = moduleDirAbsolute + File.separator + uniqueExtractedName;

        // create local dirs and empty files before extracted
        File localFile = new java.io.File(localAbsPath);
        // cannot rely on files in top-bottom order
        if (!localFile.exists()) {
          try {
            if (isDir) {
              localFile.mkdirs();
            } else {
              localFile.getParentFile().mkdirs();
              try {
                localFile.createNewFile();
              } catch (IOException ex) {
                logger.log(
                    Level.SEVERE,
                    "Error creating extracted file: " + localFile.getAbsolutePath(),
                    ex); // NON-NLS
              }
            }
          } catch (SecurityException e) {
            logger.log(
                Level.SEVERE,
                "Error setting up output path for unpacked file: {0}",
                pathInArchive); // NON-NLS
            // TODO consider bail out / msg to the user
          }
        }

        // skip the rest of this loop if we couldn't create the file
        if (localFile.exists() == false) {
          continue;
        }

        final Date createTime = item.getCreationTime();
        final Date accessTime = item.getLastAccessTime();
        final Date writeTime = item.getLastWriteTime();
        final long createtime = createTime == null ? 0L : createTime.getTime() / 1000;
        final long modtime = writeTime == null ? 0L : writeTime.getTime() / 1000;
        final long accesstime = accessTime == null ? 0L : accessTime.getTime() / 1000;

        // record derived data in unode, to be traversed later after unpacking the archive
        unpackedNode.addDerivedInfo(
            size, !isDir, 0L, createtime, accesstime, modtime, localRelPath);

        // unpack locally if a file
        if (!isDir) {
          SevenZipExtractor.UnpackStream unpackStream = null;
          try {
            unpackStream = new SevenZipExtractor.UnpackStream(localAbsPath);
            item.extractSlow(unpackStream);
          } catch (Exception e) {
            // could be something unexpected with this file, move on
            logger.log(
                Level.WARNING,
                "Could not extract file from archive: " + localAbsPath,
                e); // NON-NLS
          } finally {
            if (unpackStream != null) {
              unpackStream.close();
            }
          }
        }

        // update units for progress bar
        ++processedItems;
      }

      // add them to the DB. We wait until the end so that we have the metadata on all of the
      // intermediate nodes since the order is not guaranteed
      try {
        unpackedTree.addDerivedFilesToCase();
        unpackedFiles = unpackedTree.getAllFileObjects();

        // check if children are archives, update archive depth tracking
        for (AbstractFile unpackedFile : unpackedFiles) {
          if (isSevenZipExtractionSupported(unpackedFile)) {
            archiveDepthCountTree.addArchive(parentAr, unpackedFile.getId());
          }
        }

      } catch (TskCoreException e) {
        logger.log(
            Level.SEVERE,
            "Error populating complete derived file hierarchy from the unpacked dir structure"); // NON-NLS
        // TODO decide if anything to cleanup, for now bailing
      }

    } catch (SevenZipException ex) {
      logger.log(Level.SEVERE, "Error unpacking file: " + archiveFile, ex); // NON-NLS
      // inbox message

      // print a message if the file is allocated
      if (archiveFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
        String msg =
            NbBundle.getMessage(
                this.getClass(),
                "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.msg",
                archiveFile.getName());
        String details =
            NbBundle.getMessage(
                this.getClass(),
                "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.details",
                archiveFilePath,
                ex.getMessage());
        services.postMessage(
            IngestMessage.createErrorMessage(
                EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
      }
    } finally {
      if (inArchive != null) {
        try {
          inArchive.close();
        } catch (SevenZipException e) {
          logger.log(Level.SEVERE, "Error closing archive: " + archiveFile, e); // NON-NLS
        }
      }

      if (stream != null) {
        try {
          stream.close();
        } catch (IOException ex) {
          logger.log(
              Level.SEVERE,
              "Error closing stream after unpacking archive: " + archiveFile,
              ex); // NON-NLS
        }
      }

      // close progress bar
      if (progressStarted) {
        progress.finish();
      }
    }

    // create artifact and send user message
    if (hasEncrypted) {
      String encryptionType = fullEncryption ? ENCRYPTION_FULL : ENCRYPTION_FILE_LEVEL;
      try {
        BlackboardArtifact artifact =
            archiveFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED);
        artifact.addAttribute(
            new BlackboardAttribute(
                BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getTypeID(),
                EmbeddedFileExtractorModuleFactory.getModuleName(),
                encryptionType));
        services.fireModuleDataEvent(
            new ModuleDataEvent(
                EmbeddedFileExtractorModuleFactory.getModuleName(),
                BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED));
      } catch (TskCoreException ex) {
        logger.log(
            Level.SEVERE,
            "Error creating blackboard artifact for encryption detected for file: "
                + archiveFilePath,
            ex); // NON-NLS
      }

      String msg =
          NbBundle.getMessage(
              this.getClass(),
              "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.encrFileDetected.msg");
      String details =
          NbBundle.getMessage(
              this.getClass(),
              "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.encrFileDetected.details",
              archiveFile.getName(),
              EmbeddedFileExtractorModuleFactory.getModuleName());
      services.postMessage(
          IngestMessage.createWarningMessage(
              EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
    }

    // adding unpacked extracted derived files to the job after closing relevant resources.
    if (!unpackedFiles.isEmpty()) {
      // currently sending a single event for all new files
      services.fireModuleContentEvent(new ModuleContentEvent(archiveFile));
      context.addFilesToJob(unpackedFiles);
    }
  }
  @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();
            }
          }
        });
  }
Exemple #15
0
  @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
  public IngestModule.ProcessResult process(AbstractFile file) {
    if (attrId == -1) {
      return IngestModule.ProcessResult.ERROR;
    }

    // Skip anything other than actual file system files.
    if ((file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
        || (file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)
        || (file.isFile() == false)) {
      return IngestModule.ProcessResult.OK;
    }

    // Skip NSRL / known files.
    if (skipKnownFiles && file.getKnown() == TskData.FileKnown.KNOWN) {
      return IngestModule.ProcessResult.OK;
    }

    // Do a nonsensical calculation of the number of 0x00 bytes
    // in the first 1024-bytes of the file.  This is for demo
    // purposes only.
    try {
      byte buffer[] = new byte[1024];
      int len = file.read(buffer, 0, 1024);
      int count = 0;
      for (int i = 0; i < len; i++) {
        if (buffer[i] == 0x00) {
          count++;
        }
      }

      // Make an attribute using the ID for the attribute type that
      // was previously created.
      BlackboardAttribute attr =
          new BlackboardAttribute(attrId, SampleIngestModuleFactory.getModuleName(), count);

      // Add the to the general info artifact for the file. In a
      // real module, you would likely have more complex data types
      // and be making more specific artifacts.
      BlackboardArtifact art = file.getGenInfoArtifact();
      art.addAttribute(attr);

      // This method is thread-safe with per ingest job reference counted
      // management of shared data.
      addToBlackboardPostCount(context.getJobId(), 1L);

      // Fire an event to notify any listeners for blackboard postings.
      ModuleDataEvent event =
          new ModuleDataEvent(
              SampleIngestModuleFactory.getModuleName(), ARTIFACT_TYPE.TSK_GEN_INFO);
      IngestServices.getInstance().fireModuleDataEvent(event);

      return IngestModule.ProcessResult.OK;

    } catch (TskCoreException ex) {
      IngestServices ingestServices = IngestServices.getInstance();
      Logger logger = ingestServices.getLogger(SampleIngestModuleFactory.getModuleName());
      logger.log(Level.SEVERE, "Error processing file (id = " + file.getId() + ")", ex);
      return IngestModule.ProcessResult.ERROR;
    }
  }
  /** @inheritDoc */
  @Override
  @Messages({
    "FilesIdentifierIngestModule.indexError.message=Failed to index interesting file hit artifact for keyword search."
  })
  public ProcessResult process(AbstractFile file) {
    blackboard = Case.getCurrentCase().getServices().getBlackboard();

    // See if the file belongs to any defined interesting files set.
    List<FilesSet> filesSets =
        FilesIdentifierIngestModule.interestingFileSetsByJob.get(this.context.getJobId());
    for (FilesSet filesSet : filesSets) {
      String ruleSatisfied = filesSet.fileIsMemberOf(file);
      if (ruleSatisfied != null) {
        try {
          // Post an interesting files set hit artifact to the
          // blackboard.
          String moduleName = InterestingItemsIngestModuleFactory.getModuleName();
          BlackboardArtifact artifact =
              file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);

          // Add a set name attribute to the artifact. This adds a
          // fair amount of redundant data to the attributes table
          // (i.e., rows that differ only in artifact id), but doing
          // otherwise would requires reworking the interesting files
          // set hit artifact.
          BlackboardAttribute setNameAttribute =
              new BlackboardAttribute(
                  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, moduleName, filesSet.getName());
          artifact.addAttribute(setNameAttribute);

          // Add a category attribute to the artifact to record the
          // interesting files set membership rule that was satisfied.
          BlackboardAttribute ruleNameAttribute =
              new BlackboardAttribute(
                  BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, moduleName, ruleSatisfied);
          artifact.addAttribute(ruleNameAttribute);

          try {
            // index the artifact for keyword search
            blackboard.indexArtifact(artifact);
          } catch (Blackboard.BlackboardException ex) {
            logger.log(
                Level.SEVERE,
                "Unable to index blackboard artifact " + artifact.getArtifactID(),
                ex); // NON-NLS
            MessageNotifyUtil.Notify.error(
                Bundle.FilesIdentifierIngestModule_indexError_message(), artifact.getDisplayName());
          }

          IngestServices.getInstance()
              .fireModuleDataEvent(
                  new ModuleDataEvent(
                      moduleName,
                      BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT,
                      Collections.singletonList(artifact)));

        } catch (TskCoreException ex) {
          FilesIdentifierIngestModule.logger.log(
              Level.SEVERE, "Error posting to the blackboard", ex); // NOI18N NON-NLS
        }
      }
    }
    return ProcessResult.OK;
  }