diff --git a/Core/build.xml b/Core/build.xml index f32b5a28c3..a1290ef2e8 100644 --- a/Core/build.xml +++ b/Core/build.xml @@ -98,6 +98,8 @@ tofile="${ext.dir}/sleuthkit-${TSK_VERSION}.jar"/> + sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.centralrepository.datamodel; + +/** + * Encapsulates the concept of an examiner. + */ +final public class CentralRepoExaminer { + + private final long id; // Row id in the examiners table in central repo database. + private final String loginName; + + public CentralRepoExaminer(long id, String loginName) { + this.id = id; + this.loginName = loginName; + } + + /** + * Returns the id. + * + * @return id + */ + public long getId() { + return id; + } + + /** + * Returns the login name of examiner. + * + * @return login name + */ + public String getLoginName() { + return this.loginName; + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java index 21fd832c00..b71606594f 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepository.java @@ -26,7 +26,6 @@ import org.sleuthkit.datamodel.TskData; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.centralrepository.datamodel.CentralRepoAccount.CentralRepoAccountType; import org.sleuthkit.autopsy.coordinationservice.CoordinationService; -import org.sleuthkit.datamodel.Examiner; /** * Main interface for interacting with the database @@ -163,21 +162,15 @@ public interface CentralRepository { void updateCase(CorrelationCase eamCase) throws CentralRepoException; /** - * Updates the examiners table, by adding current logged in user to - * examiners table, if not already in there. - * - * @throws CentralRepoException If there is an error. + * Queries the examiner table for the given user name. + * Adds a row if the user is not found in the examiner table. * + * @param examinerLoginName user name to look for. + * @return CentralRepoExaminer for the given user name. + * @throws CentralRepoException If there is an error in looking up or + * inserting the user in the examiners table. */ - void updateExaminers() throws CentralRepoException; - - /** - * Get the Examiner object for the current logged in user. - * - * @return Examiner Current examiner. - * @throws CentralRepoException - */ - Examiner getCurrentCentralRepoExaminer() throws CentralRepoException; + CentralRepoExaminer getOrInsertExaminer(String examinerLoginName) throws CentralRepoException; /** * Retrieves Central Repo case based on an Autopsy Case @@ -872,10 +865,5 @@ public interface CentralRepository { * @throws CentralRepoException */ CentralRepoAccount getOrCreateAccount(CentralRepoAccount.CentralRepoAccountType crAccountType, String accountUniqueID) throws CentralRepoException; - - - /** - * Clears all caches. - */ - void clearCaches(); + } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepositoryDbQueryCallback.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepositoryDbQueryCallback.java index cedf5d0880..ffc02b4a9f 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepositoryDbQueryCallback.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepositoryDbQueryCallback.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2020 Basis Technology Corp. + * Copyright 2020 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,7 +27,7 @@ import java.sql.SQLException; * the results themselves. * */ -public interface CentralRepositoryDbQueryCallback { +interface CentralRepositoryDbQueryCallback { /** * Process the resultset from a query. diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Persona.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Persona.java index a05fee9b16..fd4e26eca2 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Persona.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/Persona.java @@ -27,7 +27,6 @@ import java.util.Collections; import java.util.Objects; import java.util.UUID; import org.apache.commons.lang3.StringUtils; -import org.sleuthkit.datamodel.Examiner; import org.sleuthkit.datamodel.SleuthkitCase; /** @@ -116,7 +115,7 @@ public class Persona { } // Persona name to use if no name is specified. - private static final String DEFAULT_PERSONA_NAME = "NoName"; + private static final String DEFAULT_PERSONA_NAME = "Unknown"; // primary key in the Personas table in CR database private final long id; @@ -126,7 +125,7 @@ public class Persona { private final long createdDate; private final long modifiedDate; private final PersonaStatus status; - private final Examiner examiner; + private final CentralRepoExaminer examiner; public long getId() { return id; @@ -156,11 +155,11 @@ public class Persona { return status; } - public Examiner getExaminer() { + public CentralRepoExaminer getExaminer() { return examiner; } - Persona(long id, String uuidStr, String name, String comment, long created_date, long modified_date, PersonaStatus status, Examiner examiner) { + Persona(long id, String uuidStr, String name, String comment, long created_date, long modified_date, PersonaStatus status, CentralRepoExaminer examiner) { this.id = id; this.uuidStr = uuidStr; this.name = name; @@ -207,7 +206,7 @@ public class Persona { private static Persona createPersona(String name, String comment, PersonaStatus status) throws CentralRepoException { // generate a UUID for the persona String uuidStr = UUID.randomUUID().toString(); - Examiner examiner = CentralRepository.getInstance().getCurrentCentralRepoExaminer(); + CentralRepoExaminer examiner = CentralRepository.getInstance().getOrInsertExaminer(System.getProperty("user.name")); Instant instant = Instant.now(); Long timeStampMillis = instant.toEpochMilli(); @@ -240,7 +239,7 @@ public class Persona { */ public PersonaAccount addAccountToPersona(CentralRepoAccount account, String justification, Persona.Confidence confidence) throws CentralRepoException { - Examiner currentExaminer = CentralRepository.getInstance().getCurrentCentralRepoExaminer(); + CentralRepoExaminer currentExaminer = CentralRepository.getInstance().getOrInsertExaminer(System.getProperty("user.name")); Instant instant = Instant.now(); Long timeStampMillis = instant.toEpochMilli(); @@ -263,19 +262,18 @@ public class Persona { */ private static class PersonaQueryCallback implements CentralRepositoryDbQueryCallback { - private Persona persona = null; + private final Collection personaList = new ArrayList<>(); @Override public void process(ResultSet rs) throws SQLException { while (rs.next()) { - Examiner examiner = new Examiner( + CentralRepoExaminer examiner = new CentralRepoExaminer( rs.getInt("examiner_id"), - rs.getString("login_name"), - rs.getString("display_name")); + rs.getString("login_name")); PersonaStatus status = PersonaStatus.fromId(rs.getInt("status_id")); - persona = new Persona( + Persona persona = new Persona( rs.getInt("id"), rs.getString("uuid"), rs.getString("name"), @@ -285,14 +283,24 @@ public class Persona { status, examiner ); + + personaList.add(persona); } } - Persona getPersona() { - return persona; + Collection getPersonas() { + return Collections.unmodifiableCollection(personaList); } }; + // Partial query string to select from personas table, + // just supply the where clause. + private static final String PERSONA_QUERY = + "SELECT p.id, p.uuid, p.name, p.comment, p.created_date, p.modified_date, p.status_id, p.examiner_id, e.login_name, e.display_name " + + "FROM personas as p " + + "INNER JOIN examiners as e ON e.id = p.examiner_id "; + + /** * Gets the row from the Personas table with the given UUID, creates and * returns the Persona from that data. @@ -306,41 +314,39 @@ public class Persona { */ private static Persona getPersonaByUUID(String uuid) throws CentralRepoException { - String queryClause = "SELECT p.id, p.uuid, p.name, p.comment, p.created_date, p.modified_date, p.status_id, p.examiner_id, e.login_name, e.display_name " - + "FROM personas as p " - + "INNER JOIN examiners as e ON e.id = p.examiner_id " + String queryClause = + PERSONA_QUERY + "WHERE p.uuid = '" + uuid + "'"; PersonaQueryCallback queryCallback = new PersonaQueryCallback(); CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback); - return queryCallback.getPersona(); + Collection personas = queryCallback.getPersonas(); + + return personas.isEmpty() ? null : personas.iterator().next(); } /** - * Gets the row from the Personas table with the given id, creates and - * returns the Persona from that data. + * Gets the rows from the Personas table with matching name. * - * @param id Persona id to match. - * @return Persona matching the given UUID, may be null if no match is - * found. + * @param partialName Name substring to match. + * @return Collection of personas matching the given name substring, may be + * empty if no match is found. * * @throws CentralRepoException If there is an error in querying the * Personas table. */ - public static Persona getPersonaById(long id) throws CentralRepoException { + public static Collection getPersonaByName(String partialName) throws CentralRepoException { - String queryClause = "SELECT p.id, p.uuid, p.name, p.comment, p.created_date, p.modified_date, p.status_id, p.examiner_id, e.login_name, e.display_name " - + "FROM personas as p " - + "INNER JOIN examiners as e ON e.id = p.examiner_id " - + "WHERE p.id = " + id; + String queryClause = PERSONA_QUERY + + "WHERE LOWER(p.name) LIKE " + "LOWER('%" + partialName + "%')" ; PersonaQueryCallback queryCallback = new PersonaQueryCallback(); CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback); - return queryCallback.getPersona(); + return queryCallback.getPersonas(); } - + /** * Creates an alias for the Persona. * @@ -403,32 +409,7 @@ public class Persona { public Collection getPersonaAccounts() throws CentralRepoException { return PersonaAccount.getPersonaAccountsForPersona(this.getId()); } - - /** - * Gets all the Persona for the specified Account. - * - * @param accountId Id of account for which to get the Personas for. - * @return Collection of PersonaAccounts. may be empty. - * - * @throws CentralRepoException If there is an error in getting the - * persona_account. - */ - public static Collection getPersonaAccountsForAccount(long accountId) throws CentralRepoException { - return PersonaAccount.getPersonaAccountsForAccount(accountId); - } - - /** - * Get all accounts associated with the persona. - * - * @return Collection of all accounts associated with the given persona, may - * be empty. - * @throws CentralRepoException If there is an error in getting the - * accounts. - */ - public Collection getAccounts() throws CentralRepoException { - return PersonaAccount.getAccountsForPersona(this.getId()); - } - + /** * Callback to process a query that gets cases for account instances of an * account @@ -464,7 +445,7 @@ public class Persona { Collection casesForPersona = new ArrayList<>(); // get all accounts for this persona - Collection accounts = this.getAccounts(); + Collection accounts = PersonaAccount.getAccountsForPersona(this.getId()); for (CentralRepoAccount account : accounts) { int corrTypeId = account.getAccountType().getCorrelationTypeId(); CorrelationAttributeInstance.Type correlationType = CentralRepository.getInstance().getCorrelationTypeById(corrTypeId); @@ -527,7 +508,7 @@ public class Persona { public Collection getDataSources() throws CentralRepoException { Collection correlationDataSources = new ArrayList<>(); - Collection accounts = this.getAccounts(); + Collection accounts = PersonaAccount.getAccountsForPersona(this.getId()); for (CentralRepoAccount account : accounts) { int corrTypeId = account.getAccountType().getCorrelationTypeId(); CorrelationAttributeInstance.Type correlationType = CentralRepository.getInstance().getCorrelationTypeById(corrTypeId); @@ -563,10 +544,9 @@ public class Persona { while (resultSet.next()) { // examiner that created the persona - Examiner personaExaminer = new Examiner( + CentralRepoExaminer personaExaminer = new CentralRepoExaminer( resultSet.getInt("persona_examiner_id"), - resultSet.getString("persona_examiner_login_name"), - resultSet.getString("persona_examiner_display_name")); + resultSet.getString("persona_examiner_login_name")); // create persona PersonaStatus status = PersonaStatus.fromId(resultSet.getInt("status_id")); @@ -653,7 +633,7 @@ public class Persona { * @return Collection of personas, may be empty. * @throws CentralRepoException */ - public static Collection getPersonaForDataSource(CorrelationDataSource dataSource) throws CentralRepoException { + public static Collection getPersonasForDataSource(CorrelationDataSource dataSource) throws CentralRepoException { Collection personaList = new ArrayList<>(); Collection accountTypes = CentralRepository.getInstance().getAllAccountTypes(); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAccount.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAccount.java index 4e11cf8202..3b74b82aea 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAccount.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAccount.java @@ -23,7 +23,6 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import org.sleuthkit.datamodel.Examiner; /** * This class represents an association between a Persona and an Account. @@ -39,9 +38,9 @@ public class PersonaAccount { private final String justification; private final Persona.Confidence confidence; private final long dateAdded; - private final Examiner examiner; + private final CentralRepoExaminer examiner; - public PersonaAccount(Persona persona, CentralRepoAccount account, String justification, Persona.Confidence confidence, long dateAdded, Examiner examiner) { + public PersonaAccount(Persona persona, CentralRepoAccount account, String justification, Persona.Confidence confidence, long dateAdded, CentralRepoExaminer examiner) { this.persona = persona; this.account = account; this.justification = justification; @@ -70,7 +69,7 @@ public class PersonaAccount { return dateAdded; } - public Examiner getExaminer() { + public CentralRepoExaminer getExaminer() { return examiner; } @@ -86,16 +85,14 @@ public class PersonaAccount { while (rs.next()) { // examiner that created the persona/account association - Examiner paExaminer = new Examiner( + CentralRepoExaminer paExaminer = new CentralRepoExaminer( rs.getInt("pa_examiner_id"), - rs.getString("pa_examiner_login_name"), - rs.getString("pa_examiner_display_name")); + rs.getString("pa_examiner_login_name")); // examiner that created the persona - Examiner personaExaminer = new Examiner( + CentralRepoExaminer personaExaminer = new CentralRepoExaminer( rs.getInt("persona_examiner_id"), - rs.getString("persona_examiner_login_name"), - rs.getString("persona_examiner_display_name")); + rs.getString("persona_examiner_login_name")); // create persona Persona.PersonaStatus status = Persona.PersonaStatus.fromId(rs.getInt("status_id")); @@ -175,7 +172,7 @@ public class PersonaAccount { * @throws CentralRepoException If there is an error in getting the * persona_account. */ - static Collection getPersonaAccountsForAccount(long accountId) throws CentralRepoException { + public static Collection getPersonaAccountsForAccount(long accountId) throws CentralRepoException { String queryClause = PERSONA_ACCOUNTS_QUERY_CALUSE + " WHERE persona_accounts.account_id = " + accountId; @@ -184,6 +181,27 @@ public class PersonaAccount { return queryCallback.getPersonaAccountsList(); } + + /** + * Gets all the Persona associated with all the accounts matching the given + * account identifier substring. + * + * @param accountIdentifierSubstring Account identifier substring to search + * for. + * @return Collection of PersonaAccounts. may be empty. + * + * @throws CentralRepoException If there is an error in getting the + * persona_account. + */ + public static Collection getPersonaAccountsForAccountIdentifier(String accountIdentifierSubstring) throws CentralRepoException { + String queryClause = PERSONA_ACCOUNTS_QUERY_CALUSE + + " WHERE LOWER(accounts.account_unique_identifier) LIKE LOWER('%" + accountIdentifierSubstring + "%')"; + + PersonaAccountsQueryCallback queryCallback = new PersonaAccountsQueryCallback(); + CentralRepository.getInstance().executeSelectSQL(queryClause, queryCallback); + + return queryCallback.getPersonaAccountsList(); + } /** * Callback to process a query that gets all accounts belonging to a diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAlias.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAlias.java index cff33619dd..cdebd7097d 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAlias.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaAlias.java @@ -25,7 +25,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import org.apache.commons.lang3.StringUtils; -import org.sleuthkit.datamodel.Examiner; import org.sleuthkit.datamodel.SleuthkitCase; /** @@ -40,7 +39,7 @@ public class PersonaAlias { private final String justification; private final Persona.Confidence confidence; private final long dateAdded; - private final Examiner examiner; + private final CentralRepoExaminer examiner; public long getPersonaId() { return personaId; @@ -62,11 +61,11 @@ public class PersonaAlias { return dateAdded; } - public Examiner getExaminer() { + public CentralRepoExaminer getExaminer() { return examiner; } - public PersonaAlias(long personaId, String alias, String justification, Persona.Confidence confidence, long dateAdded, Examiner examiner) { + public PersonaAlias(long personaId, String alias, String justification, Persona.Confidence confidence, long dateAdded, CentralRepoExaminer examiner) { this.personaId = personaId; this.alias = alias; this.justification = justification; @@ -88,7 +87,7 @@ public class PersonaAlias { */ static PersonaAlias addPersonaAlias(Persona persona, String alias, String justification, Persona.Confidence confidence) throws CentralRepoException { - Examiner examiner = CentralRepository.getInstance().getCurrentCentralRepoExaminer(); + CentralRepoExaminer examiner = CentralRepository.getInstance().getOrInsertExaminer(System.getProperty("user.name")); Instant instant = Instant.now(); Long timeStampMillis = instant.toEpochMilli(); @@ -118,10 +117,9 @@ public class PersonaAlias { public void process(ResultSet rs) throws SQLException { while (rs.next()) { - Examiner examiner = new Examiner( + CentralRepoExaminer examiner = new CentralRepoExaminer( rs.getInt("examiner_id"), - rs.getString("login_name"), - rs.getString("display_name")); + rs.getString("login_name")); PersonaAlias alias = new PersonaAlias( rs.getLong("persona_id"), diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaMetadata.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaMetadata.java index 691772d264..713f00a981 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PersonaMetadata.java @@ -25,7 +25,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import org.apache.commons.lang3.StringUtils; -import org.sleuthkit.datamodel.Examiner; import org.sleuthkit.datamodel.SleuthkitCase; /** @@ -43,7 +42,7 @@ public class PersonaMetadata { private final String justification; private final Persona.Confidence confidence; private final long dateAdded; - private final Examiner examiner; + private final CentralRepoExaminer examiner; public long getPersonaId() { return personaId; @@ -69,11 +68,11 @@ public class PersonaMetadata { return dateAdded; } - public Examiner getExaminer() { + public CentralRepoExaminer getExaminer() { return examiner; } - public PersonaMetadata(long personaId, String name, String value, String justification, Persona.Confidence confidence, long dateAdded, Examiner examiner) { + public PersonaMetadata(long personaId, String name, String value, String justification, Persona.Confidence confidence, long dateAdded, CentralRepoExaminer examiner) { this.personaId = personaId; this.name = name; this.value = value; @@ -97,7 +96,7 @@ public class PersonaMetadata { */ static PersonaMetadata addPersonaMetadata(long personaId, String name, String value, String justification, Persona.Confidence confidence) throws CentralRepoException { - Examiner examiner = CentralRepository.getInstance().getCurrentCentralRepoExaminer(); + CentralRepoExaminer examiner = CentralRepository.getInstance().getOrInsertExaminer(System.getProperty("user.name")); Instant instant = Instant.now(); Long timeStampMillis = instant.toEpochMilli(); @@ -128,10 +127,9 @@ public class PersonaMetadata { public void process(ResultSet rs) throws SQLException { while (rs.next()) { - Examiner examiner = new Examiner( + CentralRepoExaminer examiner = new CentralRepoExaminer( rs.getInt("examiner_id"), - rs.getString("login_name"), - rs.getString("display_name")); + rs.getString("login_name")); PersonaMetadata metaData = new PersonaMetadata( rs.getLong("persona_id"), diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresCentralRepo.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresCentralRepo.java index 6dd8b7efea..f1afb941bc 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresCentralRepo.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresCentralRepo.java @@ -71,8 +71,6 @@ final class PostgresCentralRepo extends RdbmsCentralRepo { private PostgresCentralRepo() throws CentralRepoException { dbSettings = new PostgresCentralRepoSettings(); bulkArtifactsThreshold = dbSettings.getBulkThreshold(); - - this.updateExaminers(); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java index 39f48b0e66..de88396de7 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/RdbmsCentralRepo.java @@ -51,7 +51,7 @@ import org.sleuthkit.autopsy.healthmonitor.HealthMonitor; import org.sleuthkit.autopsy.healthmonitor.TimingMetric; import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber; -import org.sleuthkit.datamodel.Examiner; +import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskData; /** @@ -102,8 +102,6 @@ abstract class RdbmsCentralRepo implements CentralRepository { // Update Test code if this changes. It's hard coded there. static final int DEFAULT_BULK_THRESHHOLD = 1000; - private Examiner cachedCurrentExaminer = null; - private static final int QUERY_STR_MAX_LEN = 1000; @@ -222,7 +220,6 @@ abstract class RdbmsCentralRepo implements CentralRepository { /** * Reset the contents of the caches associated with EamDb results. */ - @Override public final void clearCaches() { synchronized(typeCache) { typeCache.invalidateAll(); @@ -233,7 +230,6 @@ abstract class RdbmsCentralRepo implements CentralRepository { dataSourceCacheByDsObjectId.invalidateAll(); dataSourceCacheById.invalidateAll(); accountsCache.invalidateAll(); - cachedCurrentExaminer = null; } /** @@ -2520,72 +2516,6 @@ abstract class RdbmsCentralRepo implements CentralRepository { } } - /** - * Updates the examiners table, by adding current logged in user to - * examiners table, if not already in there. - * - * @throws CentralRepoException If there is an error. - * - */ - @Override - public void updateExaminers() throws CentralRepoException { - - String loginName = System.getProperty("user.name"); - if (loginName.isEmpty()) { - logger.log(Level.SEVERE, "Cannot determine logged in user name"); - return; - } - - try (Connection connection = connect(); - Statement statement = connection.createStatement();) { - - String insertSQL; - switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) { - case POSTGRESQL: - insertSQL = "INSERT INTO examiners (login_name) VALUES ('" + loginName + "')" + getConflictClause(); //NON-NLS - break; - case SQLITE: - insertSQL = "INSERT OR IGNORE INTO examiners (login_name) VALUES ('" + loginName + "')"; - break; - default: - throw new CentralRepoException(String.format("Cannot add examiner to currently selected CR database platform %s", CentralRepoDbManager.getSavedDbChoice().getDbPlatform())); - } - statement.execute(insertSQL); //NON-NLS - } catch (SQLException ex) { - throw new CentralRepoException("Error inserting row in examiners", ex); - } - } - - @Override - public Examiner getCurrentCentralRepoExaminer() throws CentralRepoException { - - // return cached value if there's one - if (cachedCurrentExaminer != null) { - return cachedCurrentExaminer; - } - String loginName = System.getProperty("user.name"); - if (loginName == null || loginName.isEmpty()) { - throw new CentralRepoException("Failed to determine logged in user name."); - } - - String querySQL = "SELECT * FROM examiners WHERE login_name = '" + loginName + "'"; - - try (Connection connection = connect(); - Statement statement = connection.createStatement(); - ResultSet resultSet = statement.executeQuery(querySQL);) { - - if (resultSet.next()) { - cachedCurrentExaminer = new Examiner(resultSet.getLong("id"), resultSet.getString("login_name"), resultSet.getString("display_name")); - return cachedCurrentExaminer; - } else { - throw new CentralRepoException("Error getting examiner for name = " + loginName); - } - - } catch (SQLException ex) { - throw new CentralRepoException("Error getting examiner for name = " + loginName, ex); - } - } - @Override public void executeInsertSQL(String insertClause) throws CentralRepoException { @@ -2766,6 +2696,61 @@ abstract class RdbmsCentralRepo implements CentralRepository { } } + /** + * Queries the examiner table for the given user name. + * Adds a row if the user is not found in the examiner table. + * + * @param examinerLoginName user name to look for. + * @return CentralRepoExaminer for the given user name. + * @throws CentralRepoException If there is an error in looking up or + * inserting the user in the examiners table. + */ + + @Override + public CentralRepoExaminer getOrInsertExaminer(String examinerLoginName) throws CentralRepoException { + + String querySQL = "SELECT * FROM examiners WHERE login_name = '" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + "'"; + try (Connection connection = connect(); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery(querySQL);) { + + if (resultSet.next()) { + return new CentralRepoExaminer(resultSet.getLong("id"), resultSet.getString("login_name")); + } else { + // Could not find this user in the Examiner table, add a row for it. + try { + String insertSQL; + switch (CentralRepoDbManager.getSavedDbChoice().getDbPlatform()) { + case POSTGRESQL: + insertSQL = "INSERT INTO examiners (login_name) VALUES ('" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + "')" + getConflictClause(); //NON-NLS + break; + case SQLITE: + insertSQL = "INSERT OR IGNORE INTO examiners (login_name) VALUES ('" + SleuthkitCase.escapeSingleQuotes(examinerLoginName) + "')"; //NON-NLS + break; + default: + throw new CentralRepoException(String.format("Cannot add examiner to currently selected CR database platform %s", CentralRepoDbManager.getSavedDbChoice().getDbPlatform())); //NON-NLS + } + statement.execute(insertSQL); + + // Query the table again to get the row for the user + try (ResultSet resultSet2 = statement.executeQuery(querySQL)) { + if (resultSet2.next()) { + return new CentralRepoExaminer(resultSet2.getLong("id"), resultSet2.getString("login_name")); + } else { + throw new CentralRepoException("Error getting examiner for name = " + examinerLoginName); + } + } + + } catch (SQLException ex) { + throw new CentralRepoException("Error inserting row in examiners", ex); + } + } + + } catch (SQLException ex) { + throw new CentralRepoException("Error getting examiner for name = " + examinerLoginName, ex); + } + } + /** * Update an existing organization. * diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteCentralRepo.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteCentralRepo.java index aac89adf91..80f1df746c 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteCentralRepo.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteCentralRepo.java @@ -78,8 +78,6 @@ final class SqliteCentralRepo extends RdbmsCentralRepo { private SqliteCentralRepo() throws CentralRepoException { dbSettings = new SqliteCentralRepoSettings(); bulkArtifactsThreshold = dbSettings.getBulkThreshold(); - - this.updateExaminers(); } @Override @@ -855,15 +853,6 @@ final class SqliteCentralRepo extends RdbmsCentralRepo { } } - @Override - public void updateExaminers() throws CentralRepoException { - try { - acquireSharedLock(); - super.updateExaminers(); - } finally { - releaseSharedLock(); - } - } /** * Check whether a reference set with the given name/version is in the diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties-MERGED index c8cebe69fc..4d4d3cf10f 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/Bundle.properties-MERGED @@ -17,7 +17,10 @@ ContextViewer.messageFrom=From ContextViewer.messageOn=On ContextViewer.messageTo=To ContextViewer.on=Opened at +ContextViewer.programExecution=Program Execution: ContextViewer.recentDocs=Recent Documents: +ContextViewer.runOn=Program Run On +ContextViewer.runUnknown=\ Program Run at unknown time ContextViewer.title=Context ContextViewer.toolTip=Displays context for selected file. ContextViewer.unknown=Opened at unknown time diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java index 7200f6747f..f7f1f6559e 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/contextviewer/ContextViewer.java @@ -334,7 +334,8 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte @NbBundle.Messages({ "ContextViewer.attachmentSource=Attached to: ", "ContextViewer.downloadSource=Downloaded from: ", - "ContextViewer.recentDocs=Recent Documents: " + "ContextViewer.recentDocs=Recent Documents: ", + "ContextViewer.programExecution=Program Execution: " }) private void setSourceFields(BlackboardArtifact associatedArtifact) throws TskCoreException { if (BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE.getTypeID() == associatedArtifact.getArtifactTypeID() @@ -357,6 +358,11 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte javax.swing.JPanel usagePanel = new ContextUsagePanel(sourceName, sourceText, associatedArtifact); contextUsagePanels.add(usagePanel); + } else if (BlackboardArtifact.ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID() == associatedArtifact.getArtifactTypeID()) { + String sourceName = Bundle.ContextViewer_programExecution(); + String sourceText = programExecArtifactToString(associatedArtifact); + javax.swing.JPanel usagePanel = new ContextUsagePanel(sourceName, sourceText, associatedArtifact); + contextUsagePanels.add(usagePanel); } } @@ -416,6 +422,36 @@ public final class ContextViewer extends javax.swing.JPanel implements DataConte return sb.toString(); } + /** + * Returns a display string with Program Execution + * artifact. + * + * @param artifact artifact to get doc from. + * + * @return Display string with download URL and date/time. + * + * @throws TskCoreException + */ + @NbBundle.Messages({ + "ContextViewer.runOn=Program Run On", + "ContextViewer.runUnknown= Program Run at unknown time" + }) + private String programExecArtifactToString(BlackboardArtifact artifact) throws TskCoreException { + StringBuilder sb = new StringBuilder(ARTIFACT_STR_MAX_LEN); + Map attributesMap = getAttributesMap(artifact); + + BlackboardAttribute attribute = attributesMap.get(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME); + + if (BlackboardArtifact.ARTIFACT_TYPE.TSK_PROG_RUN.getTypeID() == artifact.getArtifactTypeID()) { + if (attribute != null && attribute.getValueLong() > 0) { + appendAttributeString(sb, BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, attributesMap, Bundle.ContextViewer_runOn()); + } else { + sb.append(Bundle.ContextViewer_runUnknown()); + } + } + return sb.toString(); + } + /** * Returns a abbreviated display string for a message artifact. * diff --git a/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java b/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java index 02a5d2e2ab..f3fb273bcf 100644 --- a/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java +++ b/Core/src/org/sleuthkit/autopsy/events/AutopsyEventPublisher.java @@ -42,9 +42,9 @@ public final class AutopsyEventPublisher { private static final Logger logger = Logger.getLogger(AutopsyEventPublisher.class.getName()); private static final int MAX_REMOTE_EVENT_PUBLISH_TRIES = 1; private final LocalEventPublisher localPublisher; // LocalEventPublisher is thread-safe - @GuardedBy("this)") + @GuardedBy("this") private RemoteEventPublisher remotePublisher; - @GuardedBy("this)") + @GuardedBy("this") private String currentChannelName; /** diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoPersonasTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoPersonasTest.java index 141a23e66d..2b1d72534e 100644 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoPersonasTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoPersonasTest.java @@ -165,13 +165,8 @@ public class CentralRepoPersonasTest extends TestCase { Assert.fail("Failed to create central repo database, should be located at + " + crDbFilePath); } - // clear caches to match the clean slate database. - CentralRepository.getInstance().clearCaches(); - // Add current logged in user to examiners table - since we delete the DB after every test. - CentralRepository.getInstance().updateExaminers(); - - // Set up some default objects to be used by the tests + // Set up some default objects to be used by the tests try { case1 = new CorrelationCase(CASE_1_UUID, "case1"); case1 = CentralRepository.getInstance().newCase(case1); @@ -304,6 +299,9 @@ public class CentralRepoPersonasTest extends TestCase { Assert.assertEquals(DOG_PERSONA_NAME, pa1.getPersona().getName()); Assert.assertEquals(status.name(), dogPersona.getStatus().name()); Assert.assertTrue(dogPersona.getExaminer().getLoginName().equalsIgnoreCase(pa1.getExaminer().getLoginName())); + + // Assert that the persona was created by the currently logged in user + Assert.assertTrue(dogPersona.getExaminer().getLoginName().equalsIgnoreCase(System.getProperty("user.name"))); // Assert that Persona was created within the last 10 mins Assert.assertTrue(Instant.now().toEpochMilli() - pa1.getDateAdded() < 600 * 1000); @@ -371,7 +369,7 @@ public class CentralRepoPersonasTest extends TestCase { // Get ALL personas for an account - Collection personaAccounts2 = Persona.getPersonaAccountsForAccount(catdogFBAccount.getAccountId()); + Collection personaAccounts2 = PersonaAccount.getPersonaAccountsForAccount(catdogFBAccount.getAccountId()); Assert.assertEquals(2, personaAccounts2.size()); for (PersonaAccount pa: personaAccounts2) { @@ -525,21 +523,21 @@ public class CentralRepoPersonasTest extends TestCase { - Collection dogAccounts = dogPersona.getAccounts(); - Assert.assertEquals(2, dogAccounts.size()); // Dog has 2 accounts. - for (CentralRepoAccount acct : dogAccounts) { - Assert.assertTrue(acct.getTypeSpecificId().equalsIgnoreCase(FACEBOOK_ID_CATDOG) - || acct.getTypeSpecificId().equalsIgnoreCase(DOG_EMAIL_ID)); + Collection dogPersonaAccounts = dogPersona.getPersonaAccounts(); + Assert.assertEquals(2, dogPersonaAccounts.size()); // Dog has 2 accounts. + for (PersonaAccount pa : dogPersonaAccounts) { + Assert.assertTrue(pa.getAccount().getTypeSpecificId().equalsIgnoreCase(FACEBOOK_ID_CATDOG) + || pa.getAccount().getTypeSpecificId().equalsIgnoreCase(DOG_EMAIL_ID)); // System.out.println("Dog Account id : " + acct.getTypeSpecificId()); } - Collection catAccounts = catPersona.getAccounts(); - Assert.assertEquals(2, catAccounts.size()); // cat has 2 accounts. - for (CentralRepoAccount acct:catAccounts) { + Collection catPersonaAccounts = catPersona.getPersonaAccounts(); + Assert.assertEquals(2, catPersonaAccounts.size()); // cat has 2 accounts. + for (PersonaAccount pa:catPersonaAccounts) { //System.out.println("Cat Account id : " + acct.getTypeSpecificId()); - Assert.assertTrue(acct.getTypeSpecificId().equalsIgnoreCase(FACEBOOK_ID_CATDOG) - || acct.getTypeSpecificId().equalsIgnoreCase(CAT_WHATSAPP_ID)); + Assert.assertTrue(pa.getAccount().getTypeSpecificId().equalsIgnoreCase(FACEBOOK_ID_CATDOG) + || pa.getAccount().getTypeSpecificId().equalsIgnoreCase(CAT_WHATSAPP_ID)); } // create account and Persona for Sherlock Holmes. @@ -644,22 +642,22 @@ public class CentralRepoPersonasTest extends TestCase { // Test getting peronas by data source. // Test that getting all Personas for DS 1 - Collection ds1Persona = Persona.getPersonaForDataSource(dataSource1fromCase1); + Collection ds1Persona = Persona.getPersonasForDataSource(dataSource1fromCase1); Assert.assertEquals(2, ds1Persona.size()); // - Collection ds2Persona = Persona.getPersonaForDataSource(dataSource2fromCase1); + Collection ds2Persona = Persona.getPersonasForDataSource(dataSource2fromCase1); Assert.assertEquals(2, ds2Persona.size()); // - Collection ds3Persona = Persona.getPersonaForDataSource(dataSource1fromCase2); + Collection ds3Persona = Persona.getPersonasForDataSource(dataSource1fromCase2); Assert.assertEquals(2, ds3Persona.size()); // - Collection ds4Persona = Persona.getPersonaForDataSource(dataSource1fromCase3); + Collection ds4Persona = Persona.getPersonasForDataSource(dataSource1fromCase3); Assert.assertEquals(1, ds4Persona.size()); // - Collection ds5Persona = Persona.getPersonaForDataSource(dataSource2fromCase3); + Collection ds5Persona = Persona.getPersonasForDataSource(dataSource2fromCase3); Assert.assertEquals(0, ds5Persona.size()); // - Collection ds6Persona = Persona.getPersonaForDataSource(dataSource1fromCase4); + Collection ds6Persona = Persona.getPersonasForDataSource(dataSource1fromCase4); Assert.assertEquals(0, ds6Persona.size()); // @@ -687,7 +685,7 @@ public class CentralRepoPersonasTest extends TestCase { Persona.PersonaStatus.ACTIVE, emailAccount1, "The person lost his name", Persona.Confidence.LOW); // Verify Persona has a default name - Assert.assertEquals("NoName", pa1.getPersona().getName()); + Assert.assertEquals("Unknown", pa1.getPersona().getName()); } catch (CentralRepoException ex) { Assert.fail("No name persona test failed. Exception: " + ex); @@ -695,5 +693,212 @@ public class CentralRepoPersonasTest extends TestCase { } + } + + /** + * Tests searching of Persona by persona name. + */ + public void testPersonaSearchByName() { + + // Test1: create Personas with similar names. + { + try { + // Create an email account + CentralRepoAccount emailAccount1 = CentralRepository.getInstance() + .getOrCreateAccount(emailAccountType, EMAIL_ID_1); + + // Create all personas with same comment. + final String personaComment = "Creator of Jungle Book."; + + // Create a Persona with name "Rudyard Kipling" + Persona.createPersonaForAccount("Rudyard Kipling", personaComment, + Persona.PersonaStatus.ACTIVE, emailAccount1, "", Persona.Confidence.LOW); + + // Create a Persona with name "Rudy" + Persona.createPersonaForAccount("Rudy", personaComment, + Persona.PersonaStatus.ACTIVE, emailAccount1, "", Persona.Confidence.LOW); + + + // Create a Persona with name "Kipling Senior" + Persona.createPersonaForAccount("Kipling Senior", personaComment, + Persona.PersonaStatus.ACTIVE, emailAccount1, "", Persona.Confidence.LOW); + + // Create a Persona with name "Senor Kipling" + Persona.createPersonaForAccount("Senor Kipling", personaComment, + Persona.PersonaStatus.ACTIVE, emailAccount1, "", Persona.Confidence.LOW); + + + // Test 1 Search "kipling" - expect 3 matches + Collection personaSearchResult = Persona.getPersonaByName("kipling"); + Assert.assertEquals(3, personaSearchResult.size()); + for (Persona p: personaSearchResult) { + Assert.assertTrue(p.getComment().equalsIgnoreCase(personaComment)); + } + + // Search 'Rudy' - expect 2 matches + personaSearchResult = Persona.getPersonaByName("Rudy"); + Assert.assertEquals(2, personaSearchResult.size()); + + + // Search 'Sen' - expect 2 matches + personaSearchResult = Persona.getPersonaByName("Sen"); + Assert.assertEquals(2, personaSearchResult.size()); + + + // Search 'IPL' - expect 3 matches + personaSearchResult = Persona.getPersonaByName("IPL"); + Assert.assertEquals(3, personaSearchResult.size()); + + + // Serach "Rudyard Kipling" - expect 1 match + personaSearchResult = Persona.getPersonaByName("Rudyard Kipling"); + Assert.assertEquals(1, personaSearchResult.size()); + Assert.assertTrue(personaSearchResult.iterator().next().getName().equalsIgnoreCase("Rudyard Kipling")); + + // Search '' - expect ALL (4) to match + personaSearchResult = Persona.getPersonaByName(""); + Assert.assertEquals(4, personaSearchResult.size()); + + + } catch (CentralRepoException ex) { + Assert.fail("No name persona test failed. Exception: " + ex); + } + } + + + } + + + /** + * Tests searching of Persona by account identifier substrings. + */ + public void testPersonaSearchByAccountIdentifier() { + + // Test1: create Personas with similar names. + { + try { + // Create an email account1 + CentralRepoAccount emailAccount1 = CentralRepository.getInstance() + .getOrCreateAccount(emailAccountType, "joeexotic555@yahoo.com"); + + // Create all personas with same comment. + final String personaComment = "Comment used to create a persona"; + + // Create a Persona with name "Joe Exotic" associated with the email address + Persona.createPersonaForAccount("Joe Exotic", personaComment, + Persona.PersonaStatus.ACTIVE, emailAccount1, "", Persona.Confidence.LOW); + + // Create a Persona with name "Tiger King" associated with the email address + Persona.createPersonaForAccount("Tiger King", personaComment, + Persona.PersonaStatus.ACTIVE, emailAccount1, "", Persona.Confidence.LOW); + + + + // Create an phone account with number "+1 999 555 3366" + CentralRepoAccount phoneAccount1 = CentralRepository.getInstance() + .getOrCreateAccount(phoneAccountType, "+1 999 555 3366"); + + + // Create a Persona with name "Carol Baskin" associated + Persona.createPersonaForAccount("Carol Baskin", personaComment, + Persona.PersonaStatus.ACTIVE, phoneAccount1, "", Persona.Confidence.LOW); + + // Create a Persona with no name assoctaed with + Persona.createPersonaForAccount(null, personaComment, + Persona.PersonaStatus.ACTIVE, phoneAccount1, "", Persona.Confidence.LOW); + + + + // Create another email account1 + CentralRepoAccount emailAccount2 = CentralRepository.getInstance() + .getOrCreateAccount(emailAccountType, "jodoe@mail.com"); + + + + // Create a Persona with name "John Doe" associated with the email address + Persona.createPersonaForAccount("John Doe", personaComment, + Persona.PersonaStatus.ACTIVE, emailAccount2, "", Persona.Confidence.LOW); + + Persona.createPersonaForAccount("Joanne Doe", personaComment, + Persona.PersonaStatus.ACTIVE, emailAccount2, "", Persona.Confidence.LOW); + + + + // Test1 Search on 'joe' - should get 2 + Collection personaSearchResult = PersonaAccount.getPersonaAccountsForAccountIdentifier("joe"); + Assert.assertEquals(2, personaSearchResult.size()); + for (PersonaAccount pa: personaSearchResult) { + Assert.assertTrue(pa.getAccount().getTypeSpecificId().contains("joe")); + } + + // Search on 'exotic' - should get 2 + personaSearchResult = PersonaAccount.getPersonaAccountsForAccountIdentifier("exotic"); + Assert.assertEquals(2, personaSearchResult.size()); + for (PersonaAccount pa: personaSearchResult) { + Assert.assertTrue(pa.getAccount().getTypeSpecificId().contains("exotic")); + } + + // Test1 Search on '999' - should get 2 + personaSearchResult = PersonaAccount.getPersonaAccountsForAccountIdentifier("999"); + Assert.assertEquals(2, personaSearchResult.size()); + for (PersonaAccount pa: personaSearchResult) { + Assert.assertTrue(pa.getAccount().getTypeSpecificId().contains("999")); + } + + // Test1 Search on '555' - should get 4 + personaSearchResult = PersonaAccount.getPersonaAccountsForAccountIdentifier("555"); + Assert.assertEquals(4, personaSearchResult.size()); + for (PersonaAccount pa: personaSearchResult) { + Assert.assertTrue(pa.getAccount().getTypeSpecificId().contains("555")); + } + + // Test1 Search on 'doe' - should get 2 + personaSearchResult = PersonaAccount.getPersonaAccountsForAccountIdentifier("doe"); + Assert.assertEquals(2, personaSearchResult.size()); + for (PersonaAccount pa: personaSearchResult) { + Assert.assertTrue(pa.getAccount().getTypeSpecificId().contains("doe")); + } + + // Test1 Search on '@' - should get 4 + personaSearchResult = PersonaAccount.getPersonaAccountsForAccountIdentifier("@"); + Assert.assertEquals(4, personaSearchResult.size()); + for (PersonaAccount pa: personaSearchResult) { + Assert.assertTrue(pa.getAccount().getTypeSpecificId().contains("@")); + } + + // Test1 Search on '' - should get ALL (6) + personaSearchResult = PersonaAccount.getPersonaAccountsForAccountIdentifier(""); + Assert.assertEquals(6, personaSearchResult.size()); + + + } catch (CentralRepoException ex) { + Assert.fail("No name persona test failed. Exception: " + ex); + } + } + + } + + /** + * Tests the getOrInsertExaminer() api. + */ + public void testExaminers() { + + try { + String examinerName = "abcdefg"; + CentralRepoExaminer examiner = CentralRepository.getInstance().getOrInsertExaminer(examinerName); + Assert.assertTrue(examiner.getLoginName().equalsIgnoreCase(examinerName)); + + examinerName = ""; + examiner = CentralRepository.getInstance().getOrInsertExaminer(examinerName); + Assert.assertTrue(examiner.getLoginName().equalsIgnoreCase(examinerName)); + + examinerName = "D'Aboville"; + examiner = CentralRepository.getInstance().getOrInsertExaminer(examinerName); + Assert.assertTrue(examiner.getLoginName().equalsIgnoreCase(examinerName)); + + } catch (CentralRepoException ex) { + Assert.fail("Examiner tests failed. Exception: " + ex); + } + } } diff --git a/RecentActivity/build.xml b/RecentActivity/build.xml index d298fa519a..4b3d8e3347 100644 --- a/RecentActivity/build.xml +++ b/RecentActivity/build.xml @@ -22,6 +22,9 @@ + + + diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED index 35666d6973..310602b0f9 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/Bundle.properties-MERGED @@ -55,6 +55,13 @@ ExtractSafari_Error_Getting_History=An error occurred while processing Safari hi ExtractSafari_Error_Parsing_Bookmark=An error occured while processing Safari Bookmark files ExtractSafari_Error_Parsing_Cookies=An error occured while processing Safari Cookies files ExtractSafari_Module_Name=Safari +ExtractSru_error_finding_export_srudb_program=Error finding export_srudb program +ExtractSru_module_name=System Resource Usage Extractor +ExtractSru_process_error_executing_export_srudb_program=Error running export_srudb program +ExtractSru_process_errormsg_find_software_hive=Unable to find SOFTWARE HIVE file +ExtractSru_process_errormsg_find_srudb_dat=Unable to find srudb.dat file +ExtractSru_process_errormsg_write_software_hive=Unable to write SOFTWARE HIVE file +ExtractSru_process_errormsg_write_srudb_dat=Unable to write srudb.dat file ExtractZone_Internet=Internet Zone ExtractZone_Local_Intranet=Local Intranet Zone ExtractZone_Local_Machine=Local Machine Zone diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractSru.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractSru.java new file mode 100644 index 0000000000..08782097bf --- /dev/null +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractSru.java @@ -0,0 +1,484 @@ + /* + * + * Autopsy Forensic Browser + * + * Copyright 2020 Basis Technology Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.recentactivity; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.logging.Level; +import java.util.Map; +import org.apache.commons.io.FilenameUtils; +import org.openide.modules.InstalledFileLocator; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.FileManager; +import org.sleuthkit.autopsy.coreutils.ExecUtil; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.coreutils.SQLiteDBConnect; +import org.sleuthkit.autopsy.datamodel.ContentUtils; +import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProcessTerminator; +import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress; +import org.sleuthkit.autopsy.ingest.IngestJobContext; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Blackboard; +import org.sleuthkit.datamodel.BlackboardArtifact; +import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_ASSOCIATED_OBJECT; +import org.sleuthkit.datamodel.BlackboardAttribute; +import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.TskCoreException; + + +/** + * Extract the System Resource Usage database to a temp directory so it can be parsed into a SQLite db + * and then brought into extracted content + */ +final class ExtractSru extends Extract { + + private static final Logger logger = Logger.getLogger(ExtractSru.class.getName()); + + private IngestJobContext context; + + private static final String APPLICATION_USAGE_SOURCE_NAME = "System Resource Usage - Application Usage"; //NON-NLS + private static final String NETWORK_USAGE_SOURCE_NAME = "System Resource Usage - Network Usage"; + +// private static final String ARTIFACT_ATTRIBUTE_NAME = "TSK_ARTIFACT_NAME"; //NON-NLS + + private static final String MODULE_NAME = "extractSRU"; //NON-NLS + + private static final String SRU_TOOL_FOLDER = "markmckinnon"; //NON-NLS + private static final String SRU_TOOL_NAME_WINDOWS_32 = "Export_Srudb_32.exe"; //NON-NLS + private static final String SRU_TOOL_NAME_WINDOWS_64 = "Export_Srudb_64.exe"; //NON-NLS + private static final String SRU_TOOL_NAME_LINUX = "Export_Srudb_Linux.exe"; //NON-NLS + private static final String SRU_TOOL_NAME_MAC = "Export_srudb_macos"; //NON-NLS + private static final String SRU_OUTPUT_FILE_NAME = "Output.txt"; //NON-NLS + private static final String SRU_ERROR_FILE_NAME = "Error.txt"; //NON-NLS + + private static final Map applicationFilesFound = new HashMap<>(); + + @Messages({ + "ExtractSru_module_name=System Resource Usage Extractor" + }) + ExtractSru() { + this.moduleName = Bundle.ExtractSru_module_name(); + } + + @Messages({ + "ExtractSru_error_finding_export_srudb_program=Error finding export_srudb program", + "ExtractSru_process_error_executing_export_srudb_program=Error running export_srudb program" + }) + + @Override + void process(Content dataSource, IngestJobContext context, DataSourceIngestModuleProgress progressBar) { + + this.context = context; + + String modOutPath = Case.getCurrentCase().getModuleDirectory() + File.separator + "sru"; + File dir = new File(modOutPath); + if (dir.exists() == false) { + dir.mkdirs(); + } + + String tempDirPath = RAImageIngestModule.getRATempPath(Case.getCurrentCase(), "sru"); //NON-NLS + String softwareHiveFileName = getSoftwareHiveFile(dataSource, tempDirPath); + + if (softwareHiveFileName == null) { + return; + } + + AbstractFile sruAbstractFile = getSruFile(dataSource, tempDirPath); + + String sruFileName = tempDirPath + File.separator + sruAbstractFile.getId() + "_" + sruAbstractFile.getName(); + + if (sruFileName == null) { + this.addErrorMessage(Bundle.ExtractSru_process_errormsg_find_srudb_dat()); + logger.log(Level.SEVERE, "SRUDB.dat file not found"); //NON-NLS + return; //If we cannot find the srudb.dat file we cannot proceed + } + + final String sruDumper = getPathForSruDumper(); + if (sruDumper == null) { + this.addErrorMessage(Bundle.ExtractSru_error_finding_export_srudb_program()); + logger.log(Level.SEVERE, "Error finding export_srudb program"); //NON-NLS + return; //If we cannot find the export_srudb program we cannot proceed + } + + if (context.dataSourceIngestIsCancelled()) { + return; + } + + try { + String modOutFile = modOutPath + File.separator + sruAbstractFile.getId() + "_srudb.db3"; + + extractSruFiles(sruDumper, sruFileName, modOutFile, tempDirPath, softwareHiveFileName); + + findSruExecutedFiles(modOutFile, dataSource); + + createNetUsageArtifacts(modOutFile, sruAbstractFile); + createAppUsageArtifacts(modOutFile, sruAbstractFile); + } catch (IOException ex) { + this.addErrorMessage(Bundle.ExtractSru_process_error_executing_export_srudb_program()); + logger.log(Level.SEVERE, "SRUDB.dat file not found"); //NON-NLS + } + } + + @Messages({ + "ExtractSru_process_errormsg_find_software_hive=Unable to find SOFTWARE HIVE file", + "ExtractSru_process_errormsg_write_software_hive=Unable to write SOFTWARE HIVE file" + }) + + /** + * Extract the SOFTWARE hive file to the temp directory + * + * @param dataSource datasource where software hiive is + * @param tempDirPath temp directory to write file to + * + * @return Software hive file location + */ + String getSoftwareHiveFile(Content dataSource, String tempDirPath) { + FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); + + List softwareHiveFiles; + + try { + softwareHiveFiles = fileManager.findFiles(dataSource, "SOFTWARE"); //NON-NLS + } catch (TskCoreException ex) { + this.addErrorMessage(Bundle.ExtractSru_process_errormsg_find_software_hive()); + logger.log(Level.WARNING, "Unable to find SOFTWARE HIVE file.", ex); //NON-NLS + return null; // No need to continue + } + + String softwareHiveFileName = null; + + for (AbstractFile softwareFile : softwareHiveFiles) { + + if (softwareFile.getParentPath().endsWith("/config/")) { + softwareHiveFileName = tempDirPath + File.separator + softwareFile.getId() + "_" + softwareFile.getName(); + + try { + ContentUtils.writeToFile(softwareFile, new File(softwareHiveFileName)); + } catch (IOException ex) { + this.addErrorMessage(Bundle.ExtractSru_process_errormsg_find_software_hive()); + logger.log(Level.WARNING, String.format("Unable to write %s to temp directory. File name: %s", softwareFile.getName(), softwareFile), ex); //NON-NLS + return null; + } + } + } + return softwareHiveFileName; + } + + @Messages({ + "ExtractSru_process_errormsg_find_srudb_dat=Unable to find srudb.dat file", + "ExtractSru_process_errormsg_write_srudb_dat=Unable to write srudb.dat file" + }) + /** + * Extract the SOFTWARE hive file to the temp directory + * + * @param dataSource datasource where software hiive is + * @param tempDirPath temp directory to write file to + * + * @return Software hive file location + */ + AbstractFile getSruFile(Content dataSource, String tempDirPath) { + FileManager fileManager = Case.getCurrentCase().getServices().getFileManager(); + + List sruFiles; + + try { + sruFiles = fileManager.findFiles(dataSource, "SRUDB.DAT"); //NON-NLS + } catch (TskCoreException ex) { + this.addErrorMessage(Bundle.ExtractSru_process_errormsg_find_srudb_dat()); + logger.log(Level.WARNING, "Unable to find SRUDB.DAT file.", ex); //NON-NLS + return null; // No need to continue + } + + AbstractFile sruAbstractFile = null; + + for (AbstractFile sruFile : sruFiles) { + + String sruFileName = tempDirPath + File.separator + sruFile.getId() + "_" + sruFile.getName(); + sruAbstractFile = sruFile; + + try { + ContentUtils.writeToFile(sruFile, new File(sruFileName)); + } catch (IOException ex) { + this.addErrorMessage(Bundle.ExtractSru_process_errormsg_write_srudb_dat()); + logger.log(Level.WARNING, String.format("Unable to write %s to temp directory. File name: %s", sruFile.getName(), sruFile), ex); //NON-NLS + return null; + } + + } + return sruAbstractFile; + } + + /** + * Run the export srudb program against the srudb.dat file + * + * @param sruExePath + * @param tempDirPath + * @param tempOutPath + * + * @throws FileNotFoundException + * @throws IOException + */ + void extractSruFiles(String sruExePath, String sruFile, String tempOutFile, String tempOutPath, String softwareHiveFile) throws IOException { + final Path outputFilePath = Paths.get(tempOutPath, SRU_OUTPUT_FILE_NAME); + final Path errFilePath = Paths.get(tempOutPath, SRU_ERROR_FILE_NAME); + + List commandLine = new ArrayList<>(); + commandLine.add(sruExePath); + commandLine.add(sruFile); //NON-NLS + commandLine.add(softwareHiveFile); + commandLine.add(tempOutFile); + + ProcessBuilder processBuilder = new ProcessBuilder(commandLine); + processBuilder.redirectOutput(outputFilePath.toFile()); + processBuilder.redirectError(errFilePath.toFile()); + + ExecUtil.execute(processBuilder, new DataSourceIngestModuleProcessTerminator(context)); + } + + private String getPathForSruDumper() { + Path path = null; + if (PlatformUtil.isWindowsOS()) { + if (PlatformUtil.is64BitOS()) { + path = Paths.get(SRU_TOOL_FOLDER, SRU_TOOL_NAME_WINDOWS_64); + } else { + path = Paths.get(SRU_TOOL_FOLDER, SRU_TOOL_NAME_WINDOWS_32); + } + } else { + if ("Linux".equals(PlatformUtil.getOSName())) { + path = Paths.get(SRU_TOOL_FOLDER, SRU_TOOL_NAME_LINUX); + } else { + path = Paths.get(SRU_TOOL_FOLDER, SRU_TOOL_NAME_MAC); + } + } + File sruToolFile = InstalledFileLocator.getDefault().locate(path.toString(), + ExtractSru.class.getPackage().getName(), false); + if (sruToolFile != null) { + return sruToolFile.getAbsolutePath(); + } + + return null; + } + + private void findSruExecutedFiles(String sruDb, Content dataSource) { + + org.sleuthkit.autopsy.casemodule.services.FileManager fileManager = currentCase.getServices().getFileManager(); + + String sqlStatement = "SELECT DISTINCT SUBSTR(LTRIM(IdBlob, '\\Device\\HarddiskVolume'), INSTR(LTRIM(IdBlob, '\\Device\\HarddiskVolume'), '\\')) " + + " application_name, idBlob source_name FROM SruDbIdMapTable WHERE idType = 0 AND idBlob NOT LIKE '!!%'"; //NON-NLS + + try (SQLiteDBConnect tempdbconnect = new SQLiteDBConnect("org.sqlite.JDBC", "jdbc:sqlite:" + sruDb); //NON-NLS + ResultSet resultSet = tempdbconnect.executeQry(sqlStatement)) { + + while (resultSet.next()) { + + if (context.dataSourceIngestIsCancelled()) { + logger.log(Level.INFO, "Cancelled SRU Artifact Creation."); //NON-NLS + return; + } + + String applicationName = resultSet.getString("application_name"); //NON-NLS + String sourceName = resultSet.getString("source_name"); //NON-NLS + + String normalizePathName = FilenameUtils.normalize(applicationName, true); + String fileName = FilenameUtils.getName(normalizePathName); + String filePath = FilenameUtils.getPath(normalizePathName); + if (fileName.contains(" [")) { + fileName = fileName.substring(0, fileName.indexOf(" [")); + } + List sourceFiles; + try { + sourceFiles = fileManager.findFiles(dataSource, fileName, filePath); //NON-NLS + for (AbstractFile sourceFile : sourceFiles) { + if (sourceFile.getParentPath().endsWith(filePath)) { + applicationFilesFound.put(sourceName.toLowerCase(), sourceFile); + } + } + + } catch (TskCoreException ex) { + logger.log(Level.WARNING, String.format("Error finding actual file %s. file may not exist", normalizePathName)); //NON-NLS + } + } + } catch (SQLException ex) { + logger.log(Level.WARNING, "Error while trying to read into a sqlite db.", ex);//NON-NLS + } + + } + + private void createNetUsageArtifacts(String sruDb, AbstractFile sruAbstractFile) { + List bba = new ArrayList<>(); + + String sqlStatement = "SELECT STRFTIME('%s', timestamp) ExecutionTime, Application_Name, User_Name, " + + " bytesSent, BytesRecvd FROM network_Usage , SruDbIdMapTable " + + " where appId = IdIndex and IdType = 0 order by ExecutionTime;"; //NON-NLS + + try (SQLiteDBConnect tempdbconnect = new SQLiteDBConnect("org.sqlite.JDBC", "jdbc:sqlite:" + sruDb); //NON-NLS + ResultSet resultSet = tempdbconnect.executeQry(sqlStatement)) { + + while (resultSet.next()) { + + if (context.dataSourceIngestIsCancelled()) { + logger.log(Level.INFO, "Cancelled SRU Net Usage Artifact Creation."); //NON-NLS + return; + } + + String applicationName = resultSet.getString("Application_Name"); //NON-NLS + Long executionTime = Long.valueOf(resultSet.getInt("ExecutionTime")); //NON-NLS + Long bytesSent = Long.valueOf(resultSet.getInt("bytesSent")); //NON-NLS + Long bytesRecvd = Long.valueOf(resultSet.getInt("BytesRecvd")); //NON-NLS + String userName = resultSet.getString("User_Name"); //NON-NLS + + Collection bbattributes = Arrays.asList( + new BlackboardAttribute( + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, getName(), + applicationName),//NON-NLS + new BlackboardAttribute( + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME, getName(), + userName), + new BlackboardAttribute( + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, getName(), + executionTime), + new BlackboardAttribute( + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_BYTES_SENT, getName(), bytesSent), + new BlackboardAttribute( + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_BYTES_RECEIVED, getName(), bytesRecvd), + new BlackboardAttribute( + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, getName(), NETWORK_USAGE_SOURCE_NAME)); + + try { + BlackboardArtifact bbart = sruAbstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_PROG_RUN); + bbart.addAttributes(bbattributes); + bba.add(bbart); + BlackboardArtifact associateBbArtifact = createAssociatedArtifact(applicationName.toLowerCase(), bbart); + if (associateBbArtifact != null) { + bba.add(associateBbArtifact); + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Exception Adding Artifact.", ex);//NON-NLS + } + } + + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Error while trying to read into a sqlite db.", ex);//NON-NLS + } + + try { + blackboard.postArtifacts(bba, MODULE_NAME); + } catch (Blackboard.BlackboardException ex) { + logger.log(Level.SEVERE, "Error Posting Artifact.", ex);//NON-NLS + } + } + + private void createAppUsageArtifacts(String sruDb, AbstractFile sruAbstractFile) { + List bba = new ArrayList<>(); + + String sqlStatement = "SELECT STRFTIME('%s', timestamp) ExecutionTime, Application_Name, User_Name " + + " FROM Application_Resource_Usage, SruDbIdMapTable WHERE " + + " idType = 0 and idIndex = appId order by ExecutionTime;"; //NON-NLS + + try (SQLiteDBConnect tempdbconnect = new SQLiteDBConnect("org.sqlite.JDBC", "jdbc:sqlite:" + sruDb); //NON-NLS + ResultSet resultSet = tempdbconnect.executeQry(sqlStatement)) { + + while (resultSet.next()) { + + if (context.dataSourceIngestIsCancelled()) { + logger.log(Level.INFO, "Cancelled SRU Net Usage Artifact Creation."); //NON-NLS + return; + } + + String applicationName = resultSet.getString("Application_Name"); //NON-NLS + Long executionTime = Long.valueOf(resultSet.getInt("ExecutionTime")); //NON-NLS + String userName = resultSet.getString("User_Name"); + + Collection bbattributes = Arrays.asList( + new BlackboardAttribute( + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, getName(), + applicationName),//NON-NLS + new BlackboardAttribute( + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_USER_NAME, getName(), + userName), + new BlackboardAttribute( + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, getName(), + executionTime), + new BlackboardAttribute( + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, getName(), APPLICATION_USAGE_SOURCE_NAME)); + + try { + BlackboardArtifact bbart = sruAbstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_PROG_RUN); + bbart.addAttributes(bbattributes); + bba.add(bbart); + BlackboardArtifact associateBbArtifact = createAssociatedArtifact(applicationName.toLowerCase(), bbart); + if (associateBbArtifact != null) { + bba.add(associateBbArtifact); + } + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Exception Adding Artifact.", ex);//NON-NLS + } + } + + } catch (SQLException ex) { + logger.log(Level.SEVERE, "Error while trying to read into a sqlite db.", ex);//NON-NLS + } + + try { + blackboard.postArtifacts(bba, MODULE_NAME); + } catch (Blackboard.BlackboardException ex) { + logger.log(Level.SEVERE, "Error Posting Artifact.", ex);//NON-NLS + } + } + + /** + * Create associated artifacts using file path name and the artifact it associates with + * + * @param filePathName file and path of object being associated with + * + * @param bba blackboard artifact to associate with + * + * @returnv BlackboardArtifact or a null value + */ + private BlackboardArtifact createAssociatedArtifact(String filePathName, BlackboardArtifact bba) { + if (applicationFilesFound.containsKey(filePathName)) { + AbstractFile sourceFile = applicationFilesFound.get(filePathName); + Collection bbattributes2 = new ArrayList<>(); + bbattributes2.addAll(Arrays.asList( + new BlackboardAttribute(TSK_ASSOCIATED_ARTIFACT, this.getName(), + bba.getArtifactID()))); + + BlackboardArtifact associatedObjectBba = createArtifactWithAttributes(TSK_ASSOCIATED_OBJECT, sourceFile, bbattributes2); + if (associatedObjectBba != null) { + return associatedObjectBba; + } + } + + return null; + } + +} diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java index 444a6d638d..c5cb62a779 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/RAImageIngestModule.java @@ -78,6 +78,7 @@ public final class RAImageIngestModule implements DataSourceIngestModule { Extract safari = new ExtractSafari(); Extract zoneInfo = new ExtractZoneIdentifier(); Extract recycleBin = new ExtractRecycleBin(); + Extract sru = new ExtractSru(); extractors.add(chrome); extractors.add(firefox); @@ -91,7 +92,8 @@ public final class RAImageIngestModule implements DataSourceIngestModule { extractors.add(dataSourceAnalyzer); //this needs to run after ExtractRegistry and ExtractOs extractors.add(zoneInfo); // this needs to run after the web browser modules extractors.add(recycleBin); // this needs to run after ExtractRegistry and ExtractOS - + extractors.add(sru); + browserExtractors.add(chrome); browserExtractors.add(firefox); browserExtractors.add(iexplore); diff --git a/appveyor.yml b/appveyor.yml index d7cba33584..b3cbb4032c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,7 +19,6 @@ environment: LIBVHDI_HOME: "C:\\libvhdi_64bit" LIBVMDK_HOME: "C:\\libvmdk_64bit\\libvmdk" LIBEWF_HOME: "C:\\libewf_64bit" - POSTGRESQL_HOME_64: "C:\\Program Files\\PostgreSQL\\9.5" JDK_HOME: C:\Program Files\Java\jdk1.8.0 PYTHON: "C:\\Python36-x64" @@ -41,7 +40,7 @@ build_script: - python win32\updateAndBuildAll.py -m - ps: pushd bindings/java - ps: ant -version - - cmd: ant dist-PostgreSQL + - cmd: ant dist - ps: popd - cd %APPVEYOR_BUILD_FOLDER% - cmd: ant -q build diff --git a/thirdparty/markmckinnon/Export_Srudb_Linux b/thirdparty/markmckinnon/Export_Srudb_Linux new file mode 100644 index 0000000000..0af32da85b Binary files /dev/null and b/thirdparty/markmckinnon/Export_Srudb_Linux differ diff --git a/thirdparty/markmckinnon/Export_srudb_macos b/thirdparty/markmckinnon/Export_srudb_macos new file mode 100644 index 0000000000..eeff65b668 Binary files /dev/null and b/thirdparty/markmckinnon/Export_srudb_macos differ diff --git a/thirdparty/markmckinnon/LICENSE-2.0.txt b/thirdparty/markmckinnon/LICENSE-2.0.txt new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/thirdparty/markmckinnon/LICENSE-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/thirdparty/markmckinnon/export_srudb_32.exe b/thirdparty/markmckinnon/export_srudb_32.exe new file mode 100644 index 0000000000..e642c1d8df Binary files /dev/null and b/thirdparty/markmckinnon/export_srudb_32.exe differ diff --git a/thirdparty/markmckinnon/export_srudb_64.exe b/thirdparty/markmckinnon/export_srudb_64.exe new file mode 100644 index 0000000000..7b07367739 Binary files /dev/null and b/thirdparty/markmckinnon/export_srudb_64.exe differ diff --git a/travis_build.sh b/travis_build.sh index f7b7cfb72d..5f574d5726 100755 --- a/travis_build.sh +++ b/travis_build.sh @@ -4,7 +4,7 @@ set -e echo "Building TSK..." cd sleuthkit/sleuthkit ./bootstrap && ./configure --prefix=/usr && make -pushd bindings/java && ant -q dist-PostgreSQL && popd +pushd bindings/java && ant -q dist && popd echo "Building Autopsy..." && echo -en 'travis_fold:start:script.build\\r' cd $TRAVIS_BUILD_DIR/ diff --git a/unix_setup.sh b/unix_setup.sh index 2a75ab72c7..edd6c36632 100644 --- a/unix_setup.sh +++ b/unix_setup.sh @@ -57,13 +57,13 @@ fi ext_jar_filepath=$PWD/autopsy/modules/ext/sleuthkit-$TSK_VERSION.jar; echo -n "Copying sleuthkit-$TSK_VERSION.jar into the Autopsy directory..." -rm -f $ext_jar_filepath; +rm -f "$ext_jar_filepath"; if [ "$?" -gt 0 ]; then #checking if remove operation failed echo "ERROR: Deleting $ext_jar_filepath failed." echo "Please check your permissions." exit 1 else - cp $sleuthkit_jar_filepath $ext_jar_filepath + cp $sleuthkit_jar_filepath "$ext_jar_filepath" if [ "$?" -ne 0 ]; then # checking copy operation was successful echo "ERROR: Copying $sleuthkit_jar_filepath to $ext_jar_filepath failed." echo "Please check your permissions."