diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/CtApiDAO.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/CtApiDAO.java index 061f8a83e0..dcb0f823a7 100644 --- a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/CtApiDAO.java +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/CtApiDAO.java @@ -16,9 +16,10 @@ package com.basistech.df.cybertriage.autopsy.ctapi; import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenRequest; import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenResponse; import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthenticatedRequestData; +import com.basistech.df.cybertriage.autopsy.ctapi.json.CTCloudBean; +import com.basistech.df.cybertriage.autopsy.ctapi.json.CTCloudBeanResponse; +import com.basistech.df.cybertriage.autopsy.ctapi.json.DecryptedLicenseResponse; import com.basistech.df.cybertriage.autopsy.ctapi.json.FileReputationRequest; -import com.basistech.df.cybertriage.autopsy.ctapi.json.FileReputationResponse; -import com.basistech.df.cybertriage.autopsy.ctapi.json.FileReputationResult; import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseRequest; import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseResponse; import com.basistech.df.cybertriage.autopsy.ctapi.util.CTHostIDGenerationUtil; @@ -65,16 +66,17 @@ public class CTApiDAO { } - public AuthTokenResponse getAuthToken(String boostLicenseId) throws CTCloudException { + public AuthTokenResponse getAuthToken(DecryptedLicenseResponse decrypted) throws CTCloudException { AuthTokenRequest authTokenRequest = new AuthTokenRequest() .setAutopsyVersion(getAppVersion()) - .setRequestFileUpload(true) - .setBoostLicenseId(boostLicenseId); + .setRequestFileUpload(false) + .setBoostLicenseId(decrypted.getBoostLicenseId()) + .setHostId(decrypted.getLicenseHostId()); return httpClient.doPost(AUTH_TOKEN_REQUEST_PATH, authTokenRequest, AuthTokenResponse.class); } - public List getReputationResults(AuthenticatedRequestData authenticatedRequestData, List md5Hashes) throws CTCloudException { + public List getReputationResults(AuthenticatedRequestData authenticatedRequestData, List md5Hashes) throws CTCloudException { if (CollectionUtils.isEmpty(md5Hashes)) { return Collections.emptyList(); } @@ -85,7 +87,7 @@ public class CTApiDAO { .setToken(authenticatedRequestData.getToken()) .setHashes(md5Hashes); - FileReputationResponse resp = httpClient.doPost(CTCLOUD_SERVER_HASH_PATH, fileRepReq, FileReputationResponse.class); + CTCloudBeanResponse resp = httpClient.doPost(CTCLOUD_SERVER_HASH_PATH, fileRepReq, CTCloudBeanResponse.class); return resp == null || resp.getItems() == null ? Collections.emptyList() : resp.getItems(); diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/AuthTokenRequest.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/AuthTokenRequest.java index 6cda146c84..4e7a9e42dd 100644 --- a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/AuthTokenRequest.java +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/AuthTokenRequest.java @@ -29,6 +29,9 @@ public class AuthTokenRequest { @JsonProperty("requestFileUpload") private boolean requestFileUpload; + @JsonProperty("host_id") + private String hostId; + public String getAutopsyVersion() { return autopsyVersion; } @@ -56,4 +59,13 @@ public class AuthTokenRequest { return this; } + public String getHostId() { + return hostId; + } + + public AuthTokenRequest setHostId(String hostId) { + this.hostId = hostId; + return this; + } + } diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/AuthTokenResponse.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/AuthTokenResponse.java index c936d05dbe..ed2a1b0f39 100644 --- a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/AuthTokenResponse.java +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/AuthTokenResponse.java @@ -13,20 +13,24 @@ ************************************************************************** */ package com.basistech.df.cybertriage.autopsy.ctapi.json; +import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil.InstantEpochSecsDeserializer; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import java.time.ZonedDateTime; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.time.Instant; /** * POJO for an auth token response. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class AuthTokenResponse extends AuthenticatedRequestData { private final Long hashLookupCount; private final Long hashLookupLimit; private final Long fileUploadLimit; private final Long fileUploadCount; private final String fileUploadUrl; - private final ZonedDateTime expiration; + private final Instant expiration; @JsonCreator public AuthTokenResponse( @@ -37,7 +41,8 @@ public class AuthTokenResponse extends AuthenticatedRequestData { @JsonProperty("fileUploadLimit") Long fileUploadLimit, @JsonProperty("fileUploadCount") Long fileUploadCount, @JsonProperty("fileUploadUrl") String fileUploadUrl, - @JsonProperty("expiration") ZonedDateTime expiration + @JsonDeserialize(using=InstantEpochSecsDeserializer.class) + @JsonProperty("expiration") Instant expiration ) { this.token = token; this.apiKey = apiKey; @@ -69,7 +74,7 @@ public class AuthTokenResponse extends AuthenticatedRequestData { return fileUploadUrl; } - public ZonedDateTime getExpiration() { + public Instant getExpiration() { return expiration; } } diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/BoostLicenseResponse.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/BoostLicenseResponse.java index ce213aeba4..381f9843b1 100644 --- a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/BoostLicenseResponse.java +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/BoostLicenseResponse.java @@ -14,12 +14,14 @@ package com.basistech.df.cybertriage.autopsy.ctapi.json; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; /** * POJO for a boost license response object that is a part of the license * response. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class BoostLicenseResponse { private final String version; diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CTCloudBean.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CTCloudBean.java new file mode 100644 index 0000000000..25960094ca --- /dev/null +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CTCloudBean.java @@ -0,0 +1,98 @@ +/** ************************************************************************* + ** This data and information is proprietary to, and a valuable trade secret + ** of, Basis Technology Corp. It is given in confidence by Basis Technology + ** and may only be used as permitted under the license agreement under which + ** it has been distributed, and in no other way. + ** + ** Copyright (c) 2020 Basis Technology Corp. All rights reserved. + ** + ** The technical data and information provided herein are provided with + ** `limited rights', and the computer software provided herein is provided + ** with `restricted rights' as those terms are defined in DAR and ASPR + ** 7-104.9(a). + ************************************************************************** */ +package com.basistech.df.cybertriage.autopsy.ctapi.json; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * + * @author rishwanth + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class CTCloudBean { + + public static enum Status { + FOUND, + NOT_FOUND, + ERROR, + LIMITS_EXCEEDED, + BEING_SCANNED; + } + + @Nonnull + @JsonProperty("malware") + private MalwareResultBean malwareResult; + + @JsonProperty("correlation") + private CorrelationResultBean correlationResult; + + @Nonnull + @JsonProperty("md5_hash") + private String md5HashValue; + + @Nullable + @JsonProperty("sha1_hash") + private String sha1HashValue; + + public String getMd5HashValue() { + return md5HashValue; + } + + public String getSha1HashValue() { + return sha1HashValue; + } + + public void setMd5HashValue(String md5HashValue) { + this.md5HashValue = md5HashValue; + } + + public void setSha1HashValue(String sha1HashValue) { + this.sha1HashValue = sha1HashValue; + } + + public MalwareResultBean getMalwareResult() { + return malwareResult; + } + + public void setMalwareResult(MalwareResultBean malwareResult) { + this.malwareResult = malwareResult; + } + + public CorrelationResultBean getCorrelationResult() { + return correlationResult; + } + + public void setCorrelationResult(CorrelationResultBean correlationResult) { + this.correlationResult = correlationResult; + } + + @Override + public String toString() { + return "CTCloudBean{" + + "status=" + malwareResult.getStatus() + + ", malwareDescription=" + malwareResult.getMalwareDescription() + + ", score=" + malwareResult.getCTScore() + + ", md5HashValue=" + md5HashValue + + ", sha1HashValue=" + sha1HashValue + + ", firstSeen=" + malwareResult.getFirstAnalyzedDate() + + ", lastSeen=" + malwareResult.getLastAnalyzedDate() + + ", statusDescription=" + malwareResult.getStatusDescription() + + ", metadata=" + malwareResult.getMetadata() + + '}'; + } + +} diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/FileReputationResponse.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CTCloudBeanResponse.java similarity index 77% rename from Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/FileReputationResponse.java rename to Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CTCloudBeanResponse.java index aaff89b1d1..cc98008ea1 100644 --- a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/FileReputationResponse.java +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CTCloudBeanResponse.java @@ -14,24 +14,26 @@ package com.basistech.df.cybertriage.autopsy.ctapi.json; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.List; /** * Container for file reputation result list response. */ -public class FileReputationResponse { +@JsonIgnoreProperties(ignoreUnknown = true) +public class CTCloudBeanResponse { - private final List items; + private final List items; @JsonCreator - public FileReputationResponse( - @JsonProperty("items") List items + public CTCloudBeanResponse( + @JsonProperty("items") List items ) { this.items = items; } - public List getItems() { + public List getItems() { return items; } diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CTCloudCorrelationResultBean.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CTCloudCorrelationResultBean.java new file mode 100644 index 0000000000..3406f69e58 --- /dev/null +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CTCloudCorrelationResultBean.java @@ -0,0 +1,53 @@ +/** ************************************************************************* + ** This data and information is proprietary to, and a valuable trade secret + ** of, Basis Technology Corp. It is given in confidence by Basis Technology + ** and may only be used as permitted under the license agreement under which + ** it has been distributed, and in no other way. + ** + ** Copyright (c) 2023 Basis Technology Corp. All rights reserved. + ** + ** The technical data and information provided herein are provided with + ** `limited rights', and the computer software provided herein is provided + ** with `restricted rights' as those terms are defined in DAR and ASPR + ** 7-104.9(a). + ************************************************************************** */ +package com.basistech.df.cybertriage.autopsy.ctapi.json; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.annotation.Nonnull; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class CTCloudCorrelationResultBean { + + @JsonProperty("correlation") + private CorrelationResultBean correlationResult; + + @Nonnull + @JsonProperty("signature") + private String signature; + + public CorrelationResultBean getCorrelationResult() { + return correlationResult; + } + + public void setCorrelationResult(CorrelationResultBean correlationResult) { + this.correlationResult = correlationResult; + } + + public String getSignature() { + return signature; + } + + public void setSignature(String signature) { + this.signature = signature; + } + + @Override + public String toString() { + return "CTCloudCorrelationResultBean{" + + "correlationResult=" + correlationResult + + ", signature=" + signature + + '}'; + } +} diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CTCloudCostBean.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CTCloudCostBean.java new file mode 100644 index 0000000000..f1ab859eef --- /dev/null +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CTCloudCostBean.java @@ -0,0 +1,41 @@ +/** ************************************************************************* + ** This data and information is proprietary to, and a valuable trade secret + ** of, Basis Technology Corp. It is given in confidence by Basis Technology + ** and may only be used as permitted under the license agreement under which + ** it has been distributed, and in no other way. + ** + ** Copyright (c) 2023 Basis Technology Corp. All rights reserved. + ** + ** The technical data and information provided herein are provided with + ** `limited rights', and the computer software provided herein is provided + ** with `restricted rights' as those terms are defined in DAR and ASPR + ** 7-104.9(a). + ************************************************************************** */ +package com.basistech.df.cybertriage.autopsy.ctapi.json; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * + * @author rishwanth + */ +class CTCloudCostBean { + + private final String provider; + + private final Integer units; + + public CTCloudCostBean(@JsonProperty("provider") String provider, @JsonProperty("units") Integer units) { + this.provider = provider; + this.units = units; + } + + public String getProvider() { + return provider; + } + + public Integer getUnits() { + return units; + } + +} diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CorrelationFrequency.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CorrelationFrequency.java new file mode 100644 index 0000000000..13c0051c5a --- /dev/null +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CorrelationFrequency.java @@ -0,0 +1,24 @@ +/** ************************************************************************* + ** This data and information is proprietary to, and a valuable trade secret + ** of, Basis Technology Corp. It is given in confidence by Basis Technology + ** and may only be used as permitted under the license agreement under which + ** it has been distributed, and in no other way. + ** + ** Copyright (c) 2020 Basis Technology Corp. All rights reserved. + ** + ** The technical data and information provided herein are provided with + ** `limited rights', and the computer software provided herein is provided + ** with `restricted rights' as those terms are defined in DAR and ASPR + ** 7-104.9(a). + ************************************************************************** */ +package com.basistech.df.cybertriage.autopsy.ctapi.json; + +/** + * + * @author rishwanth + */ +public enum CorrelationFrequency { + UNIQUE, + RARE, + COMMON; +} diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CorrelationResultBean.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CorrelationResultBean.java new file mode 100644 index 0000000000..b7355b5203 --- /dev/null +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/CorrelationResultBean.java @@ -0,0 +1,46 @@ +/** ************************************************************************* + ** This data and information is proprietary to, and a valuable trade secret + ** of, Basis Technology Corp. It is given in confidence by Basis Technology + ** and may only be used as permitted under the license agreement under which + ** it has been distributed, and in no other way. + ** + ** Copyright (c) 2020 Basis Technology Corp. All rights reserved. + ** + ** The technical data and information provided herein are provided with + ** `limited rights', and the computer software provided herein is provided + ** with `restricted rights' as those terms are defined in DAR and ASPR + ** 7-104.9(a). + ************************************************************************** */ +package com.basistech.df.cybertriage.autopsy.ctapi.json; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * + * @author rishwanth + */ +public class CorrelationResultBean { + + @JsonProperty("frequency") + private CorrelationFrequency frequency; + + @JsonProperty("frequency_description") + private String frequencyDescription; + + public CorrelationFrequency getFrequency() { + return frequency; + } + + public String getFrequencyDescription() { + return frequencyDescription; + } + + public void setFrequency(CorrelationFrequency frequency) { + this.frequency = frequency; + } + + public void setFrequencyDescription(String frequencyDescription) { + this.frequencyDescription = frequencyDescription; + } + +} diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/DecryptedLicenseResponse.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/DecryptedLicenseResponse.java index 79ef4350d5..d39e36686b 100644 --- a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/DecryptedLicenseResponse.java +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/DecryptedLicenseResponse.java @@ -14,8 +14,9 @@ package com.basistech.df.cybertriage.autopsy.ctapi.json; import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil.InstantEpochMillisDeserializer; -import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil.MDYDateDeserializer; +import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil.ZonedDateTimeDeserializer; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import java.time.Instant; @@ -24,6 +25,7 @@ import java.time.ZonedDateTime; /** * POJO for after encrypted boost license has been decrypted. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class DecryptedLicenseResponse { private final String boostLicenseId; @@ -39,17 +41,16 @@ public class DecryptedLicenseResponse { public DecryptedLicenseResponse( @JsonProperty("boostLicenseId") String boostLicenseId, @JsonProperty("licenseHostId") String licenseHostId, - @JsonDeserialize(using=MDYDateDeserializer.class) + @JsonDeserialize(using = ZonedDateTimeDeserializer.class) @JsonProperty("expirationDate") ZonedDateTime expirationDate, @JsonProperty("hashLookups") Long hashLookups, @JsonProperty("fileUploads") Long fileUploads, - @JsonDeserialize(using=InstantEpochMillisDeserializer.class) + @JsonDeserialize(using = InstantEpochMillisDeserializer.class) @JsonProperty("activationTime") Instant activationTime, @JsonProperty("product") String product, - @JsonProperty("limitType") String limitType, - - @JsonProperty("l4jLicenseId") String l4jlicenseId, - @JsonProperty("ctLicenseId") String ctLicenseId + @JsonProperty("limitType") String limitType + // @JsonProperty("l4jLicenseId") String l4jlicenseId, + // @JsonProperty("ctLicenseId") String ctLicenseId ) { this.boostLicenseId = boostLicenseId; this.licenseHostId = licenseHostId; diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/FileReputationResult.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/FileReputationResult.java deleted file mode 100644 index 53e604e381..0000000000 --- a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/FileReputationResult.java +++ /dev/null @@ -1,123 +0,0 @@ -/** ************************************************************************* - ** This data and information is proprietary to, and a valuable trade secret - ** of, Basis Technology Corp. It is given in confidence by Basis Technology - ** and may only be used as permitted under the license agreement under which - ** it has been distributed, and in no other way. - ** - ** Copyright (c) 2023 Basis Technology Corp. All rights reserved. - ** - ** The technical data and information provided herein are provided with - ** `limited rights', and the computer software provided herein is provided - ** with `restricted rights' as those terms are defined in DAR and ASPR - ** 7-104.9(a). - ************************************************************************** */ -package com.basistech.df.cybertriage.autopsy.ctapi.json; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.time.ZonedDateTime; -import java.util.List; - -/** - * A file reputation result regarding malware status. - */ -public class FileReputationResult { - - public static enum Status { - FOUND, - NOT_FOUND, - ERROR, - LIMITS_EXCEEDED, - BEING_SCANNED; - } - - public enum CorrelationFrequency { - UNIQUE, - RARE, - COMMON; - } - - private final String malwareDescription; - private final Status status; - private final CTScore score; - private final String md5Hash; - private final String sha1Hash; - private final ZonedDateTime firstScanDate; - private final ZonedDateTime lastScanDate; - private final List metadata; - private final String statusDescription; - private final CorrelationFrequency frequency; - private final String frequencyDescription; - - @JsonCreator - public FileReputationResult( - @JsonProperty("malwareDescription") String malwareDescription, - @JsonProperty("status") Status status, - @JsonProperty("score") CTScore score, - @JsonProperty("md5Hash") String md5Hash, - @JsonProperty("sha1Hash") String sha1Hash, - @JsonProperty("firstScanDate") ZonedDateTime firstScanDate, - @JsonProperty("lastScanDate") ZonedDateTime lastScanDate, - @JsonProperty("metadata") List metadata, - @JsonProperty("statusDescription") String statusDescription, - @JsonProperty("frequency") CorrelationFrequency frequency, - @JsonProperty("frequencyDescription") String frequencyDescription - ) { - this.malwareDescription = malwareDescription; - this.status = status; - this.score = score; - this.md5Hash = md5Hash; - this.sha1Hash = sha1Hash; - this.firstScanDate = firstScanDate; - this.lastScanDate = lastScanDate; - this.metadata = metadata; - this.statusDescription = statusDescription; - this.frequency = frequency; - this.frequencyDescription = frequencyDescription; - } - - public String getMalwareDescription() { - return malwareDescription; - } - - public Status getStatus() { - return status; - } - - public CTScore getScore() { - return score; - } - - public String getMd5Hash() { - return md5Hash; - } - - public String getSha1Hash() { - return sha1Hash; - } - - public ZonedDateTime getFirstScanDate() { - return firstScanDate; - } - - public ZonedDateTime getLastScanDate() { - return lastScanDate; - } - - public List getMetadata() { - return metadata; - } - - public String getStatusDescription() { - return statusDescription; - } - - public CorrelationFrequency getFrequency() { - return frequency; - } - - public String getFrequencyDescription() { - return frequencyDescription; - } - -} diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/LicenseResponse.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/LicenseResponse.java index 39184322e2..28511cf087 100644 --- a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/LicenseResponse.java +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/LicenseResponse.java @@ -14,11 +14,13 @@ package com.basistech.df.cybertriage.autopsy.ctapi.json; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; /** * Response POJO for request for license. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class LicenseResponse { private final Boolean success; private final Boolean hostChanged; diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/MalwareResultBean.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/MalwareResultBean.java new file mode 100644 index 0000000000..7a11359181 --- /dev/null +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/MalwareResultBean.java @@ -0,0 +1,165 @@ +/** ************************************************************************* + ** This data and information is proprietary to, and a valuable trade secret + ** of, Basis Technology Corp. It is given in confidence by Basis Technology + ** and may only be used as permitted under the license agreement under which + ** it has been distributed, and in no other way. + ** + ** Copyright (c) 2014 Basis Technology Corp. All rights reserved. + ** + ** The technical data and information provided herein are provided with + ** `limited rights', and the computer software provided herein is provided + ** with `restricted rights' as those terms are defined in DAR and ASPR + ** 7-104.9(a). + ************************************************************************** */ +package com.basistech.df.cybertriage.autopsy.ctapi.json; + +import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil.ZonedDateTimeDeserializer; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import java.time.ZonedDateTime; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * + * @author rishwanth + */ +public class MalwareResultBean { + + public static enum Status { + FOUND, + NOT_FOUND, + ERROR, + LIMITS_EXCEEDED, + BEING_SCANNED; + } + + @Nullable + @JsonProperty("malware_description") + private String malwareDescription; + + @Nonnull + @JsonProperty("status") + private Status status; + + @Nonnull + @JsonProperty("score") + private String score; + + private CTScore ctScore; + + @Nullable + @JsonProperty("first_scan_date") + @JsonDeserialize(using = ZonedDateTimeDeserializer.class) + private ZonedDateTime firstAnalyzedDate; + + @Nullable + @JsonProperty("last_scan_date") + @JsonDeserialize(using = ZonedDateTimeDeserializer.class) + private ZonedDateTime lastAnalyzedDate; + + @JsonProperty("metadata") + private List metadata; + + @Nullable + @JsonProperty("status_description") + private String statusDescription; + + + @Nullable + @JsonProperty + private List cost; + + @JsonIgnore + public CTScore getCTScore() { + return ctScore; + } + + public String getScore() { + return score; + } + + public ZonedDateTime getFirstAnalyzedDate() { + return firstAnalyzedDate; + } + + public ZonedDateTime getLastAnalyzedDate() { + return lastAnalyzedDate; + } + + public List getMetadata() { + if (metadata != null) { + return List.copyOf(metadata); + } else { + return List.of(); // empty list + } + } + + public Status getStatus() { + return status; + } + + public String getStatusDescription() { + return statusDescription; + } + + + public String getMalwareDescription() { + return malwareDescription; + } + + public void setMalwareDescription(String malwareDescription) { + this.malwareDescription = malwareDescription; + } + + public void setStatus(Status status) { + this.status = status; + } + + public void setScore(String score) { + this.score = score; + switch(score) { + case "GOOD_HIGH": + this.ctScore = CTScore.NONE; + break; + case "GOOD_MEDIUM": + this.ctScore = CTScore.LIKELY_NONE; + break; + case "BAD_HIGH": + this.ctScore = CTScore.NOTABLE; + break; + case "BAD_MEDIUM": + this.ctScore = CTScore.LIKELY_NOTABLE; + break; + default: + this.ctScore = CTScore.UNKNOWN; + break; + } + } + + public void setFirstAnalyzedDate(ZonedDateTime firstAnalyzedDate) { + this.firstAnalyzedDate = firstAnalyzedDate; + } + + public void setLastAnalyzedDate(ZonedDateTime lastAnalyzedDate) { + this.lastAnalyzedDate = lastAnalyzedDate; + } + + public void setMetadata(List metadata) { + this.metadata = List.copyOf(metadata); + } + + public void setStatusDescription(String statusDescription) { + this.statusDescription = statusDescription; + } + + public List getCost() { + return List.copyOf(cost); + } + + public void setCost(List cost) { + this.cost = List.copyOf(cost); + } +} diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/MetadataLabel.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/MetadataLabel.java index 8077250c8b..43d94a879e 100644 --- a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/MetadataLabel.java +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/json/MetadataLabel.java @@ -1,16 +1,26 @@ -/* - * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license - * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template - */ +/** ************************************************************************* + ** This data and information is proprietary to, and a valuable trade secret + ** of, Basis Technology Corp. It is given in confidence by Basis Technology + ** and may only be used as permitted under the license agreement under which + ** it has been distributed, and in no other way. + ** + ** Copyright (c) 2023 Basis Technology Corp. All rights reserved. + ** + ** The technical data and information provided herein are provided with + ** `limited rights', and the computer software provided herein is provided + ** with `restricted rights' as those terms are defined in DAR and ASPR + ** 7-104.9(a). + ************************************************************************** */ package com.basistech.df.cybertriage.autopsy.ctapi.json; import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; /** - * - * @author gregd + * Metadata entry. */ +@JsonIgnoreProperties(ignoreUnknown = true) public class MetadataLabel { private final String key; diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/util/ObjectMapperUtil.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/util/ObjectMapperUtil.java index 4a5ecd7925..0c82e5bb68 100644 --- a/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/util/ObjectMapperUtil.java +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctapi/util/ObjectMapperUtil.java @@ -21,11 +21,17 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.time.DateTimeException; import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; +import java.util.Date; +import java.util.function.Function; /** * Creates default ObjectMapper @@ -44,41 +50,110 @@ public class ObjectMapperUtil { public ObjectMapper getDefaultObjectMapper() { ObjectMapper defaultMapper = new ObjectMapper(); -// defaultMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + // defaultMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); defaultMapper.registerModule(new JavaTimeModule()); return defaultMapper; } - public static class MDYDateDeserializer extends JsonDeserializer { - private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("MMM dd, yyyy"); + + public static class ZonedDateTimeDeserializer extends JsonDeserializer { + @Override public ZonedDateTime deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JacksonException { - JsonNode node = jp.getCodec().readTree(jp); - String nodeText = node.asText(); + String date = jp.getText(); try { - return ZonedDateTime.parse(nodeText, FORMATTER); + LocalDateTime ldt = LocalDateTime.parse(date, DateTimeFormatter.ISO_LOCAL_DATE_TIME); + return ZonedDateTime.of(ldt, ZoneOffset.UTC); } catch (DateTimeParseException ex) { return null; } } - } - public static class InstantEpochMillisDeserializer extends JsonDeserializer { +// public static class MDYDateDeserializer extends JsonDeserializer { +// +// private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("MMM dd, yyyy"); +// +// @Override +// public Date deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JacksonException { +// JsonNode node = jp.getCodec().readTree(jp); +// String nodeText = node.asText(); +// try { +// return FORMATTER.parse(nodeText); +// } catch (ParseException ex) { +// return null; +// } +// } +// +// } + + public static class EpochTimeDeserializer extends JsonDeserializer { + + private final Function timeDeserializer; + + public EpochTimeDeserializer(Function timeDeserializer) { + this.timeDeserializer = timeDeserializer; + } @Override - public Instant deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JacksonException { + public T deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JacksonException { JsonNode node = jp.getCodec().readTree(jp); - if (!node.isNumber()) { - return null; + + Long timeVal = null; + if (node.isNumber()) { + timeVal = node.asLong(); } else { + String nodeText = node.asText(); try { - long millis = node.asLong(); - return Instant.ofEpochMilli(millis); - } catch (DateTimeException ex) { - return null; + timeVal = Long.parseLong(nodeText); + } catch (NumberFormatException ex) { + // do nothing if can't parse as number } } + + if (timeVal != null) { + try { + return timeDeserializer.apply(timeVal); + } catch (DateTimeException ex) { + // do nothing if can't parse to epoch + } + } + + return null; + } + } + + public static class InstantEpochMillisDeserializer extends EpochTimeDeserializer { + + public InstantEpochMillisDeserializer() { + super(InstantEpochMillisDeserializer::convert); + } + + private static Instant convert(Long longVal) { + try { + return Instant.ofEpochMilli(longVal); + } catch (DateTimeException ex) { + // do nothing if can't parse to epoch + + return null; + } + } + } + + public static class InstantEpochSecsDeserializer extends EpochTimeDeserializer { + + public InstantEpochSecsDeserializer() { + super(InstantEpochSecsDeserializer::convert); + } + + private static Instant convert(Long longVal) { + try { + return Instant.ofEpochSecond(longVal); + } catch (DateTimeException ex) { + // do nothing if can't parse to epoch + + return null; + } } } } diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/CTMalwareScannerOptionsPanel.java b/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/CTMalwareScannerOptionsPanel.java index 97e0f0ccee..a1eb7d9386 100644 --- a/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/CTMalwareScannerOptionsPanel.java +++ b/Core/src/com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/CTMalwareScannerOptionsPanel.java @@ -17,12 +17,15 @@ import com.basistech.df.cybertriage.autopsy.ctoptions.subpanel.CTOptionsSubPanel import com.basistech.df.cybertriage.autopsy.ctapi.CTCloudException; import com.basistech.df.cybertriage.autopsy.ctapi.CTApiDAO; import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenResponse; +import com.basistech.df.cybertriage.autopsy.ctapi.json.DecryptedLicenseResponse; import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseInfo; import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseResponse; import com.basistech.df.cybertriage.autopsy.ctapi.util.LicenseDecryptorUtil; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.text.SimpleDateFormat; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.logging.Level; @@ -34,6 +37,7 @@ import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.core.UserPreferences; /** * Options panel for CyberTriage options for importing a CyberTriage incident @@ -43,8 +47,13 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel { private static final Logger logger = Logger.getLogger(CTMalwareScannerOptionsPanel.class.getName()); - private static final SimpleDateFormat LICENSE_EXPIRES_FORMAT = new SimpleDateFormat("MMMM d, YYYY"); - private static final SimpleDateFormat MALWARE_SCANS_RESET_FORMAT = new SimpleDateFormat("MMM d, YYYY' at 'h:mma"); + private static final DateTimeFormatter LICENSE_EXPIRES_FORMAT = DateTimeFormatter + .ofPattern("MMMM d, YYYY") + .withZone(ZoneId.of(UserPreferences.getTimeZoneForDisplays())); + + private static final DateTimeFormatter MALWARE_SCANS_RESET_FORMAT = DateTimeFormatter + .ofPattern("MMM d, YYYY' at 'h:mma") + .withZone(ZoneId.of(UserPreferences.getTimeZoneForDisplays())); private final CTApiDAO ctApiDAO = CTApiDAO.getInstance(); private final CTLicensePersistence ctPersistence = CTLicensePersistence.getInstance(); @@ -171,7 +180,7 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel { - this.authTokenFetcher = new AuthTokenFetcher(licenseInfo.getDecryptedLicense().getBoostLicenseId()); + this.authTokenFetcher = new AuthTokenFetcher(licenseInfo.getDecryptedLicense()); this.authTokenFetcher.execute(); } @@ -491,15 +500,15 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel { "CTMalwareScannerOptionsPanel_MalwareScansFetcher_localErr_desc=A general error occurred while fetching malware scans information. Please try again later.",}) private class AuthTokenFetcher extends SwingWorker { - private final String boostLicenseId; + private final DecryptedLicenseResponse decryptedLicense; - public AuthTokenFetcher(String boostLicenseId) { - this.boostLicenseId = boostLicenseId; + public AuthTokenFetcher(DecryptedLicenseResponse decryptedLicense) { + this.decryptedLicense = decryptedLicense; } @Override protected AuthTokenResponse doInBackground() throws Exception { - return ctApiDAO.getAuthToken(boostLicenseId); + return ctApiDAO.getAuthToken(decryptedLicense); } @Override diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/BatchProcessor.java b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/BatchProcessor.java index 9adb7410ce..46365ff88e 100644 --- a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/BatchProcessor.java +++ b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/BatchProcessor.java @@ -70,7 +70,11 @@ public class BatchProcessor { private synchronized void asyncProcessBatch() throws InterruptedException { if (!batchingQueue.isEmpty()) { // wait for previous processing to finish - lastProcessingFuture.wait(millisTimeout); + synchronized (lastProcessingFuture) { + if (!lastProcessingFuture.isDone()) { + lastProcessingFuture.wait(millisTimeout); + } + } // if 'andThen' doesn't run, clear the processing queue processingQueue.clear(); diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties-MERGED b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties-MERGED index 9b715cf1fb..67b07a28ae 100644 --- a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties-MERGED +++ b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/Bundle.properties-MERGED @@ -18,6 +18,6 @@ MalwareScanIngestModule_ShareProcessing_batchTimeout_title=Batch Processing Time # {0} - remainingLookups MalwareScanIngestModule_ShareProcessing_lowLimitWarning_desc=This license only has {0} lookups remaining MalwareScanIngestModule_ShareProcessing_lowLimitWarning_title=Hash Lookups Low -MalwareScanIngestModuleFactory_description=The malware scan ingest module queries the CyberTriage cloud API for any possible malicious executables. -MalwareScanIngestModuleFactory_displayName=Malware Scan +MalwareScanIngestModuleFactory_description=The malware scan ingest module queries the Cyber Triage cloud API for any possible malicious executables. +MalwareScanIngestModuleFactory_displayName=Cyber Triage Malware Scan MalwareScanIngestModuleFactory_version=1.0.0 diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModule.java b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModule.java index 65a12f59b7..b966a1c667 100644 --- a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModule.java +++ b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModule.java @@ -15,7 +15,7 @@ package com.basistech.df.cybertriage.autopsy.malwarescan; import com.basistech.df.cybertriage.autopsy.ctapi.CTApiDAO; import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenResponse; -import com.basistech.df.cybertriage.autopsy.ctapi.json.FileReputationResult; +import com.basistech.df.cybertriage.autopsy.ctapi.json.CTCloudBean; import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseInfo; import com.basistech.df.cybertriage.autopsy.ctoptions.ctcloud.CTLicensePersistence; import java.util.ArrayList; @@ -135,8 +135,7 @@ public class MalwareScanIngestModule implements FileIngestModule { throw new IngestModuleException("No saved license was found"); } - String licenseStr = licenseInfoOpt.get().getDecryptedLicense().getBoostLicenseId(); - AuthTokenResponse authTokenResponse = ctApiDAO.getAuthToken(licenseStr); + AuthTokenResponse authTokenResponse = ctApiDAO.getAuthToken(licenseInfoOpt.get().getDecryptedLicense()); // syncronously fetch malware scans info // determine lookups remaining @@ -161,6 +160,7 @@ public class MalwareScanIngestModule implements FileIngestModule { licenseInfo = licenseInfoOpt.get(); startupException = null; noMoreHashLookups = false; + runState = RunState.STARTED_UP; } catch (IngestModuleException ex) { startupException = ex; throw startupException; @@ -235,7 +235,7 @@ public class MalwareScanIngestModule implements FileIngestModule { try { // get an auth token with the license - AuthTokenResponse authTokenResponse = ctApiDAO.getAuthToken(licenseInfo.getDecryptedLicense().getBoostLicenseId()); + AuthTokenResponse authTokenResponse = ctApiDAO.getAuthToken(licenseInfo.getDecryptedLicense()); // make sure we are in bounds for the remaining scans long remainingScans = remaining(authTokenResponse.getHashLookupLimit(), authTokenResponse.getHashLookupCount()); @@ -256,14 +256,14 @@ public class MalwareScanIngestModule implements FileIngestModule { } // using auth token, get results - List repResult = ctApiDAO.getReputationResults(authTokenResponse, md5Hashes); + List repResult = ctApiDAO.getReputationResults(authTokenResponse, md5Hashes); if (repResult != null && !repResult.isEmpty()) { SleuthkitCase.CaseDbTransaction trans = null; try { trans = tskCase.beginTransaction(); - for (FileReputationResult result : repResult) { - String sanitizedMd5 = sanitizedMd5(result.getMd5Hash()); + for (CTCloudBean result : repResult) { + String sanitizedMd5 = sanitizedMd5(result.getMd5HashValue()); List objIds = md5ToObjId.remove(sanitizedMd5); if (objIds == null || objIds.isEmpty()) { continue; @@ -309,18 +309,20 @@ public class MalwareScanIngestModule implements FileIngestModule { "MalwareScanIngestModule_SharedProcessing_createAnalysisResult_Yes=YES", "MalwareScanIngestModule_SharedProcessing_createAnalysisResult_No=NO" }) - private void createAnalysisResult(Long objId, FileReputationResult fileReputationResult, SleuthkitCase.CaseDbTransaction trans) throws Blackboard.BlackboardException { - if (objId == null || fileReputationResult == null) { + private void createAnalysisResult(Long objId, CTCloudBean cloudBean, SleuthkitCase.CaseDbTransaction trans) throws Blackboard.BlackboardException { + if (objId == null || cloudBean == null || cloudBean.getMalwareResult() == null) { return; } - Score score = fileReputationResult.getScore() == null ? Score.SCORE_UNKNOWN : fileReputationResult.getScore().getTskCore(); + Score score = cloudBean.getMalwareResult().getCTScore() == null + ? Score.SCORE_UNKNOWN + : cloudBean.getMalwareResult().getCTScore().getTskCore(); String conclusion = score.getSignificance() == Score.Significance.NOTABLE || score.getSignificance() == Score.Significance.LIKELY_NOTABLE ? Bundle.MalwareScanIngestModule_SharedProcessing_createAnalysisResult_Yes() : Bundle.MalwareScanIngestModule_SharedProcessing_createAnalysisResult_No(); - String justification = fileReputationResult.getStatusDescription(); + String justification = cloudBean.getMalwareResult().getStatusDescription(); tskCase.getBlackboard().newAnalysisResult( malwareType, diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModuleFactory.java b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModuleFactory.java index 0a7fffb416..0411985955 100644 --- a/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModuleFactory.java +++ b/Core/src/com/basistech/df/cybertriage/autopsy/malwarescan/MalwareScanIngestModuleFactory.java @@ -26,8 +26,8 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; */ @ServiceProvider(service = org.sleuthkit.autopsy.ingest.IngestModuleFactory.class) @Messages({ - "MalwareScanIngestModuleFactory_displayName=Malware Scan", - "MalwareScanIngestModuleFactory_description=The malware scan ingest module queries the CyberTriage cloud API for any possible malicious executables.", + "MalwareScanIngestModuleFactory_displayName=Cyber Triage Malware Scan", + "MalwareScanIngestModuleFactory_description=The malware scan ingest module queries the Cyber Triage cloud API for any possible malicious executables.", "MalwareScanIngestModuleFactory_version=1.0.0" }) public class MalwareScanIngestModuleFactory extends IngestModuleFactoryAdapter {