initial commit

This commit is contained in:
Greg DiCristofaro 2023-07-20 14:07:52 -04:00
parent 499f880632
commit 0c3394e88f
45 changed files with 3959 additions and 53 deletions

View File

@ -1,3 +1,6 @@
<!DOCTYPE ivy-module [
<!ENTITY httpcomponents.version "4.5.14">
]>
<ivy-module version="2.0">
<info organisation="org.sleuthkit.autopsy" module="core"/>
<configurations >
@ -72,6 +75,15 @@
<!-- annotations like guarded by -->
<dependency conf="core->default" org="com.github.spotbugs" name="spotbugs-annotations" rev="4.6.0"/>
<dependency conf="core->default" org="com.license4j" name="license4j-runtime-library" rev="4.7.1"/>
<dependency conf="core->default" org="org.apache.httpcomponents" name="httpclient" rev="&httpcomponents.version;"/>
<dependency conf="core->default" org="org.apache.httpcomponents" name="httpmime" rev="&httpcomponents.version;"/>
<dependency conf="core->default" org="org.apache.httpcomponents" name="httpclient-win" rev="&httpcomponents.version;">
<exclude name="jna" />
<exclude name="jna-platform" />
</dependency>
<override org="org.apache.zookeeper" module="zookeeper" rev="3.8.0"/>
<override org="org.apache.zookeeper" module="zookeeper-jute" rev="3.8.0"/>
@ -84,5 +96,6 @@
<override org="org.bouncycastle" module="bcprov-ext-jdk15on" rev="1.70"/>
<override org="org.bouncycastle" module="bcprov-jdk15on" rev="1.70"/>
<override org="org.bouncycastle" module="bcpkix-jdk15on" rev="1.70"/>
<override org="junit" module="junit" rev="4.13.2"/>
</dependencies>
</ivy-module>

View File

@ -18,6 +18,7 @@ file.reference.bcprov-jdk15on-1.70.jar=release/modules/ext/bcprov-jdk15on-1.70.j
file.reference.bcutil-jdk15on-1.70.jar=release/modules/ext/bcutil-jdk15on-1.70.jar
file.reference.c3p0-0.9.5.5.jar=release/modules/ext/c3p0-0.9.5.5.jar
file.reference.checker-qual-3.33.0.jar=release/modules/ext/checker-qual-3.33.0.jar
file.reference.commons-codec-1.11.jar=release/modules/ext/commons-codec-1.11.jar
file.reference.commons-dbcp2-2.9.0.jar=release/modules/ext/commons-dbcp2-2.9.0.jar
file.reference.commons-io-2.11.0.jar=release/modules/ext/commons-io-2.11.0.jar
file.reference.commons-lang3-3.10.jar=release/modules/ext/commons-lang3-3.10.jar
@ -31,6 +32,10 @@ file.reference.decodetect-core-0.3.jar=release/modules/ext/decodetect-core-0.3.j
file.reference.error_prone_annotations-2.18.0.jar=release/modules/ext/error_prone_annotations-2.18.0.jar
file.reference.failureaccess-1.0.1.jar=release/modules/ext/failureaccess-1.0.1.jar
file.reference.guava-32.0.1-jre.jar=release/modules/ext/guava-32.0.1-jre.jar
file.reference.httpclient-4.5.14.jar=release/modules/ext/httpclient-4.5.14.jar
file.reference.httpclient-win-4.5.14.jar=release/modules/ext/httpclient-win-4.5.14.jar
file.reference.httpcore-4.4.16.jar=release/modules/ext/httpcore-4.4.16.jar
file.reference.httpmime-4.5.14.jar=release/modules/ext/httpmime-4.5.14.jar
file.reference.icepdf-core-6.2.2.jar=release/modules/ext/icepdf-core-6.2.2.jar
file.reference.icepdf-viewer-6.2.2.jar=release/modules/ext/icepdf-viewer-6.2.2.jar
file.reference.istack-commons-runtime-3.0.11.jar=release/modules/ext/istack-commons-runtime-3.0.11.jar
@ -46,6 +51,7 @@ file.reference.javax.activation-api-1.2.0.jar=release/modules/ext/javax.activati
file.reference.javax.ws.rs-api-2.1.1.jar=release/modules/ext/javax.ws.rs-api-2.1.1.jar
file.reference.jaxb-api-2.3.1.jar=release/modules/ext/jaxb-api-2.3.1.jar
file.reference.jaxb-runtime-2.3.3.jar=release/modules/ext/jaxb-runtime-2.3.3.jar
file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar
file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar
file.reference.jfreechart-1.5.3.jar=release/modules/ext/jfreechart-1.5.3.jar
file.reference.jgraphx-4.2.2.jar=release/modules/ext/jgraphx-4.2.2.jar
@ -55,6 +61,7 @@ file.reference.jutf7-1.0.0.jar=release/modules/ext/jutf7-1.0.0.jar
file.reference.jxmapviewer2-2.6.jar=release/modules/ext/jxmapviewer2-2.6.jar
file.reference.jython-standalone-2.7.2.jar=release/modules/ext/jython-standalone-2.7.2.jar
file.reference.libphonenumber-8.12.45.jar=release/modules/ext/libphonenumber-8.12.45.jar
file.reference.license4j-runtime-library-4.7.1.jar=release/modules/ext/license4j-runtime-library-4.7.1.jar
file.reference.listenablefuture-1.0.jar=release/modules/ext/listenablefuture-1.0.jar
file.reference.logback-classic-1.2.10.jar=release/modules/ext/logback-classic-1.2.10.jar
file.reference.logback-core-1.2.10.jar=release/modules/ext/logback-core-1.2.10.jar

View File

@ -66,6 +66,14 @@
<implementation-version/>
</run-dependency>
</dependency>
<dependency>
<code-name-base>org.netbeans.modules.keyring</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
<specification-version>1.41</specification-version>
</run-dependency>
</dependency>
<dependency>
<code-name-base>org.netbeans.modules.options.api</code-name-base>
<build-prerequisite/>
@ -165,14 +173,6 @@
<specification-version>9.29</specification-version>
</run-dependency>
</dependency>
<!-- <dependency>
<code-name-base>org.openide.filesystems.compat8</code-name-base>
<build-prerequisite/>
<compile-dependency/>
<run-dependency>
<specification-version>9.26</specification-version>
</run-dependency>
</dependency> -->
<dependency>
<code-name-base>org.openide.filesystems.nb</code-name-base>
<build-prerequisite/>
@ -448,6 +448,10 @@
<runtime-relative-path>ext/checker-qual-3.33.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/checker-qual-3.33.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/commons-codec-1.11.jar</runtime-relative-path>
<binary-origin>release/modules/ext/commons-codec-1.11.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/commons-dbcp2-2.9.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/commons-dbcp2-2.9.0.jar</binary-origin>
@ -500,6 +504,22 @@
<runtime-relative-path>ext/guava-32.0.1-jre.jar</runtime-relative-path>
<binary-origin>release/modules/ext/guava-32.0.1-jre.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/httpclient-4.5.14.jar</runtime-relative-path>
<binary-origin>release/modules/ext/httpclient-4.5.14.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/httpclient-win-4.5.14.jar</runtime-relative-path>
<binary-origin>release/modules/ext/httpclient-win-4.5.14.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/httpcore-4.4.16.jar</runtime-relative-path>
<binary-origin>release/modules/ext/httpcore-4.4.16.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/httpmime-4.5.14.jar</runtime-relative-path>
<binary-origin>release/modules/ext/httpmime-4.5.14.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/icepdf-core-6.2.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/icepdf-core-6.2.2.jar</binary-origin>
@ -560,6 +580,10 @@
<runtime-relative-path>ext/jaxb-runtime-2.3.3.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jaxb-runtime-2.3.3.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jdom-2.0.5-contrib.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jdom-2.0.5-contrib.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jdom-2.0.5.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jdom-2.0.5.jar</binary-origin>
@ -596,6 +620,10 @@
<runtime-relative-path>ext/libphonenumber-8.12.45.jar</runtime-relative-path>
<binary-origin>release/modules/ext/libphonenumber-8.12.45.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/license4j-runtime-library-4.7.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/license4j-runtime-library-4.7.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/listenablefuture-1.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/listenablefuture-1.0.jar</binary-origin>

View File

@ -0,0 +1,97 @@
/** *************************************************************************
** 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;
import java.util.Objects;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
/**
*
* @author rishwanth
*/
public class CTCloudException extends Exception{
private final ErrorCode errorCode;
public enum ErrorCode {
BAD_REQUEST("CT-400", "Unknown or Bad request. Please contact Basis support at " + Constants.SUPPORT_AT_CYBERTRIAGE_DOT_COM + " for help diagnosing the problem."),
INVALID_KEY("CT-401", "An invalid license ID was used to access CyberTriage Cloud Service. Please contact Basis support " + Constants.SUPPORT_AT_CYBERTRIAGE_DOT_COM + " for help diagnosing the problem."),
GATEWAY_TIMEOUT("CT-504", "Request to CyberTriage Cloud Service timed out. Please retry after some time. If issue persists, please contact Basis support at " + Constants.SUPPORT_AT_CYBERTRIAGE_DOT_COM + " for assistance."),
UN_AUTHORIZED("CT-403", "An authorization error occurred. Please contact Basis support " + Constants.SUPPORT_AT_CYBERTRIAGE_DOT_COM + " for help diagnosing the problem."),
PROXY_UNAUTHORIZED("CT-407", "Proxy authentication failed. Please validate the connection settings from the Options panel Proxy Settings."),
TEMP_UNAVAILABLE("CT-500", "CyberTriage Cloud Service temporarily unavailable; please try again later. If this problem persists, contact Basis support at " + Constants.SUPPORT_AT_CYBERTRIAGE_DOT_COM),
UNKNOWN("CT-080", "Unknown error while communicating with CyberTriage Cloud Service. If this problem persists, contact Basis support at "+ Constants.SUPPORT_AT_CYBERTRIAGE_DOT_COM +" for assistance."),
UNKNOWN_HOST("CT-081", "Unknown host error. If this problem persists, contact Basis support at "+ Constants.SUPPORT_AT_CYBERTRIAGE_DOT_COM +" for assistance."),
NETWORK_ERROR("CT-015", "Error connecting to CyberTriage Cloud.\n"
+ "Check your firewall or proxy settings.\n"
+ "Contact Support (support@cybertriage.com) for further assistance");
private final String errorcode;
private final String description;
private ErrorCode(String errorcode, String description) {
this.errorcode = errorcode;
this.description = description;
}
public String getCode() {
return errorcode;
}
public String getDescription() {
return description;
}
}
public CTCloudException(CTCloudException.ErrorCode errorCode) {
super(errorCode.name());
this.errorCode = errorCode;
}
public CTCloudException(CTCloudException.ErrorCode errorCode, Throwable throwable) {
super(errorCode.name(), throwable);
this.errorCode = errorCode;
}
public ErrorCode getErrorCode() {
return errorCode;
}
public String getErrorDetails() {
if(getErrorCode() == CTCloudException.ErrorCode.UNKNOWN && Objects.nonNull(getCause())){
return String.format("Malware scan error %s occurred. Please try \"Re Scan\" from the dashboard to attempt Malware scaning again. "
+ "\nPlease contact Basis support at %s for help if the problem presists.",
StringUtils.isNotBlank(getCause().getLocalizedMessage()) ? "("+getCause().getLocalizedMessage()+")": "(Unknown)",
Constants.SUPPORT_AT_CYBERTRIAGE_DOT_COM );
}else {
return getErrorCode().getDescription();
}
}
/*
* Attempts to find a more specific error code than "Unknown" for the given exception.
*/
public static ErrorCode parseUnknownException(Throwable throwable) {
String stackTrace = ExceptionUtils.getStackTrace(throwable);
if (stackTrace.contains("UnknownHostException")) {
return ErrorCode.UNKNOWN_HOST;
}
return ErrorCode.UNKNOWN;
}
}

View File

@ -0,0 +1,83 @@
/** *************************************************************************
** 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) 2016 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;
import com.google.common.collect.ImmutableList;
import java.net.URI;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
// TODO take out anything sensitive or not used
final public class Constants {
public static final String CYBER_TRIAGE = "CyberTriage";
public static final String IS_MEMORY_IMAGE = "IS_MEMORY_IMAGE";
public static final String SSLTEST_URL = "https://www2.cybertriage.com/ssl_test.html";
public static final String CT_CLOUD_SERVER = "https://rep1.cybertriage.com";
public static final String CT_CLOUD_DEV_SERVER = "https://cyber-triage-dev.appspot.com";
/**
* Link to watch demo video
* @since 3.1.0
*/
public static final String DEMO_VIDEO_URL = "https://www.cybertriage.com/video/cyber-triage-demo-video/?utm_source=Cyber+Triage+Tool&utm_campaign=Eval+Demo+Video";
/**
* Link request quote
* @since 3.1.0
*/
public static final String REQUEST_QUOTE_URL = "https://www.cybertriage.com/request-quote/?utm_source=Cyber+Triage+Tool&utm_campaign=Eval+Quote";
/**
* Latest help document URL
* @since 3.2.0
*/
public static final URI USER_GUIDE_LATEST_URL = URI.create("https://docs.cybertriage.com/en/latest/?utm_source=Cyber+Triage+Tool&utm_campaign=Help+Docs");
/**
* Visit website URL
* @since 3.1.0
*/
public static final String VISIT_WEBSITE_URL ="https://www.cybertriage.com/eval_data_202109/?utm_source=Cyber+Triage+Tool&utm_campaign=Eval+Data+Button";
/**
* URL for visiting the website after the data is ingested on the dashboard.
*/
public static final String EVAL_WEBSITE_AUTO_URL = "https://www.cybertriage.com/eval_data_202109_auto/?utm_source=Cyber+Triage+Tool&utm_campaign=Eval+Data+Auto/"; //CT-4045
public static final String SUPPORT_AT_CYBERTRIAGE_DOT_COM = "support@cybertriage.com";
public static final String SALES_AT_CYBERTRIAGE_DOT_COM = "sales@cybertriage.com";
public final static String AUTODETECT = "Auto Detect";
public final static int RESTAPI_PORT = 9443;
public static final String INVALID_HOSTNAME_REQUEST = "Request rejected. Invalid host name. Hostname contains characters that are not allowed. \n"
+ "Characters that are not allowed include `~!@#$&^*(){}[]\\\\|;'\",<>/? \n"
+ "You may input the host IP address if the name is not resolving.";
public static final String INVALID_HOSTNAME_UI = "Invalid host name. Hostname contains characters that are not allowed. \n"
+ "Characters that are not allowed include `~!@#$&^*(){}[]\\\\|;'\",<>/?";
}

View File

@ -0,0 +1,83 @@
/** *************************************************************************
** 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;
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.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;
import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
import org.sleuthkit.autopsy.coreutils.Version;
/**
*
* Data access layer for handling the CT api.
*/
public class CtApiDAO {
private static final String LICENSE_REQUEST_PATH = "/_ah/api/license/v1/activate";
private static final String AUTH_TOKEN_REQUEST_PATH = "/_ah/api/auth/v2/generate_token";
private static final CtApiDAO instance = new CtApiDAO();
private final ObjectMapper mapper = ObjectMapperUtil.getInstance().getDefaultObjectMapper();
private CtApiDAO() {
}
public static CtApiDAO getInstance() {
return instance;
}
private static String getAppVersion() {
return Version.getName() + " " + Version.getVersion();
}
private <T> T doPost(String urlPath, Object requestBody, Class<T> responseTypeRef) throws CTCloudException {
return null;
// TODO
}
public LicenseResponse getLicenseInfo(String licenseString) throws CTCloudException {
LicenseRequest licenseRequest = new LicenseRequest()
.setBoostLicenseCode(licenseString)
.setHostId(CTHostIDGenerationUtil.generateLicenseHostID())
.setProduct(getAppVersion());
return doPost(LICENSE_REQUEST_PATH, licenseRequest, LicenseResponse.class);
}
public AuthTokenResponse getAuthToken(String boostLicenseId) throws CTCloudException {
AuthTokenRequest authTokenRequest = new AuthTokenRequest()
.setAutopsyVersion(getAppVersion())
.setRequestFileUpload(true)
.setBoostLicenseId(boostLicenseId);
return doPost(AUTH_TOKEN_REQUEST_PATH, authTokenRequest, AuthTokenResponse.class);
}
public List<FileReputationResult> getReputationResults(String authToken, List<String> md5Hashes) throws CTCloudException {
// TODO
// return cloudServiceApi.lookupFileResults(md5Hashes, HashTypes.md5);
return null;
}
public enum ResultType {
OK, SERVER_ERROR, NOT_AUTHORIZED
}
}

View File

@ -0,0 +1,443 @@
/** *************************************************************************
** 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;
import java.net.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.PreferenceChangeListener;
import java.util.prefs.Preferences;
import org.netbeans.api.keyring.Keyring;
import org.openide.util.*;
import org.openide.util.lookup.ServiceProvider;
/**
* Taken from https://raw.githubusercontent.com/apache/netbeans/master/platform/o.n.core/src/org/netbeans/core/ProxySettings.java
* @author Jiri Rechtacek
*/
public class ProxySettings {
public static final String PROXY_HTTP_HOST = "proxyHttpHost"; // NOI18N
public static final String PROXY_HTTP_PORT = "proxyHttpPort"; // NOI18N
public static final String PROXY_HTTPS_HOST = "proxyHttpsHost"; // NOI18N
public static final String PROXY_HTTPS_PORT = "proxyHttpsPort"; // NOI18N
public static final String PROXY_SOCKS_HOST = "proxySocksHost"; // NOI18N
public static final String PROXY_SOCKS_PORT = "proxySocksPort"; // NOI18N
public static final String NOT_PROXY_HOSTS = "proxyNonProxyHosts"; // NOI18N
public static final String PROXY_TYPE = "proxyType"; // NOI18N
public static final String USE_PROXY_AUTHENTICATION = "useProxyAuthentication"; // NOI18N
public static final String PROXY_AUTHENTICATION_USERNAME = "proxyAuthenticationUsername"; // NOI18N
public static final String PROXY_AUTHENTICATION_PASSWORD = "proxyAuthenticationPassword"; // NOI18N
public static final String USE_PROXY_ALL_PROTOCOLS = "useProxyAllProtocols"; // NOI18N
public static final String DIRECT = "DIRECT"; // NOI18N
public static final String PAC = "PAC"; // NOI18N
public static final String SYSTEM_PROXY_HTTP_HOST = "systemProxyHttpHost"; // NOI18N
public static final String SYSTEM_PROXY_HTTP_PORT = "systemProxyHttpPort"; // NOI18N
public static final String SYSTEM_PROXY_HTTPS_HOST = "systemProxyHttpsHost"; // NOI18N
public static final String SYSTEM_PROXY_HTTPS_PORT = "systemProxyHttpsPort"; // NOI18N
public static final String SYSTEM_PROXY_SOCKS_HOST = "systemProxySocksHost"; // NOI18N
public static final String SYSTEM_PROXY_SOCKS_PORT = "systemProxySocksPort"; // NOI18N
public static final String SYSTEM_NON_PROXY_HOSTS = "systemProxyNonProxyHosts"; // NOI18N
public static final String SYSTEM_PAC = "systemPAC"; // NOI18N
// Only for testing purpose (Test connection in General options panel)
public static final String TEST_SYSTEM_PROXY_HTTP_HOST = "testSystemProxyHttpHost"; // NOI18N
public static final String TEST_SYSTEM_PROXY_HTTP_PORT = "testSystemProxyHttpPort"; // NOI18N
public static final String HTTP_CONNECTION_TEST_URL = "https://netbeans.apache.org";// NOI18N
private static String presetNonProxyHosts;
/** No proxy is used to connect. */
public static final int DIRECT_CONNECTION = 0;
/** Proxy setting is automatically detect in OS. */
public static final int AUTO_DETECT_PROXY = 1; // as default
/** Manually set proxy host and port. */
public static final int MANUAL_SET_PROXY = 2;
/** Proxy PAC file automatically detect in OS. */
public static final int AUTO_DETECT_PAC = 3;
/** Proxy PAC file manually set. */
public static final int MANUAL_SET_PAC = 4;
private static final Logger LOGGER = Logger.getLogger(ProxySettings.class.getName());
private static Preferences getPreferences() {
return NbPreferences.forModule (ProxySettings.class);
}
public static String getHttpHost () {
return normalizeProxyHost (getPreferences ().get (PROXY_HTTP_HOST, ""));
}
public static String getHttpPort () {
return getPreferences ().get (PROXY_HTTP_PORT, "");
}
public static String getHttpsHost () {
if (useProxyAllProtocols ()) {
return getHttpHost ();
} else {
return getPreferences ().get (PROXY_HTTPS_HOST, "");
}
}
public static String getHttpsPort () {
if (useProxyAllProtocols ()) {
return getHttpPort ();
} else {
return getPreferences ().get (PROXY_HTTPS_PORT, "");
}
}
public static String getSocksHost () {
if (useProxyAllProtocols ()) {
return getHttpHost ();
} else {
return getPreferences ().get (PROXY_SOCKS_HOST, "");
}
}
public static String getSocksPort () {
if (useProxyAllProtocols ()) {
return getHttpPort ();
} else {
return getPreferences ().get (PROXY_SOCKS_PORT, "");
}
}
public static String getNonProxyHosts () {
String hosts = getPreferences ().get (NOT_PROXY_HOSTS, getDefaultUserNonProxyHosts ());
return compactNonProxyHosts(hosts);
}
public static int getProxyType () {
int type = getPreferences ().getInt (PROXY_TYPE, AUTO_DETECT_PROXY);
if (AUTO_DETECT_PROXY == type) {
type = ProxySettings.getSystemPac() != null ? AUTO_DETECT_PAC : AUTO_DETECT_PROXY;
}
return type;
}
public static String getSystemHttpHost() {
return getPreferences().get(SYSTEM_PROXY_HTTP_HOST, "");
}
public static String getSystemHttpPort() {
return getPreferences().get(SYSTEM_PROXY_HTTP_PORT, "");
}
public static String getSystemHttpsHost() {
return getPreferences().get(SYSTEM_PROXY_HTTPS_HOST, "");
}
public static String getSystemHttpsPort() {
return getPreferences().get(SYSTEM_PROXY_HTTPS_PORT, "");
}
public static String getSystemSocksHost() {
return getPreferences().get(SYSTEM_PROXY_SOCKS_HOST, "");
}
public static String getSystemSocksPort() {
return getPreferences().get(SYSTEM_PROXY_SOCKS_PORT, "");
}
public static String getSystemNonProxyHosts() {
return getPreferences().get(SYSTEM_NON_PROXY_HOSTS, getModifiedNonProxyHosts(""));
}
public static String getSystemPac() {
return getPreferences().get(SYSTEM_PAC, null);
}
public static String getTestSystemHttpHost() {
return getPreferences().get(TEST_SYSTEM_PROXY_HTTP_HOST, "");
}
public static String getTestSystemHttpPort() {
return getPreferences().get(TEST_SYSTEM_PROXY_HTTP_PORT, "");
}
public static boolean useAuthentication () {
return getPreferences ().getBoolean (USE_PROXY_AUTHENTICATION, false);
}
public static boolean useProxyAllProtocols () {
return getPreferences ().getBoolean (USE_PROXY_ALL_PROTOCOLS, false);
}
public static String getAuthenticationUsername () {
return getPreferences ().get (PROXY_AUTHENTICATION_USERNAME, "");
}
public static char[] getAuthenticationPassword () {
String old = getPreferences().get(PROXY_AUTHENTICATION_PASSWORD, null);
if (old != null) {
getPreferences().remove(PROXY_AUTHENTICATION_PASSWORD);
setAuthenticationPassword(old.toCharArray());
}
char[] pwd = Keyring.read(PROXY_AUTHENTICATION_PASSWORD);
return pwd != null ? pwd : new char[0];
}
public static void setAuthenticationPassword(char[] password) {
Keyring.save(ProxySettings.PROXY_AUTHENTICATION_PASSWORD, password,
// XXX consider including getHttpHost and/or getHttpsHost
NbBundle.getMessage(ProxySettings.class, "ProxySettings.password.description")); // NOI18N
}
public static void addPreferenceChangeListener (PreferenceChangeListener l) {
getPreferences ().addPreferenceChangeListener (l);
}
public static void removePreferenceChangeListener (PreferenceChangeListener l) {
getPreferences ().removePreferenceChangeListener (l);
}
private static String getPresetNonProxyHosts () {
if (presetNonProxyHosts == null) {
presetNonProxyHosts = System.getProperty ("http.nonProxyHosts", ""); // NOI18N
}
return presetNonProxyHosts;
}
private static String getDefaultUserNonProxyHosts () {
return getModifiedNonProxyHosts (getSystemNonProxyHosts ());
}
private static String concatProxies(String... proxies) {
StringBuilder sb = new StringBuilder();
for (String n : proxies) {
if (n == null) {
continue;
}
n = n.trim();
if (n.isEmpty()) {
continue;
}
if (sb.length() > 0 && sb.charAt(sb.length() - 1) != '|') { // NOI18N
if (!n.startsWith("|")) { // NOI18N
sb.append('|'); // NOI18N
}
}
sb.append(n);
}
return sb.toString();
}
private static String getModifiedNonProxyHosts (String systemPreset) {
String fromSystem = systemPreset.replace (";", "|").replace (",", "|"); //NOI18N
String fromUser = getPresetNonProxyHosts () == null ? "" : getPresetNonProxyHosts ().replace (";", "|").replace (",", "|"); //NOI18N
if (Utilities.isWindows ()) {
fromSystem = addReguralToNonProxyHosts (fromSystem);
}
final String staticNonProxyHosts = NbBundle.getMessage(ProxySettings.class, "StaticNonProxyHosts"); // NOI18N
String nonProxy = concatProxies(fromUser, fromSystem, staticNonProxyHosts); // NOI18N
String localhost;
try {
localhost = InetAddress.getLocalHost().getHostName();
if (!"localhost".equals(localhost)) { // NOI18N
nonProxy = nonProxy + "|" + localhost; // NOI18N
} else {
// Avoid this error when hostname == localhost:
// Error in http.nonProxyHosts system property: sun.misc.REException: localhost is a duplicate
}
}
catch (UnknownHostException e) {
// OK. Sometimes a hostname is assigned by DNS, but a computer
// is later pulled off the network. It may then produce a bogus
// name for itself which can't actually be resolved. Normally
// "localhost" is aliased to 127.0.0.1 anyway.
}
/* per Milan's agreement it's removed. See issue #89868
try {
String localhost2 = InetAddress.getLocalHost().getCanonicalHostName();
if (!"localhost".equals(localhost2) && !localhost2.equals(localhost)) { // NOI18N
nonProxy = nonProxy + "|" + localhost2; // NOI18N
} else {
// Avoid this error when hostname == localhost:
// Error in http.nonProxyHosts system property: sun.misc.REException: localhost is a duplicate
}
}
catch (UnknownHostException e) {
// OK. Sometimes a hostname is assigned by DNS, but a computer
// is later pulled off the network. It may then produce a bogus
// name for itself which can't actually be resolved. Normally
// "localhost" is aliased to 127.0.0.1 anyway.
}
*/
return compactNonProxyHosts (nonProxy);
}
// avoid duplicate hosts
private static String compactNonProxyHosts (String hosts) {
StringTokenizer st = new StringTokenizer(hosts, ","); //NOI18N
StringBuilder nonProxyHosts = new StringBuilder();
while (st.hasMoreTokens()) {
String h = st.nextToken().trim();
if (h.length() == 0) {
continue;
}
if (nonProxyHosts.length() > 0) {
nonProxyHosts.append("|"); // NOI18N
}
nonProxyHosts.append(h);
}
st = new StringTokenizer (nonProxyHosts.toString(), "|"); //NOI18N
Set<String> set = new HashSet<String> ();
StringBuilder compactedProxyHosts = new StringBuilder();
while (st.hasMoreTokens ()) {
String t = st.nextToken ();
if (set.add (t.toLowerCase (Locale.US))) {
if (compactedProxyHosts.length() > 0) {
compactedProxyHosts.append('|'); // NOI18N
}
compactedProxyHosts.append(t);
}
}
return compactedProxyHosts.toString();
}
private static String addReguralToNonProxyHosts (String nonProxyHost) {
StringTokenizer st = new StringTokenizer (nonProxyHost, "|"); // NOI18N
StringBuilder reguralProxyHosts = new StringBuilder();
while (st.hasMoreTokens ()) {
String t = st.nextToken ();
if (t.indexOf ('*') == -1) { //NOI18N
t = t + '*'; //NOI18N
}
if (reguralProxyHosts.length() > 0)
reguralProxyHosts.append('|'); // NOI18N
reguralProxyHosts.append(t);
}
return reguralProxyHosts.toString();
}
public static String normalizeProxyHost (String proxyHost) {
if (proxyHost.toLowerCase (Locale.US).startsWith ("http://")) { // NOI18N
return proxyHost.substring (7, proxyHost.length ());
} else {
return proxyHost;
}
}
private static InetSocketAddress analyzeProxy(URI uri) {
Parameters.notNull("uri", uri); // NOI18N
List<Proxy> proxies = ProxySelector.getDefault().select(uri);
assert proxies != null : "ProxySelector cannot return null for " + uri; // NOI18N
assert !proxies.isEmpty() : "ProxySelector cannot return empty list for " + uri; // NOI18N
String protocol = uri.getScheme();
Proxy p = proxies.get(0);
if (Proxy.Type.DIRECT == p.type()) {
// return null for DIRECT proxy
return null;
}
if (protocol == null
|| ((protocol.startsWith("http") || protocol.equals("ftp")) && Proxy.Type.HTTP == p.type()) // NOI18N
|| !(protocol.startsWith("http") || protocol.equals("ftp"))) { // NOI18N
if (p.address() instanceof InetSocketAddress) {
// check is
//assert ! ((InetSocketAddress) p.address()).isUnresolved() : p.address() + " must be resolved address.";
return (InetSocketAddress) p.address();
} else {
LOGGER.log(Level.INFO, p.address() + " is not instanceof InetSocketAddress but " + p.address().getClass()); // NOI18N
return null;
}
} else {
return null;
}
}
public static void reload() {
Reloader reloader = Lookup.getDefault().lookup(Reloader.class);
reloader.reload();
}
@ServiceProvider(service = NetworkSettings.ProxyCredentialsProvider.class, position = 1000)
public static class NbProxyCredentialsProvider extends NetworkSettings.ProxyCredentialsProvider {
@Override
public String getProxyHost(URI u) {
if (getPreferences() == null) {
return null;
}
InetSocketAddress sa = analyzeProxy(u);
return sa == null ? null : sa.getHostName();
}
@Override
public String getProxyPort(URI u) {
if (getPreferences() == null) {
return null;
}
InetSocketAddress sa = analyzeProxy(u);
return sa == null ? null : Integer.toString(sa.getPort());
}
@Override
protected String getProxyUserName(URI u) {
if (getPreferences() == null) {
return null;
}
return ProxySettings.getAuthenticationUsername();
}
@Override
protected char[] getProxyPassword(URI u) {
if (getPreferences() == null) {
return null;
}
return ProxySettings.getAuthenticationPassword();
}
@Override
protected boolean isProxyAuthentication(URI u) {
if (getPreferences() == null) {
return false;
}
return getPreferences().getBoolean(USE_PROXY_AUTHENTICATION, false);
}
}
/** A bridge between <code>o.n.core</code> and <code>core.network</code>.
* An implementation of this class brings a facility to reload Network Proxy Settings
* from underlying OS.
* The module <code>core.network</code> provides a implementation which may be accessible
* via <code>Lookup.getDefault()</code>. It's not guaranteed any implementation is found on all distribution.
*
* @since 3.40
*/
public abstract static class Reloader {
/** Reloads Network Proxy Settings from underlying system.
*
*/
public abstract void reload();
}
}

View File

@ -0,0 +1,59 @@
/** *************************************************************************
** 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;
/**
* POJO for an auth token request.
*/
public class AuthTokenRequest {
@JsonProperty("autopsy_version")
private String autopsyVersion;
@JsonProperty("boost_license_id")
private String boostLicenseId;
@JsonProperty("requestFileUpload")
private boolean requestFileUpload;
public String getAutopsyVersion() {
return autopsyVersion;
}
public AuthTokenRequest setAutopsyVersion(String autopsyVersion) {
this.autopsyVersion = autopsyVersion;
return this;
}
public String getBoostLicenseId() {
return boostLicenseId;
}
public AuthTokenRequest setBoostLicenseId(String boostLicenseId) {
this.boostLicenseId = boostLicenseId;
return this;
}
public boolean isRequestFileUpload() {
return requestFileUpload;
}
public AuthTokenRequest setRequestFileUpload(boolean requestFileUpload) {
this.requestFileUpload = requestFileUpload;
return this;
}
}

View File

@ -0,0 +1,85 @@
/** *************************************************************************
** 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;
/**
* POJO for an auth token response.
*/
public class AuthTokenResponse {
private final String token;
private final String apiKey;
private final Long hashLookupCount;
private final Long hashLookupLimit;
private final Long fileUploadLimit;
private final Long fileUploadCount;
private final String fileUploadUrl;
private final ZonedDateTime expiration;
@JsonCreator
public AuthTokenResponse(
@JsonProperty("token") String token,
@JsonProperty("api_key") String apiKey,
@JsonProperty("hashLookupCount") Long hashLookupCount,
@JsonProperty("hashLookupLimit") Long hashLookupLimit,
@JsonProperty("fileUploadLimit") Long fileUploadLimit,
@JsonProperty("fileUploadCount") Long fileUploadCount,
@JsonProperty("fileUploadUrl") String fileUploadUrl,
@JsonProperty("expiration") ZonedDateTime expiration
) {
this.token = token;
this.apiKey = apiKey;
this.hashLookupCount = hashLookupCount;
this.hashLookupLimit = hashLookupLimit;
this.fileUploadLimit = fileUploadLimit;
this.fileUploadCount = fileUploadCount;
this.fileUploadUrl = fileUploadUrl;
this.expiration = expiration;
}
public String getToken() {
return token;
}
public String getApiKey() {
return apiKey;
}
public Long getHashLookupCount() {
return hashLookupCount;
}
public Long getHashLookupLimit() {
return hashLookupLimit;
}
public Long getFileUploadLimit() {
return fileUploadLimit;
}
public Long getFileUploadCount() {
return fileUploadCount;
}
public String getFileUploadUrl() {
return fileUploadUrl;
}
public ZonedDateTime getExpiration() {
return expiration;
}
}

View File

@ -0,0 +1,59 @@
/** *************************************************************************
** 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;
/**
* POJO for a boost license response object that is a part of the license
* response.
*/
public class BoostLicenseResponse {
private final String version;
private final String iv;
private final String encryptedKey;
private final String encryptedJson;
@JsonCreator
public BoostLicenseResponse(
@JsonProperty("version") String version,
@JsonProperty("iv") String iv,
@JsonProperty("encryptedKey") String encryptedKey,
@JsonProperty("encryptedJson") String encryptedJson) {
this.version = version;
this.iv = iv;
this.encryptedKey = encryptedKey;
this.encryptedJson = encryptedJson;
}
public String getVersion() {
return version;
}
public String getIv() {
return iv;
}
public String getEncryptedKey() {
return encryptedKey;
}
public String getEncryptedJson() {
return encryptedJson;
}
}

View File

@ -0,0 +1,77 @@
/** *************************************************************************
** 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 - 2016 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.google.common.base.MoreObjects;
import static com.google.common.base.Preconditions.checkArgument;
import org.sleuthkit.datamodel.Score;
import org.sleuthkit.datamodel.Score.Priority;
import org.sleuthkit.datamodel.Score.Significance;
/**
*
* Score class represents a conclusion and the relative confidence in the conclusion about
* a subject. A subject may be an Item, a category/analysis result etc.
* @since 1.7.0
*
*/
public enum CTScore {
/*
Enum names without method defaults to AUTO
NOTABLE -> NOTABLE
*/
// Unknown None
UNKNOWN(new Score(Significance.UNKNOWN, Priority.NORMAL)),
// GOOD_MEDIUM
LIKELY_NONE(new Score(Significance.LIKELY_NONE, Priority.NORMAL)),
// SUSPICIOUS_HIGH / BAD_MEDIUM
LIKELY_NOTABLE(new Score(Significance.LIKELY_NOTABLE, Priority.NORMAL)),
// GOOD_HIGH
NONE(new Score(Significance.NONE, Priority.NORMAL)),
// BAD_HIGH
NOTABLE(new Score(Significance.NOTABLE, Priority.NORMAL)),
// SUSPICIOUS (User flagged)
LIKELY_NOTABLE_MANUAL(new Score(Significance.LIKELY_NOTABLE, Priority.OVERRIDE)),
// Good (User flagged)
NONE_MANUAL(new Score(Significance.NONE, Priority.OVERRIDE)),
// Bad (User flagged)
NOTABLE_MANUAL(new Score(Significance.NOTABLE, Priority.OVERRIDE));
private final Score tskScore;
/**
* Create a CTScore instance based on score
* @param tskScore
*/
private CTScore(Score tskScore) {
checkArgument(tskScore.getSignificance() == Significance.UNKNOWN ? tskScore.getPriority() == Priority.NORMAL : true, "Unknown Conclusions expects no (NORMAL) priority");
this.tskScore = tskScore;
}
public Score getTskCore() {
return tskScore;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("Method Category", tskScore.getPriority())
.add("Significance", tskScore.getSignificance()).toString();
}
}

View File

@ -0,0 +1,87 @@
/** *************************************************************************
** 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;
/**
* POJO for after encrypted boost license has been decrypted.
*/
public class DecryptedLicenseResponse {
private final String boostLicenseId;
private final String licenseHostId;
private final ZonedDateTime expirationDate;
private final Long hashLookups;
private final Long fileUploads;
private final ZonedDateTime activationTime;
private final String product;
private final String limitType;
@JsonCreator
public DecryptedLicenseResponse(
@JsonProperty("boostLicenseId") String boostLicenseId,
@JsonProperty("licenseHostId") String licenseHostId,
@JsonProperty("expirationDate") ZonedDateTime expirationDate,
@JsonProperty("hashLookups") Long hashLookups,
@JsonProperty("fileUploads") Long fileUploads,
@JsonProperty("activationTime") ZonedDateTime activationTime,
@JsonProperty("product") String product,
@JsonProperty("limitType") String limitType
) {
this.boostLicenseId = boostLicenseId;
this.licenseHostId = licenseHostId;
this.expirationDate = expirationDate;
this.hashLookups = hashLookups;
this.fileUploads = fileUploads;
this.activationTime = activationTime;
this.product = product;
this.limitType = limitType;
}
public String getBoostLicenseId() {
return boostLicenseId;
}
public String getLicenseHostId() {
return licenseHostId;
}
public Long getHashLookups() {
return hashLookups;
}
public Long getFileUploads() {
return fileUploads;
}
public ZonedDateTime getActivationTime() {
return activationTime;
}
public String getProduct() {
return product;
}
public String getLimitType() {
return limitType;
}
public ZonedDateTime getExpirationDate() {
return expirationDate;
}
}

View File

@ -0,0 +1,123 @@
/** *************************************************************************
** 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<MetadataLabel> 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<MetadataLabel> 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<MetadataLabel> getMetadata() {
return metadata;
}
public String getStatusDescription() {
return statusDescription;
}
public CorrelationFrequency getFrequency() {
return frequency;
}
public String getFrequencyDescription() {
return frequencyDescription;
}
}

View File

@ -0,0 +1,45 @@
/** *************************************************************************
** 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;
/**
* Contains license info and decrypted boost license.
*/
public class LicenseInfo {
private final LicenseResponse licenseResponse;
private final DecryptedLicenseResponse decryptedLicense;
public LicenseInfo(LicenseResponse licenseResponse, DecryptedLicenseResponse decryptedLicense) {
this.licenseResponse = licenseResponse;
this.decryptedLicense = decryptedLicense;
}
public LicenseResponse getLicenseResponse() {
return licenseResponse;
}
public DecryptedLicenseResponse getDecryptedLicense() {
return decryptedLicense;
}
// TODO
public String getUser() {
return "TBD";
}
// TODO
public String getEmail() {
return "TBD";
}
}

View File

@ -0,0 +1,59 @@
/** *************************************************************************
** 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;
/**
* POJO for license request information.
*/
public class LicenseRequest {
@JsonProperty("host_id")
private String hostId;
@JsonProperty("boost_license_code")
private String boostLicenseCode;
@JsonProperty("product")
private String product;
public String getHostId() {
return hostId;
}
public LicenseRequest setHostId(String hostId) {
this.hostId = hostId;
return this;
}
public String getBoostLicenseCode() {
return boostLicenseCode;
}
public LicenseRequest setBoostLicenseCode(String boostLicenseCode) {
this.boostLicenseCode = boostLicenseCode;
return this;
}
public String getProduct() {
return product;
}
public LicenseRequest setProduct(String product) {
this.product = product;
return this;
}
}

View File

@ -0,0 +1,59 @@
/** *************************************************************************
** 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;
/**
* Response POJO for request for license.
*/
public class LicenseResponse {
private final Boolean success;
private final Boolean hostChanged;
private final Long hostChangesRemaining;
private final BoostLicenseResponse boostLicense;
@JsonCreator
public LicenseResponse(
@JsonProperty("success") Boolean success,
@JsonProperty("hostChanged") Boolean hostChanged,
@JsonProperty("hostChangesRemaining") Long hostChangesRemaining,
@JsonProperty("boostLicense") BoostLicenseResponse boostLicense
) {
this.success = success;
this.hostChanged = hostChanged;
this.hostChangesRemaining = hostChangesRemaining;
this.boostLicense = boostLicense;
}
public Boolean isSuccess() {
return success;
}
public Boolean isHostChanged() {
return hostChanged;
}
public Long getHostChangesRemaining() {
return hostChangesRemaining;
}
public BoostLicenseResponse getBoostLicense() {
return boostLicense;
}
}

View File

@ -0,0 +1,43 @@
/*
* 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
*/
package com.basistech.df.cybertriage.autopsy.ctapi.json;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
*
* @author gregd
*/
public class MetadataLabel {
private final String key;
private final String value;
private final String extendedInfo;
@JsonCreator
public MetadataLabel(
@JsonProperty("key") String key,
@JsonProperty("value") String value,
@JsonProperty("info") String extendedInfo
) {
this.key = key;
this.value = value;
this.extendedInfo = extendedInfo;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
public String getExtendedInfo() {
return extendedInfo;
}
}

View File

@ -0,0 +1,57 @@
/** *************************************************************************
** 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) 2021 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.util;
import com.license4j.HardwareID;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.logging.Level;
import org.apache.commons.lang3.StringUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
* Utility class to generate license hostID and Target hostID for malware scan
*
* @author rishwanth
*/
public class CTHostIDGenerationUtil {
private static final Logger LOGGER = Logger.getLogger(CTHostIDGenerationUtil.class.getName());
private static final String USER_NAME = System.getProperty("user.name");
private static String HOST_NAME = "";
/**
* Host ID Algorithm: Get MAC address from License4J. Get MD5 hash of it and
* grab the first 16 characters of the hash. Get user name that Cyber Triage
* is running as. MD5 hash of user name. Grab first 16 characters.
* Concatenate them and separate with underscore. Example:
* c84f70d1baf96420_7d7519bf21602c24
*
* @return
*/
public static String generateLicenseHostID() {
if (StringUtils.isBlank(HOST_NAME)) {
try {
HOST_NAME = StringUtils.defaultString(InetAddress.getLocalHost().getCanonicalHostName());
} catch (UnknownHostException ex) {
LOGGER.log(Level.WARNING, "UNable to determine host name.", ex);
}
}
String macAddressMd5 = StringUtils.isNotBlank(HardwareID.getHardwareIDFromEthernetAddress()) ? Md5HashUtil.getMD5MessageDigest(HardwareID.getHardwareIDFromEthernetAddress()).substring(0, 16) : Md5HashUtil.getMD5MessageDigest(HOST_NAME).substring(0, 16);
String usernameMd5 = StringUtils.isNotBlank(USER_NAME) ? Md5HashUtil.getMD5MessageDigest(USER_NAME).substring(0, 16) : Md5HashUtil.getMD5MessageDigest(HOST_NAME).substring(0, 16);
String md5 = macAddressMd5 + "_" + usernameMd5;
return md5;
}
}

View File

@ -0,0 +1,172 @@
/** *************************************************************************
** 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.util;
import com.basistech.df.cybertriage.autopsy.ctapi.json.BoostLicenseResponse;
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.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* Decrypts the payload of boost license.
*/
public class LicenseDecryptorUtil {
private static final LicenseDecryptorUtil instance = new LicenseDecryptorUtil();
public static LicenseDecryptorUtil getInstance() {
return instance;
}
private final ObjectMapper objectMapper = ObjectMapperUtil.getInstance().getDefaultObjectMapper();
private LicenseDecryptorUtil() {
}
public LicenseInfo createLicenseInfo(LicenseResponse licenseResponse) throws JsonProcessingException, InvalidLicenseException {
if (licenseResponse == null || licenseResponse.getBoostLicense() == null) {
throw new InvalidLicenseException("License or boost license are null");
}
DecryptedLicenseResponse decrypted = parseLicenseJSON(licenseResponse.getBoostLicense());
return new LicenseInfo(licenseResponse, decrypted);
}
/**
* Decrypts a boost license response.
*
* @param licenseResponse The boost license response.
* @return The decrypted license response.
* @throws JsonProcessingException
* @throws
* com.basistech.df.cybertriage.autopsy.ctapi.util.LicenseDecryptorUtil.InvalidLicenseException
*/
public DecryptedLicenseResponse parseLicenseJSON(BoostLicenseResponse licenseResponse) throws JsonProcessingException, InvalidLicenseException {
String decryptedJsonResponse;
try {
decryptedJsonResponse = decryptLicenseString(
licenseResponse.getEncryptedJson(),
licenseResponse.getIv(),
licenseResponse.getEncryptedKey(),
licenseResponse.getVersion()
);
} catch (IOException | GeneralSecurityException ex) {
throw new InvalidLicenseException("An exception occurred while parsing the license string", ex);
}
DecryptedLicenseResponse decryptedLicense = objectMapper.readValue(decryptedJsonResponse, DecryptedLicenseResponse.class);
if (!"CYBERTRIAGE".equalsIgnoreCase(decryptedLicense.getProduct())) {
// license file is expected to contain product of "CYBERTRIAGE"
throw new InvalidLicenseException("Not a valid Cyber Triage license");
}
return decryptedLicense;
}
private String decryptLicenseString(String encryptedJson, String ivBase64, String encryptedKey, String version) throws IOException, GeneralSecurityException, InvalidLicenseException {
if (!"1.0".equals(version)) {
throw new InvalidLicenseException("Unexpected file version: " + version);
}
byte[] encryptedKeyBytes = Base64.getDecoder().decode(encryptedKey);
byte[] keyBytes = decryptKey(encryptedKeyBytes);
SecretKey key = new SecretKeySpec(keyBytes, 0, keyBytes.length, "AES");
byte[] ivBytes = Base64.getDecoder().decode(ivBase64);
IvParameterSpec iv = new IvParameterSpec(ivBytes);
byte[] encryptedLicenseJsonBytes = Base64.getDecoder().decode(encryptedJson);
String algorithm = "AES/CBC/PKCS5Padding";
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] licenseJsonBytes = cipher.doFinal(encryptedLicenseJsonBytes);
return new String(licenseJsonBytes, StandardCharsets.UTF_8);
}
private PublicKey getPublicKey() throws InvalidKeySpecException, NoSuchAlgorithmException {
String publicKeyString = """
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwIKulLyaLQ2WeO0gIW2G
3jQqny3Y/7VUevBKulAEywaUbvECvZ4zGsnaMyACjXxMNkA1xU2WeSMP/WqC03wz
4d71liUeAqOYKMdGHXFN2qswWz/ufK6An0pTEqYaoiUfcwSBVo2ZTUcMQexScKaS
ghmaWqBHBYx+lBkVMcLG2PtLDRZbqgJvJr2QCzMSVUpEGGQEWs7YolIq46KCgqsq
pTdfrdqd59x6oRhTLegswzxwLyouvrKbRqKR2ZRbVvlGtUnnnlLDuhEfd0flMxuv
W98Siw6dWe1K3x45nDu5py2G9Q9fZS8/2KHUC6QcLLstLIoPnZjCl9Lcur1U6s9N
f5aLI9mwMfmSJsoVOuwx2/MC98uHvPoPbG4ZjiT0aaGg4JccTGD6pssDA35zPhkk
1l6wktEYtyF2A7zjzuFxioQz8fHBzIbHPCxzu4S2gh3qOVFf7c9COmX9MsnB70o2
EZ1rxlFIJ7937IGJNwWOQuiMKTpEeT6BwTdQNZQPqCUGvZ5eEjhrm57yCF4zuyrt
AR8DG7ahK2YAarADHRyxTuxH1qY7E5/CTQKYk9tIYsV4O05CKj7B8rBMtjVNjb4b
d7JwPW43Z3J6jo/gLlVdGSPg8vQDNVLl6sdDM4Pm1eJEzgR2JlqXDCRDUGNNsXH2
qt9Ru8ykX7PAfF2Q3/qg1jkCAwEAAQ==
-----END PUBLIC KEY-----
""";
publicKeyString = publicKeyString.replaceAll("-----BEGIN PUBLIC KEY-----", "").replaceAll("-----END PUBLIC KEY-----", "").replaceAll("\\s", "");
byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyString);
KeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
return publicKey;
}
private byte[] decryptKey(byte[] encryptedKeyBytes) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
PublicKey publicKey = getPublicKey();
Cipher decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, publicKey);
byte[] decryptedBytes = decryptCipher.doFinal(encryptedKeyBytes);
return decryptedBytes;
}
public class InvalidLicenseException extends Exception {
public InvalidLicenseException(String message) {
super(message);
}
public InvalidLicenseException(String message, Throwable cause) {
super(message, cause);
}
}
}

View File

@ -0,0 +1,40 @@
/** *************************************************************************
** 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) 2018 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.util;
import com.google.common.base.Charsets;
import com.google.common.hash.HashCode;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import org.apache.commons.lang3.StringUtils;
/**
*
* @author jayaram
*/
public class Md5HashUtil {
/**
* Returns MD5 hash value for the lower case value of the string provided.
* @param inp
* @return
*/
public static String getMD5MessageDigest(String inp) {
if (StringUtils.isNotBlank(inp)) {
HashFunction hf = Hashing.md5(); // Using despite its deprecation as md5 is good enough for our uses.
HashCode hc = hf.newHasher()
.putString(inp.toLowerCase(), Charsets.UTF_8)
.hash();
return hc.toString();
}
return "";
}
}

View File

@ -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.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
/**
* Creates default ObjectMapper
*/
public class ObjectMapperUtil {
private static final ObjectMapperUtil instance = new ObjectMapperUtil();
public static ObjectMapperUtil getInstance() {
return instance;
}
private ObjectMapperUtil() {
}
public ObjectMapper getDefaultObjectMapper() {
ObjectMapper defaultMapper = new ObjectMapper();
defaultMapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
defaultMapper.registerModule(new JavaTimeModule());
return defaultMapper;
}
}

View File

@ -0,0 +1,5 @@
# Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template
OptionsCategory_Name_CyberTriage=CyberTriage
OptionsCategory_Keywords_CyberTriage=CyberTriage,Cyber,Triage

View File

@ -0,0 +1,5 @@
# Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template
OptionsCategory_Name_CyberTriage=CyberTriage
OptionsCategory_Keywords_CyberTriage=CyberTriage,Cyber,Triage

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,120,0,0,2,2"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
<SubComponents>
<Container class="javax.swing.JScrollPane" name="scrollPane">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription">
<BorderConstraints direction="Center"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="contentPane">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
</Container>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,141 @@
/** *************************************************************************
** 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.ctoptions;
import com.basistech.df.cybertriage.autopsy.ctoptions.subpanel.CTOptionsSubPanel;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.swing.JPanel;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
/**
* Options panel for CyberTriage.
*/
public class CTOptionsPanel extends IngestModuleGlobalSettingsPanel {
private static final int MAX_SUBPANEL_WIDTH = 500;
private static final Logger logger = Logger.getLogger(CTOptionsPanel.class.getName());
private final List<CTOptionsSubPanel> subPanels;
/**
* Creates new form CTOptions
*/
public CTOptionsPanel() {
initComponents();
Collection<? extends CTOptionsSubPanel> coll = Lookup.getDefault().lookupAll(CTOptionsSubPanel.class);
Stream<? extends CTOptionsSubPanel> panelStream = coll != null ? coll.stream() : Stream.empty();
this.subPanels = panelStream
.sorted(Comparator.comparing(p -> p.getClass().getSimpleName().toUpperCase()))
.collect(Collectors.toList());
addSubOptionsPanels(this.subPanels);
}
private void addSubOptionsPanels(List<CTOptionsSubPanel> subPanels) {
for (int i = 0; i < subPanels.size(); i++) {
CTOptionsSubPanel subPanel = subPanels.get(i);
subPanel.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(OptionsPanelController.PROP_CHANGED)) {
CTOptionsPanel.this.firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}
}
});
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = i;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(i == 0 ? 5 : 0, 5, 5, 5);
gridBagConstraints.weighty = 0;
gridBagConstraints.weightx = 0;
contentPane.add(subPanel, gridBagConstraints);
}
GridBagConstraints verticalConstraints = new GridBagConstraints();
verticalConstraints.gridx = 0;
verticalConstraints.gridy = subPanels.size();
verticalConstraints.weighty = 1;
verticalConstraints.weightx = 0;
JPanel verticalSpacer = new JPanel();
verticalSpacer.setMinimumSize(new Dimension(MAX_SUBPANEL_WIDTH, 0));
verticalSpacer.setPreferredSize(new Dimension(MAX_SUBPANEL_WIDTH, 0));
verticalSpacer.setMaximumSize(new Dimension(MAX_SUBPANEL_WIDTH, Short.MAX_VALUE));
contentPane.add(verticalSpacer, verticalConstraints);
GridBagConstraints horizontalConstraints = new GridBagConstraints();
horizontalConstraints.gridx = 1;
horizontalConstraints.gridy = 0;
horizontalConstraints.weighty = 0;
horizontalConstraints.weightx = 1;
JPanel horizontalSpacer = new JPanel();
contentPane.add(horizontalSpacer, horizontalConstraints);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
javax.swing.JScrollPane scrollPane = new javax.swing.JScrollPane();
contentPane = new javax.swing.JPanel();
setLayout(new java.awt.BorderLayout());
contentPane.setLayout(new java.awt.GridBagLayout());
scrollPane.setViewportView(contentPane);
add(scrollPane, java.awt.BorderLayout.CENTER);
}// </editor-fold>//GEN-END:initComponents
@Override
public void saveSettings() {
subPanels.forEach(panel -> panel.saveSettings());
}
public void loadSavedSettings() {
subPanels.forEach(panel -> panel.loadSettings());
}
public boolean valid() {
return subPanels.stream().allMatch(panel -> panel.valid());
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JPanel contentPane;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,128 @@
/** *************************************************************************
** 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.ctoptions;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import javax.swing.JComponent;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
/**
* Options panel controller for CyberTriage.
*/
@OptionsPanelController.TopLevelRegistration(categoryName = "#OptionsCategory_Name_CyberTriage",
iconBase = "com/basistech/df/cybertriage/autopsy/images/logo.png",
position = 999999,
keywords = "#OptionsCategory_Keywords_CyberTriage",
keywordsCategory = "CyberTriage")
public final class CTOptionsPanelController extends OptionsPanelController {
private CTOptionsPanel panel;
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private boolean changed;
/**
* Component should load its data here.
*/
@Override
public void update() {
getPanel().loadSavedSettings();
changed = false;
}
/**
* This method is called when both the Ok and Apply buttons are pressed. It
* applies to any of the panels that have been opened in the process of
* using the options pane.
*/
@Override
public void applyChanges() {
if (changed) {
getPanel().saveSettings();
changed = false;
}
}
/**
* This method is called when the Cancel button is pressed. It applies to
* any of the panels that have been opened in the process of using the
* options pane.
*/
@Override
public void cancel() {
}
@Override
public boolean isValid() {
return getPanel().valid();
}
/**
* Used to determine whether any changes have been made to this controller's
* panel.
*
* @return Whether or not a change has been made.
*/
@Override
public boolean isChanged() {
return changed;
}
@Override
public HelpCtx getHelpCtx() {
return null;
}
@Override
public JComponent getComponent(Lookup masterLookup) {
return getPanel();
}
@Override
public void addPropertyChangeListener(PropertyChangeListener l) {
pcs.addPropertyChangeListener(l);
}
@Override
public void removePropertyChangeListener(PropertyChangeListener l) {
pcs.removePropertyChangeListener(l);
}
private CTOptionsPanel getPanel() {
if (panel == null) {
panel = new CTOptionsPanel();
panel.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(OptionsPanelController.PROP_CHANGED)) {
changed();
}
}
});
}
return panel;
}
void changed() {
if (!changed) {
changed = true;
pcs.firePropertyChange(OptionsPanelController.PROP_CHANGED, false, true);
}
pcs.firePropertyChange(OptionsPanelController.PROP_VALID, null, null);
}
}

View File

@ -0,0 +1,23 @@
# Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template
CTLicenseDialog.licenseNumberLabel.text=License Number:
CTLicenseDialog.licenseNumberTextField.text=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
CTLicenseDialog.cancelButton.text=Cancel
CTLicenseDialog.okButton.text=Ok
CTLicenseDialog.warningLabel.text=
CTMalwareScannerOptionsPanel.hashLookupsRemainingLabel.text=
CTMalwareScannerOptionsPanel.licenseInfoMessageLabel.text=
CTMalwareScannerOptionsPanel.countersResetLabel.text=
CTMalwareScannerOptionsPanel.licenseInfoPanel.border.title=License Info
CTMalwareScannerOptionsPanel.maxFileUploadsLabel.text=
CTMalwareScannerOptionsPanel.maxHashLookupsLabel.text=
CTMalwareScannerOptionsPanel.malwareScansMessageLabel.text=
CTMalwareScannerOptionsPanel.malwareScansPanel.border.title=Malware Scans
CTMalwareScannerOptionsPanel.licenseInfoAddButton.text=Add License
CTMalwareScannerOptionsPanel.licenseInfoIdLabel.text=
CTMalwareScannerOptionsPanel.licenseInfoExpiresLabel.text=
CTMalwareScannerOptionsPanel.fileUploadsRemainingLabel.text=
CTMalwareScannerOptionsPanel.licenseInfoUserLabel.text=

View File

@ -0,0 +1,55 @@
# Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template
CTLicenseDialog.licenseNumberLabel.text=License Number:
CTLicenseDialog.licenseNumberTextField.text=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
CTLicenseDialog.cancelButton.text=Cancel
CTLicenseDialog.okButton.text=Ok
CTLicenseDialog.warningLabel.text=
CTLicenseDialog_verifyInput_licenseNumberError=<html>Please verify license number format of 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'</html>
CTMalwareScannerOptionsPanel.hashLookupsRemainingLabel.text=
CTMalwareScannerOptionsPanel.licenseInfoMessageLabel.text=
CTMalwareScannerOptionsPanel.countersResetLabel.text=
CTMalwareScannerOptionsPanel.licenseInfoPanel.border.title=License Info
CTMalwareScannerOptionsPanel.maxFileUploadsLabel.text=
CTMalwareScannerOptionsPanel.maxHashLookupsLabel.text=
CTMalwareScannerOptionsPanel.malwareScansMessageLabel.text=
CTMalwareScannerOptionsPanel.malwareScansPanel.border.title=Malware Scans
CTMalwareScannerOptionsPanel.licenseInfoAddButton.text=Add License
CTMalwareScannerOptionsPanel.licenseInfoIdLabel.text=
CTMalwareScannerOptionsPanel.licenseInfoExpiresLabel.text=
CTMalwareScannerOptionsPanel.fileUploadsRemainingLabel.text=
CTMalwareScannerOptionsPanel.licenseInfoUserLabel.text=
CTMalwareScannerOptionsPanel_licenseAddDialog_desc=License Number:
CTMalwareScannerOptionsPanel_licenseAddDialog_title=Add a License...
CTMalwareScannerOptionsPanel_licenseAddDialogEnteredErr_desc=The license number has already been entered
CTMalwareScannerOptionsPanel_licenseAddDialogEnteredErr_title=License Number Already Entered
CTMalwareScannerOptionsPanel_licenseAddDialogPatternErr_desc=Please verify that license number is of format 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
CTMalwareScannerOptionsPanel_licenseAddDialogPatternErr_title=Invalid License Number
CTMalwareScannerOptionsPanel_LicenseFetcher_apiErr_title=Server Error
CTMalwareScannerOptionsPanel_LicenseFetcher_localErr_desc=A general error occurred while fetching license information. Please try again later.
CTMalwareScannerOptionsPanel_LicenseFetcher_localErr_title=General Error
# {0} - expiresDate
CTMalwareScannerOptionsPanel_licenseInfo_expires=Expires: {0}
# {0} - idNumber
CTMalwareScannerOptionsPanel_licenseInfo_id=ID: {0}
# {0} - userName
# {1} - email
CTMalwareScannerOptionsPanel_licenseInfo_userInfo=<html>User: {0}<br/>Email: {1}</html>
# {0} - countersResetDate
CTMalwareScannerOptionsPanel_malwareScans_countersReset=Counters reset: {0}
# {0} - fileUploadsRemaining
CTMalwareScannerOptionsPanel_malwareScans_fileUploadsRemaining=File uploads remaining: {0}
# {0} - hashLookupsRemaining
CTMalwareScannerOptionsPanel_malwareScans_hashLookupsRemaining=Hash lookups remaining: {0}
# {0} - maxDailyFileLookups
CTMalwareScannerOptionsPanel_malwareScans_maxDailyFileLookups=Max file uploads: {0}/day
# {0} - maxDailyLookups
CTMalwareScannerOptionsPanel_malwareScans_maxDailyHashLookups=Max Hash lookups: {0}/day
CTMalwareScannerOptionsPanel_MalwareScansFetcher_apiErr_title=Server Error
CTMalwareScannerOptionsPanel_MalwareScansFetcher_localErr_desc=A general error occurred while fetching malware scans information. Please try again later.
CTMalwareScannerOptionsPanel_MalwareScansFetcher_localErr_title=General Error
CTOPtionsPanel_loadLicenseInfo_loading=Loading...
CTOPtionsPanel_loadMalwareScansInfo_loading=Loading...

View File

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
<Properties>
<Property name="defaultCloseOperation" type="int" value="2"/>
<Property name="title" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/Bundle.properties" key="CTLicenseDialog.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="alwaysOnTop" type="boolean" value="true"/>
<Property name="resizable" type="boolean" value="false"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,122,0,0,1,-19"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="licenseNumberLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTLicenseDialog.licenseNumberLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="3" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="warningLabel">
<Properties>
<Property name="foreground" type="java.awt.Color" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="java.awt.Color.RED" type="code"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTLicenseDialog.warningLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[419, 36]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[419, 36]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[419, 36]"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="2" gridWidth="3" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Container class="javax.swing.JPanel" name="buttonPadding">
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</DimensionLayout>
</Layout>
</Container>
<Component class="javax.swing.JButton" name="okButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTLicenseDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okButtonActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="2" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="cancelButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTLicenseDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JTextField" name="licenseNumberTextField">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTLicenseDialog.licenseNumberTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="3" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,192 @@
/** *************************************************************************
** 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.ctoptions.ctcloud;
import java.util.regex.Pattern;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle.Messages;
/**
* License dialog
*/
public class CTLicenseDialog extends javax.swing.JDialog {
private static final Pattern LICENSE_PATTERN = Pattern.compile("^\\s*[0-9a-zA-Z]{8}\\-[0-9a-zA-Z]{4}\\-[0-9a-zA-Z]{4}\\-[0-9a-zA-Z]{4}\\-[0-9a-zA-Z]{12}\\s*$");
private String licenseString = null;
/**
* Creates new form CTLicenseDialog
*/
public CTLicenseDialog(java.awt.Frame parent, boolean modal) {
super(parent, modal);
initComponents();
this.licenseNumberTextField.getDocument().putProperty("filterNewlines", Boolean.TRUE);
this.licenseNumberTextField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent e) {
verifyInput();
}
@Override
public void insertUpdate(DocumentEvent e) {
verifyInput();
}
@Override
public void removeUpdate(DocumentEvent e) {
verifyInput();
}
});
}
String getValue() {
return licenseString;
}
@Messages({
"CTLicenseDialog_verifyInput_licenseNumberError=<html>Please verify license number format of 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'</html>"
})
private void verifyInput() {
String licenseInput = StringUtils.defaultString(this.licenseNumberTextField.getText());
if (LICENSE_PATTERN.matcher(licenseInput).matches()) {
this.warningLabel.setText("");
this.okButton.setEnabled(true);
} else {
this.warningLabel.setText(Bundle.CTLicenseDialog_verifyInput_licenseNumberError());
this.okButton.setEnabled(false);
}
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
javax.swing.JLabel licenseNumberLabel = new javax.swing.JLabel();
warningLabel = new javax.swing.JLabel();
javax.swing.JPanel buttonPadding = new javax.swing.JPanel();
okButton = new javax.swing.JButton();
cancelButton = new javax.swing.JButton();
licenseNumberTextField = new javax.swing.JTextField();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle(org.openide.util.NbBundle.getMessage(CTLicenseDialog.class, "CTLicenseDialog.title")); // NOI18N
setAlwaysOnTop(true);
setResizable(false);
getContentPane().setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(licenseNumberLabel, org.openide.util.NbBundle.getMessage(CTLicenseDialog.class, "CTLicenseDialog.licenseNumberLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
getContentPane().add(licenseNumberLabel, gridBagConstraints);
warningLabel.setForeground(java.awt.Color.RED);
org.openide.awt.Mnemonics.setLocalizedText(warningLabel, org.openide.util.NbBundle.getMessage(CTLicenseDialog.class, "CTLicenseDialog.warningLabel.text")); // NOI18N
warningLabel.setMaximumSize(new java.awt.Dimension(419, 36));
warningLabel.setMinimumSize(new java.awt.Dimension(419, 36));
warningLabel.setPreferredSize(new java.awt.Dimension(419, 36));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
getContentPane().add(warningLabel, gridBagConstraints);
javax.swing.GroupLayout buttonPaddingLayout = new javax.swing.GroupLayout(buttonPadding);
buttonPadding.setLayout(buttonPaddingLayout);
buttonPaddingLayout.setHorizontalGroup(
buttonPaddingLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
);
buttonPaddingLayout.setVerticalGroup(
buttonPaddingLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 0, Short.MAX_VALUE)
);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.weightx = 1.0;
getContentPane().add(buttonPadding, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(CTLicenseDialog.class, "CTLicenseDialog.okButton.text")); // NOI18N
okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
okButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
getContentPane().add(okButton, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(CTLicenseDialog.class, "CTLicenseDialog.cancelButton.text")); // NOI18N
cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
getContentPane().add(cancelButton, gridBagConstraints);
licenseNumberTextField.setText(org.openide.util.NbBundle.getMessage(CTLicenseDialog.class, "CTLicenseDialog.licenseNumberTextField.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
getContentPane().add(licenseNumberTextField, gridBagConstraints);
pack();
}// </editor-fold>//GEN-END:initComponents
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
this.licenseString = this.licenseNumberTextField.getText();
this.dispose();
}//GEN-LAST:event_okButtonActionPerformed
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
this.licenseString = null;
this.dispose();
}//GEN-LAST:event_cancelButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton cancelButton;
private javax.swing.JTextField licenseNumberTextField;
private javax.swing.JButton okButton;
private javax.swing.JLabel warningLabel;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,90 @@
/** *************************************************************************
** 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.ctoptions.ctcloud;
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 com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
/**
* Handles persisting CT Settings.
*/
public class CTLicensePersistence {
private static final String CT_SETTINGS_DIR = "CyberTriage";
private static final String CT_LICENSE_FILENAME = "CyberTriageLicense.json";
private static final Logger logger = Logger.getLogger(CTLicensePersistence.class.getName());
private static final CTLicensePersistence instance = new CTLicensePersistence();
private final ObjectMapper objectMapper = ObjectMapperUtil.getInstance().getDefaultObjectMapper();
public static CTLicensePersistence getInstance() {
return instance;
}
public synchronized boolean saveLicenseResponse(LicenseResponse licenseResponse) {
if (licenseResponse != null) {
File licenseFile = getCTLicenseFile();
try {
objectMapper.writeValue(licenseFile, licenseResponse);
return true;
} catch (IOException ex) {
logger.log(Level.WARNING, "There was an error writing CyberTriage license to file: " + licenseFile.getAbsolutePath(), ex);
}
}
return false;
}
public synchronized Optional<LicenseResponse> loadLicenseResponse() {
Optional<LicenseResponse> toRet = Optional.empty();
File licenseFile = getCTLicenseFile();
if (licenseFile.isFile()) {
try {
toRet = Optional.ofNullable(objectMapper.readValue(licenseFile, LicenseResponse.class));
} catch (IOException ex) {
logger.log(Level.WARNING, "There was an error reading CyberTriage license to file: " + licenseFile.getAbsolutePath(), ex);
}
}
return toRet;
}
public synchronized Optional<LicenseInfo> loadLicenseInfo() {
return loadLicenseResponse().flatMap((license) -> {
try {
return Optional.ofNullable(LicenseDecryptorUtil.getInstance().createLicenseInfo(license));
} catch (JsonProcessingException | LicenseDecryptorUtil.InvalidLicenseException ex) {
logger.log(Level.WARNING, "There was an error decrypting license data from license file", ex);
return Optional.empty();
}
});
}
private File getCTLicenseFile() {
return Paths.get(PlatformUtil.getModuleConfigDirectory(), CT_SETTINGS_DIR, CT_LICENSE_FILENAME).toFile();
}
}

View File

@ -0,0 +1,199 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.8" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
<AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,-109,0,0,1,-29"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Container class="javax.swing.JPanel" name="licenseInfoPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="License Info">
<ResourceString PropertyName="titleX" bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<AuxValues>
<AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="licenseInfoMessageLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoMessageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="2" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="licenseInfoUserLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoUserLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="licenseInfoExpiresLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoExpiresLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="licenseInfoIdLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoIdLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="licenseInfoAddButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.licenseInfoAddButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="licenseInfoAddButtonActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="12" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="malwareScansPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Malware Scans">
<ResourceString PropertyName="titleX" bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.malwareScansPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="malwareScansMessageLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.malwareScansMessageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="2" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="maxHashLookupsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.maxHashLookupsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="maxFileUploadsLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.maxFileUploadsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="countersResetLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.countersResetLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="hashLookupsRemainingLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.hashLookupsRemainingLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JLabel" name="fileUploadsRemainingLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.fileUploadsRemainingLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@ -0,0 +1,551 @@
/** *************************************************************************
** 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.ctoptions.ctcloud;
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.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.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import javax.swing.SwingWorker;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider;
import org.openide.windows.WindowManager;
/**
* Options panel for CyberTriage options for importing a CyberTriage incident
*/
@ServiceProvider(service = CTOptionsSubPanel.class)
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 final CtApiDAO ctApiDAO = CtApiDAO.getInstance();
private final CTLicensePersistence ctPersistence = CTLicensePersistence.getInstance();
private volatile LicenseInfo licenseInfo = null;
private volatile String licenseInfoMessage = null;
private volatile LicenseFetcher licenseFetcher = null;
private volatile AuthTokenResponse authTokenResponse = null;
private volatile String authTokenMessage = null;
private volatile AuthTokenFetcher authTokenFetcher = null;
/**
* Creates new form CTIncidentImportOptionsPanel
*/
public CTMalwareScannerOptionsPanel() {
initComponents();
this.addComponentListener(new ComponentAdapter() {
@Override
public void componentHidden(ComponentEvent e) {
synchronized (CTMalwareScannerOptionsPanel.this) {
if (CTMalwareScannerOptionsPanel.this.isLicenseAddRunning()) {
CTMalwareScannerOptionsPanel.this.licenseFetcher.cancel(true);
CTMalwareScannerOptionsPanel.this.licenseFetcher = null;
}
if (CTMalwareScannerOptionsPanel.this.isMalwareScansRunning()) {
CTMalwareScannerOptionsPanel.this.authTokenFetcher.cancel(true);
CTMalwareScannerOptionsPanel.this.authTokenFetcher = null;
}
}
}
@Override
public void componentShown(ComponentEvent e) {
synchronized (CTMalwareScannerOptionsPanel.this) {
if (CTMalwareScannerOptionsPanel.this.licenseInfo != null) {
loadMalwareScansInfo(CTMalwareScannerOptionsPanel.this.licenseInfo);
}
}
}
}
);
}
@Override
public synchronized void saveSettings() {
ctPersistence.saveLicenseResponse(getLicenseInfo());
}
@Override
public boolean valid() {
return true;
}
@Override
public synchronized void loadSettings() {
Optional<LicenseInfo> licenseInfoOpt = ctPersistence.loadLicenseInfo();
LicenseInfo licenseInfo = licenseInfoOpt.orElse(null);
setLicenseDisplay(licenseInfo, null);
setMalwareScansDisplay(null, null);
if (licenseInfo != null) {
loadMalwareScansInfo(licenseInfo);
}
}
private synchronized LicenseResponse getLicenseInfo() {
return this.licenseInfo == null ? null : this.licenseInfo.getLicenseResponse();
}
private synchronized void setLicenseDisplay(LicenseInfo licenseInfo, String licenseMessage) {
this.licenseInfo = licenseInfo;
this.licenseInfoMessage = licenseMessage;
renderLicenseState();
}
private synchronized void setMalwareScansDisplay(AuthTokenResponse authTokenResponse, String authTokenMessage) {
this.authTokenResponse = authTokenResponse;
this.authTokenMessage = authTokenMessage;
renderLicenseState();
}
/**
* @return True if there is an operation to fetch the license.
*/
private synchronized boolean isLicenseAddRunning() {
return this.licenseFetcher != null && !this.licenseFetcher.isCancelled() && !this.licenseFetcher.isDone();
}
/**
* @return True if there is an operation to fetch malware scans information.
*/
private synchronized boolean isMalwareScansRunning() {
return this.authTokenFetcher != null && !this.authTokenFetcher.isCancelled() && !this.authTokenFetcher.isDone();
}
@Messages({
"CTOPtionsPanel_loadLicenseInfo_loading=Loading..."
})
private synchronized void loadLicenseInfo(String licenseNumber) {
if (isLicenseAddRunning()) {
this.licenseFetcher.cancel(true);
}
setLicenseDisplay(null, Bundle.CTOPtionsPanel_loadLicenseInfo_loading());
this.licenseFetcher = new LicenseFetcher(licenseNumber);
this.licenseFetcher.execute();
}
@Messages({
"CTOPtionsPanel_loadMalwareScansInfo_loading=Loading..."
})
private synchronized void loadMalwareScansInfo(LicenseInfo licenseInfo) {
if (isMalwareScansRunning()) {
this.authTokenFetcher.cancel(true);
}
setMalwareScansDisplay(null, Bundle.CTOPtionsPanel_loadMalwareScansInfo_loading());
if (licenseInfo == null || licenseInfo.getDecryptedLicense() == null) {
return;
}
this.authTokenFetcher = new AuthTokenFetcher(licenseInfo.getDecryptedLicense().getBoostLicenseId());
this.authTokenFetcher.execute();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
javax.swing.JPanel licenseInfoPanel = new javax.swing.JPanel();
licenseInfoMessageLabel = new javax.swing.JLabel();
licenseInfoUserLabel = new javax.swing.JLabel();
licenseInfoExpiresLabel = new javax.swing.JLabel();
licenseInfoIdLabel = new javax.swing.JLabel();
licenseInfoAddButton = new javax.swing.JButton();
malwareScansPanel = new javax.swing.JPanel();
malwareScansMessageLabel = new javax.swing.JLabel();
maxHashLookupsLabel = new javax.swing.JLabel();
maxFileUploadsLabel = new javax.swing.JLabel();
countersResetLabel = new javax.swing.JLabel();
hashLookupsRemainingLabel = new javax.swing.JLabel();
fileUploadsRemainingLabel = new javax.swing.JLabel();
setLayout(new java.awt.GridBagLayout());
licenseInfoPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.licenseInfoPanel.border.title"))); // NOI18N
licenseInfoPanel.setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(licenseInfoMessageLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.licenseInfoMessageLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
licenseInfoPanel.add(licenseInfoMessageLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(licenseInfoUserLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.licenseInfoUserLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
licenseInfoPanel.add(licenseInfoUserLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(licenseInfoExpiresLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.licenseInfoExpiresLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
licenseInfoPanel.add(licenseInfoExpiresLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(licenseInfoIdLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.licenseInfoIdLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
licenseInfoPanel.add(licenseInfoIdLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(licenseInfoAddButton, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.licenseInfoAddButton.text")); // NOI18N
licenseInfoAddButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
licenseInfoAddButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
licenseInfoPanel.add(licenseInfoAddButton, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
add(licenseInfoPanel, gridBagConstraints);
malwareScansPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.malwareScansPanel.border.title"))); // NOI18N
malwareScansPanel.setLayout(new java.awt.GridBagLayout());
org.openide.awt.Mnemonics.setLocalizedText(malwareScansMessageLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.malwareScansMessageLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
malwareScansPanel.add(malwareScansMessageLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(maxHashLookupsLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.maxHashLookupsLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
malwareScansPanel.add(maxHashLookupsLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(maxFileUploadsLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.maxFileUploadsLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
malwareScansPanel.add(maxFileUploadsLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(countersResetLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.countersResetLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
malwareScansPanel.add(countersResetLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(hashLookupsRemainingLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.hashLookupsRemainingLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
malwareScansPanel.add(hashLookupsRemainingLabel, gridBagConstraints);
org.openide.awt.Mnemonics.setLocalizedText(fileUploadsRemainingLabel, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.fileUploadsRemainingLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
malwareScansPanel.add(fileUploadsRemainingLabel, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.weightx = 1.0;
add(malwareScansPanel, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
@Messages({
"CTMalwareScannerOptionsPanel_licenseAddDialog_title=Add a License...",
"CTMalwareScannerOptionsPanel_licenseAddDialog_desc=License Number:",
"CTMalwareScannerOptionsPanel_licenseAddDialogEnteredErr_title=License Number Already Entered",
"CTMalwareScannerOptionsPanel_licenseAddDialogEnteredErr_desc=The license number has already been entered",
"CTMalwareScannerOptionsPanel_licenseAddDialogPatternErr_title=Invalid License Number",
"CTMalwareScannerOptionsPanel_licenseAddDialogPatternErr_desc=Please verify that license number is of format 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'"})
private void licenseInfoAddButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_licenseInfoAddButtonActionPerformed
CTLicenseDialog licenseDialog = new CTLicenseDialog(WindowManager.getDefault().getMainWindow(), true);
licenseDialog.setLocationRelativeTo(this);
licenseDialog.setVisible(true);
String licenseNumber = licenseDialog.getValue();
if (licenseNumber != null) {
synchronized (this) {
if (this.licenseInfo == null || !licenseNumber.trim().equalsIgnoreCase(this.licenseInfo.getDecryptedLicense().getBoostLicenseId())) {
loadLicenseInfo(licenseNumber);
return;
}
}
JOptionPane.showMessageDialog(
this,
Bundle.CTMalwareScannerOptionsPanel_licenseAddDialogEnteredErr_desc(),
Bundle.CTMalwareScannerOptionsPanel_licenseAddDialogEnteredErr_title(),
JOptionPane.INFORMATION_MESSAGE);
}
}//GEN-LAST:event_licenseInfoAddButtonActionPerformed
@NbBundle.Messages({
"# {0} - userName",
"# {1} - email",
"CTMalwareScannerOptionsPanel_licenseInfo_userInfo=<html>User: {0}<br/>Email: {1}</html>",
"# {0} - expiresDate",
"CTMalwareScannerOptionsPanel_licenseInfo_expires=Expires: {0}",
"# {0} - idNumber",
"CTMalwareScannerOptionsPanel_licenseInfo_id=ID: {0}",
"# {0} - maxDailyLookups",
"CTMalwareScannerOptionsPanel_malwareScans_maxDailyHashLookups=Max Hash lookups: {0}/day",
"# {0} - maxDailyFileLookups",
"CTMalwareScannerOptionsPanel_malwareScans_maxDailyFileLookups=Max file uploads: {0}/day",
"# {0} - countersResetDate",
"CTMalwareScannerOptionsPanel_malwareScans_countersReset=Counters reset: {0}",
"# {0} - hashLookupsRemaining",
"CTMalwareScannerOptionsPanel_malwareScans_hashLookupsRemaining=Hash lookups remaining: {0}",
"# {0} - fileUploadsRemaining",
"CTMalwareScannerOptionsPanel_malwareScans_fileUploadsRemaining=File uploads remaining: {0}"})
private synchronized void renderLicenseState() {
this.licenseInfoAddButton.setEnabled(!isLicenseAddRunning());
this.licenseInfoMessageLabel.setVisible(StringUtils.isNotBlank(this.licenseInfoMessage));
this.licenseInfoMessageLabel.setText(this.licenseInfoMessage);
if (licenseInfo == null) {
this.licenseInfoExpiresLabel.setVisible(false);
this.licenseInfoIdLabel.setVisible(false);
this.licenseInfoUserLabel.setVisible(false);
} else {
this.licenseInfoExpiresLabel.setVisible(true);
this.licenseInfoExpiresLabel.setText(Bundle.CTMalwareScannerOptionsPanel_licenseInfo_expires(LICENSE_EXPIRES_FORMAT.format(this.licenseInfo.getDecryptedLicense().getExpirationDate())));
this.licenseInfoIdLabel.setVisible(true);
this.licenseInfoIdLabel.setText(Bundle.CTMalwareScannerOptionsPanel_licenseInfo_id(this.licenseInfo.getDecryptedLicense().getBoostLicenseId()));
this.licenseInfoUserLabel.setVisible(true);
this.licenseInfoUserLabel.setText(Bundle.CTMalwareScannerOptionsPanel_licenseInfo_userInfo(this.licenseInfo.getUser(), this.licenseInfo.getEmail()));
}
this.malwareScansPanel.setVisible(StringUtils.isNotBlank(this.authTokenMessage) || authTokenResponse != null);
this.malwareScansMessageLabel.setVisible(StringUtils.isNotBlank(this.authTokenMessage));
this.malwareScansMessageLabel.setText(this.authTokenMessage);
if (authTokenResponse == null) {
this.maxHashLookupsLabel.setVisible(false);
this.maxFileUploadsLabel.setVisible(false);
this.countersResetLabel.setVisible(false);
this.hashLookupsRemainingLabel.setVisible(false);
this.fileUploadsRemainingLabel.setVisible(false);
} else {
this.maxHashLookupsLabel.setVisible(true);
this.maxHashLookupsLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_maxDailyHashLookups(this.authTokenResponse.getHashLookupLimit()));
this.maxFileUploadsLabel.setVisible(true);
this.maxFileUploadsLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_maxDailyFileLookups(this.authTokenResponse.getFileUploadLimit()));
this.countersResetLabel.setVisible(true);
this.countersResetLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_countersReset(MALWARE_SCANS_RESET_FORMAT.format(this.authTokenResponse.getExpiration())));
this.hashLookupsRemainingLabel.setVisible(true);
this.hashLookupsRemainingLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_hashLookupsRemaining(remaining(this.authTokenResponse.getHashLookupLimit(), this.authTokenResponse.getHashLookupCount())));
this.fileUploadsRemainingLabel.setVisible(true);
this.fileUploadsRemainingLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_fileUploadsRemaining(remaining(this.authTokenResponse.getFileUploadLimit(), this.authTokenResponse.getFileUploadCount())));
}
}
private long remaining(Long total, Long used) {
total = total == null ? 0 : total;
used = used == null ? 0 : used;
return total - used;
}
@NbBundle.Messages({
"CTMalwareScannerOptionsPanel_LicenseFetcher_apiErr_title=Server Error",
"CTMalwareScannerOptionsPanel_LicenseFetcher_localErr_title=General Error",
"CTMalwareScannerOptionsPanel_LicenseFetcher_localErr_desc=A general error occurred while fetching license information. Please try again later.",})
private class LicenseFetcher extends SwingWorker<LicenseInfo, Void> {
private final String licenseText;
public LicenseFetcher(String licenseText) {
this.licenseText = licenseText;
}
@Override
protected LicenseInfo doInBackground() throws Exception {
LicenseResponse licenseResponse = ctApiDAO.getLicenseInfo(licenseText);
ctPersistence.saveLicenseResponse(licenseResponse);
return LicenseDecryptorUtil.getInstance().createLicenseInfo(licenseResponse);
}
@Override
protected void done() {
LicenseInfo licenseInfo = null;
try {
licenseInfo = get();
} catch (InterruptedException ex) {
// ignore cancellation
} catch (ExecutionException ex) {
if (ex.getCause() != null && ex.getCause() instanceof CTCloudException cloudEx) {
logger.log(Level.WARNING, "An API error occurred while fetching license information", cloudEx);
JOptionPane.showMessageDialog(
CTMalwareScannerOptionsPanel.this,
cloudEx.getErrorCode().getDescription(),
Bundle.CTMalwareScannerOptionsPanel_LicenseFetcher_apiErr_title(),
JOptionPane.ERROR_MESSAGE);
} else {
logger.log(Level.WARNING, "An error occurred while fetching data", ex);
JOptionPane.showMessageDialog(
CTMalwareScannerOptionsPanel.this,
Bundle.CTMalwareScannerOptionsPanel_LicenseFetcher_localErr_desc(),
Bundle.CTMalwareScannerOptionsPanel_LicenseFetcher_localErr_title(),
JOptionPane.ERROR_MESSAGE);
}
} finally {
synchronized (CTMalwareScannerOptionsPanel.this) {
CTMalwareScannerOptionsPanel.this.licenseFetcher = null;
if (!this.isCancelled()) {
setLicenseDisplay(licenseInfo, null);
loadMalwareScansInfo(licenseInfo);
}
}
}
}
}
@NbBundle.Messages({
"CTMalwareScannerOptionsPanel_MalwareScansFetcher_apiErr_title=Server Error",
"CTMalwareScannerOptionsPanel_MalwareScansFetcher_localErr_title=General Error",
"CTMalwareScannerOptionsPanel_MalwareScansFetcher_localErr_desc=A general error occurred while fetching malware scans information. Please try again later.",})
private class AuthTokenFetcher extends SwingWorker<AuthTokenResponse, Void> {
private final String boostLicenseId;
public AuthTokenFetcher(String boostLicenseId) {
this.boostLicenseId = boostLicenseId;
}
@Override
protected AuthTokenResponse doInBackground() throws Exception {
return ctApiDAO.getAuthToken(boostLicenseId);
}
@Override
protected void done() {
AuthTokenResponse authTokenResponse = null;
try {
authTokenResponse = get();
} catch (InterruptedException ex) {
// ignore cancellation
} catch (ExecutionException ex) {
if (ex.getCause() != null && ex.getCause() instanceof CTCloudException cloudEx) {
logger.log(Level.WARNING, "An API error occurred while fetching malware scans information for license", cloudEx);
JOptionPane.showMessageDialog(
CTMalwareScannerOptionsPanel.this,
cloudEx.getErrorDetails(),
Bundle.CTMalwareScannerOptionsPanel_MalwareScansFetcher_apiErr_title(),
JOptionPane.ERROR_MESSAGE);
} else {
logger.log(Level.WARNING, "An error occurred while fetching data", ex);
JOptionPane.showMessageDialog(
CTMalwareScannerOptionsPanel.this,
Bundle.CTMalwareScannerOptionsPanel_MalwareScansFetcher_localErr_desc(),
Bundle.CTMalwareScannerOptionsPanel_MalwareScansFetcher_localErr_title(),
JOptionPane.ERROR_MESSAGE);
}
} finally {
synchronized (CTMalwareScannerOptionsPanel.this) {
CTMalwareScannerOptionsPanel.this.authTokenFetcher = null;
if (!this.isCancelled()) {
setMalwareScansDisplay(authTokenResponse, null);
}
}
}
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel countersResetLabel;
private javax.swing.JLabel fileUploadsRemainingLabel;
private javax.swing.JLabel hashLookupsRemainingLabel;
private javax.swing.JButton licenseInfoAddButton;
private javax.swing.JLabel licenseInfoExpiresLabel;
private javax.swing.JLabel licenseInfoIdLabel;
private javax.swing.JLabel licenseInfoMessageLabel;
private javax.swing.JLabel licenseInfoUserLabel;
private javax.swing.JLabel malwareScansMessageLabel;
private javax.swing.JPanel malwareScansPanel;
private javax.swing.JLabel maxFileUploadsLabel;
private javax.swing.JLabel maxHashLookupsLabel;
// End of variables declaration//GEN-END:variables
}

View File

@ -0,0 +1,26 @@
/** *************************************************************************
** 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.ctoptions.subpanel;
import javax.swing.JPanel;
/**
* A panel to be put in the CyberTriage options.
*/
public abstract class CTOptionsSubPanel extends JPanel {
public abstract void loadSettings();
public abstract void saveSettings();
public abstract boolean valid();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,88 @@
/** *************************************************************************
** 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.malwarescan;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.function.Consumer;
/**
* Processes a batch when number of items reaches batchSize or flush. Processing
* blocks (and subsequently add and flush operations) until previous batch
* finishes.
*/
public class BatchProcessor<T> {
private final ExecutorService processingExecutorService = Executors.newSingleThreadExecutor();
private final BlockingQueue<T> batchingQueue;
private final List<T> processingQueue;
private final int batchSize;
private final Consumer<List<T>> itemsConsumer;
private final long millisTimeout;
private Future<?> lastProcessingFuture = CompletableFuture.runAsync(() -> {
});
public BatchProcessor(int batchSize, long millisTimeout, Consumer<List<T>> itemsConsumer) {
this.batchingQueue = new LinkedBlockingQueue<>(batchSize);
this.processingQueue = new ArrayList<>(batchSize);
this.batchSize = batchSize;
this.itemsConsumer = itemsConsumer;
this.millisTimeout = millisTimeout;
}
public synchronized void clearCurrentBatch() {
batchingQueue.clear();
}
public synchronized void flush(boolean blockUntilFinished) throws InterruptedException {
asyncProcessBatch();
if (blockUntilFinished) {
lastProcessingFuture.wait(millisTimeout);
}
}
public synchronized void add(T item) throws InterruptedException {
batchingQueue.add(item);
if (batchingQueue.size() >= batchSize) {
asyncProcessBatch();
}
}
private synchronized void asyncProcessBatch() throws InterruptedException {
if (!batchingQueue.isEmpty()) {
// wait for previous processing to finish
lastProcessingFuture.wait(millisTimeout);
// if 'andThen' doesn't run, clear the processing queue
processingQueue.clear();
// transfer batching queue to processing queue
batchingQueue.drainTo(processingQueue);
// submit to processor and then clear processing queue
lastProcessingFuture = processingExecutorService.submit(
() -> itemsConsumer.andThen(processingQueue -> processingQueue.clear()).accept(processingQueue)
);
}
}
}

View File

@ -0,0 +1,23 @@
MalwareScanIngestModule_malwareTypeDisplayName=Malware
# {0} - errorResponse
MalwareScanIngestModule_SharedProcessing_authTokenResponseError_desc=Received error: ''{0}'' when fetching the API authentication token for the license
MalwareScanIngestModule_SharedProcessing_authTokenResponseError_title=Authentication API error
MalwareScanIngestModule_SharedProcessing_createAnalysisResult_No=NO
MalwareScanIngestModule_SharedProcessing_createAnalysisResult_Yes=YES
MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_desc=The remaining hash lookups for this license have been exhausted
MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_title=Hash Lookups Exhausted
MalwareScanIngestModule_SharedProcessing_flushTimeout_desc=A timeout occurred while finishing processing
MalwareScanIngestModule_SharedProcessing_flushTimeout_title=Processing Timeout
MalwareScanIngestModule_SharedProcessing_generalProcessingError_desc=An error occurred while processing hash lookup results
MalwareScanIngestModule_SharedProcessing_generalProcessingError_title=Hash Lookup Error
# {0} - errorResponse
MalwareScanIngestModule_SharedProcessing_repServicenResponseError_desc=Received error: ''{0}'' when fetching hash lookup results
MalwareScanIngestModule_SharedProcessing_repServicenResponseError_title=Lookup API error
MalwareScanIngestModule_ShareProcessing_batchTimeout_desc=Batch processing timed out
MalwareScanIngestModule_ShareProcessing_batchTimeout_title=Batch Processing Timeout
# {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_version=1.0.0

View File

@ -0,0 +1,395 @@
/** *************************************************************************
** 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.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.LicenseInfo;
import com.basistech.df.cybertriage.autopsy.ctoptions.ctcloud.CTLicensePersistence;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestJobContext;
import org.sleuthkit.autopsy.ingest.IngestModule;
import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Blackboard;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.Score;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskData;
/**
* Uses CT cloud API to determine if file is malware
*/
public class MalwareScanIngestModule implements FileIngestModule {
private static final SharedProcessing sharedProcessing = new SharedProcessing();
@Override
public void startUp(IngestJobContext context) throws IngestModuleException {
sharedProcessing.startUp(context);
}
@Override
public ProcessResult process(AbstractFile af) {
return sharedProcessing.process(af);
}
@Override
public void shutDown() {
sharedProcessing.shutDown();
}
/**
* Does the bulk of processing for the ingest module and handles concurrent
* ingest modules adding files simultaneously.
*/
private static class SharedProcessing {
// batch size of 200 files max
private static final int BATCH_SIZE = 200;
// 3 minute timeout for an API request
private static final long BATCH_MILLIS_TIMEOUT = 3 * 60 * 1000;
//minimum lookups left before issuing warning
private static final long LOW_LOOKUPS_REMAINING = 250;
private static final Set<String> EXECUTABLE_MIME_TYPES = Stream.of(
"application/x-bat",//NON-NLS
"application/x-dosexec",//NON-NLS
"application/vnd.microsoft.portable-executable",//NON-NLS
"application/x-msdownload",//NON-NLS
"application/exe",//NON-NLS
"application/x-exe",//NON-NLS
"application/dos-exe",//NON-NLS
"vms/exe",//NON-NLS
"application/x-winexe",//NON-NLS
"application/msdos-windows",//NON-NLS
"application/x-msdos-program"//NON-NLS
).collect(Collectors.toSet());
private static final String MALWARE_TYPE_NAME = "TSK_MALWARE";
private static final String MALWARE_CONFIG = "Cyber Triage Cloud";
private static final Logger logger = Logger.getLogger(MalwareScanIngestModule.class.getName());
private final BatchProcessor<FileRecord> batchProcessor = new BatchProcessor<FileRecord>(BATCH_SIZE, BATCH_MILLIS_TIMEOUT, this::handleBatch);
private final CTLicensePersistence ctSettingsPersistence = CTLicensePersistence.getInstance();
private final CtApiDAO ctApiDAO = CtApiDAO.getInstance();
private FileTypeDetector fileTypeDetector;
private RunState runState = null;
private SleuthkitCase tskCase = null;
private LicenseInfo licenseInfo = null;
private BlackboardArtifact.Type malwareType = null;
private boolean noMoreHashLookups = false;
private IngestModuleException startupException;
private long dsId = 0;
@Messages({
"MalwareScanIngestModule_ShareProcessing_lowLimitWarning_title=Hash Lookups Low",
"# {0} - remainingLookups",
"MalwareScanIngestModule_ShareProcessing_lowLimitWarning_desc=This license only has {0} lookups remaining",
"MalwareScanIngestModule_malwareTypeDisplayName=Malware"
})
synchronized void startUp(IngestJobContext context) throws IngestModuleException {
// only run this code once per startup
if (runState == RunState.STARTED_UP) {
if (startupException != null) {
throw startupException;
} else {
return;
}
}
try {
// get saved license
Optional<LicenseInfo> licenseInfoOpt = ctSettingsPersistence.loadLicenseInfo();
if (licenseInfoOpt.isEmpty() || licenseInfoOpt.get().getDecryptedLicense() == null) {
throw new IngestModuleException("No saved license was found");
}
String licenseStr = licenseInfoOpt.get().getDecryptedLicense().getBoostLicenseId();
AuthTokenResponse authTokenResponse = ctApiDAO.getAuthToken(licenseStr);
// syncronously fetch malware scans info
// determine lookups remaining
long lookupsRemaining = remaining(authTokenResponse.getHashLookupLimit(), authTokenResponse.getHashLookupCount());
if (lookupsRemaining <= 0) {
throw new IngestModuleException("There are no more file hash lookups for this license");
} else if (lookupsRemaining < LOW_LOOKUPS_REMAINING) {
notifyWarning(
Bundle.MalwareScanIngestModule_ShareProcessing_lowLimitWarning_title(),
Bundle.MalwareScanIngestModule_ShareProcessing_lowLimitWarning_desc(lookupsRemaining),
null);
}
// setup necessary variables for processing
tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
malwareType = tskCase.getBlackboard().getOrAddArtifactType(
MALWARE_TYPE_NAME,
Bundle.MalwareScanIngestModule_malwareTypeDisplayName(),
BlackboardArtifact.Category.ANALYSIS_RESULT);
fileTypeDetector = new FileTypeDetector();
dsId = context.getDataSource().getId();
licenseInfo = licenseInfoOpt.get();
startupException = null;
noMoreHashLookups = false;
} catch (IngestModuleException ex) {
startupException = ex;
throw startupException;
} catch (Exception ex) {
startupException = new IngestModuleException("An exception occurred on MalwareScanIngestModule startup", ex);
throw startupException;
}
}
private static long remaining(Long limit, Long used) {
limit = limit == null ? 0 : limit;
used = used == null ? 0 : used;
return limit - used;
}
@Messages({
"MalwareScanIngestModule_ShareProcessing_batchTimeout_title=Batch Processing Timeout",
"MalwareScanIngestModule_ShareProcessing_batchTimeout_desc=Batch processing timed out"
})
IngestModule.ProcessResult process(AbstractFile af) {
try {
if (af.getKnown() != TskData.FileKnown.KNOWN
&& EXECUTABLE_MIME_TYPES.contains(StringUtils.defaultString(fileTypeDetector.getMIMEType(af)).trim().toLowerCase())) {
batchProcessor.add(new FileRecord(af.getId(), af.getMd5Hash()));
}
return ProcessResult.OK;
} catch (InterruptedException ex) {
notifyWarning(
Bundle.MalwareScanIngestModule_ShareProcessing_batchTimeout_title(),
Bundle.MalwareScanIngestModule_ShareProcessing_batchTimeout_desc(),
ex);
return IngestModule.ProcessResult.ERROR;
}
}
@Messages({
"MalwareScanIngestModule_SharedProcessing_authTokenResponseError_title=Authentication API error",
"# {0} - errorResponse",
"MalwareScanIngestModule_SharedProcessing_authTokenResponseError_desc=Received error: ''{0}'' when fetching the API authentication token for the license",
"MalwareScanIngestModule_SharedProcessing_repServicenResponseError_title=Lookup API error",
"# {0} - errorResponse",
"MalwareScanIngestModule_SharedProcessing_repServicenResponseError_desc=Received error: ''{0}'' when fetching hash lookup results",
"MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_title=Hash Lookups Exhausted",
"MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_desc=The remaining hash lookups for this license have been exhausted",
"MalwareScanIngestModule_SharedProcessing_generalProcessingError_title=Hash Lookup Error",
"MalwareScanIngestModule_SharedProcessing_generalProcessingError_desc=An error occurred while processing hash lookup results",})
private void handleBatch(List<FileRecord> fileRecords) {
if (fileRecords == null || fileRecords.isEmpty() || noMoreHashLookups) {
return;
}
// create mapping of md5 to corresponding object ids as well as just the list of md5's
Map<String, List<Long>> md5ToObjId = new HashMap<>();
List<String> md5Hashes = new ArrayList<>();
for (FileRecord fr : fileRecords) {
if (fr == null || StringUtils.isBlank(fr.getMd5hash()) || fr.getObjId() <= 0) {
continue;
}
String sanitizedMd5 = sanitizedMd5(fr.getMd5hash());
md5ToObjId
.computeIfAbsent(sanitizedMd5, (k) -> new ArrayList<>())
.add(fr.getObjId());
md5Hashes.add(sanitizedMd5);
}
if (md5Hashes.isEmpty()) {
return;
}
try {
// get an auth token with the license
AuthTokenResponse authTokenResponse = ctApiDAO.getAuthToken(licenseInfo.getDecryptedLicense().getBoostLicenseId());
// make sure we are in bounds for the remaining scans
long remainingScans = remaining(authTokenResponse.getHashLookupLimit(), authTokenResponse.getHashLookupCount());
if (remainingScans <= 0) {
noMoreHashLookups = true;
notifyWarning(
Bundle.MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_title(),
Bundle.MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_desc(),
null);
return;
}
// if the size of this batch will exceed limit, shrink list to limit and fail after processing
boolean exceededScanLimit = false;
if (remainingScans < md5Hashes.size()) {
md5Hashes = md5Hashes.subList(0, (int) remainingScans);
exceededScanLimit = true;
}
// using auth token, get results
List<FileReputationResult> repResult = ctApiDAO.getReputationResults(authTokenResponse.getToken(), md5Hashes);
if (repResult != null && !repResult.isEmpty()) {
SleuthkitCase.CaseDbTransaction trans = null;
try {
trans = tskCase.beginTransaction();
for (FileReputationResult result : repResult) {
String sanitizedMd5 = sanitizedMd5(result.getMd5Hash());
List<Long> objIds = md5ToObjId.remove(sanitizedMd5);
if (objIds == null || objIds.isEmpty()) {
continue;
}
for (Long objId : objIds) {
createAnalysisResult(objId, result, trans);
}
}
trans.commit();
trans = null;
} finally {
if (trans != null) {
trans.rollback();
trans = null;
}
}
// if we only processed part of the batch, after processing, notify that we are out of scans.
if (exceededScanLimit) {
noMoreHashLookups = true;
notifyWarning(
Bundle.MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_title(),
Bundle.MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_desc(),
null);
return;
}
}
} catch (Exception ex) {
notifyWarning(
Bundle.MalwareScanIngestModule_SharedProcessing_generalProcessingError_title(),
Bundle.MalwareScanIngestModule_SharedProcessing_generalProcessingError_desc(),
ex);
}
}
private String sanitizedMd5(String orig) {
return StringUtils.defaultString(orig).trim().toLowerCase();
}
@Messages({
"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) {
return;
}
Score score = fileReputationResult.getScore() == null ? Score.SCORE_UNKNOWN : fileReputationResult.getScore().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();
tskCase.getBlackboard().newAnalysisResult(
malwareType,
objId,
dsId,
score,
conclusion,
MALWARE_CONFIG,
justification,
Collections.emptyList(),
trans);
}
@Messages({
"MalwareScanIngestModule_SharedProcessing_flushTimeout_title=Processing Timeout",
"MalwareScanIngestModule_SharedProcessing_flushTimeout_desc=A timeout occurred while finishing processing"
})
synchronized void shutDown() {
// if already shut down, return
if (runState == RunState.SHUT_DOWN) {
return;
}
// flush any remaining items
try {
batchProcessor.flush(true);
} catch (InterruptedException ex) {
notifyWarning(
Bundle.MalwareScanIngestModule_SharedProcessing_flushTimeout_title(),
Bundle.MalwareScanIngestModule_SharedProcessing_flushTimeout_desc(),
ex);
} finally {
// set state to shut down and clear any remaining
malwareType = null;
fileTypeDetector = null;
noMoreHashLookups = false;
runState = RunState.SHUT_DOWN;
startupException = null;
batchProcessor.clearCurrentBatch();
}
}
private void notifyWarning(String title, String message, Exception ex) {
MessageNotifyUtil.Notify.warn(title, message);
logger.log(Level.WARNING, message, ex);
}
private enum RunState {
STARTED_UP, SHUT_DOWN
}
class FileRecord {
private final long objId;
private final String md5hash;
FileRecord(long objId, String md5hash) {
this.objId = objId;
this.md5hash = md5hash;
}
long getObjId() {
return objId;
}
String getMd5hash() {
return md5hash;
}
}
}
}

View File

@ -0,0 +1,72 @@
/** *************************************************************************
** 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.malwarescan;
import com.basistech.df.cybertriage.autopsy.ctoptions.CTOptionsPanel;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
/**
* Factory for malware scan ingest modules.
*/
@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_version=1.0.0"
})
public class MalwareScanIngestModuleFactory extends IngestModuleFactoryAdapter {
@Override
public String getModuleDisplayName() {
return Bundle.MalwareScanIngestModuleFactory_displayName();
}
@Override
public String getModuleDescription() {
return Bundle.MalwareScanIngestModuleFactory_description();
}
@Override
public String getModuleVersionNumber() {
return Bundle.MalwareScanIngestModuleFactory_version();
}
@Override
public boolean isFileIngestModuleFactory() {
return true;
}
@Override
public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings ingestOptions) {
return new MalwareScanIngestModule();
}
@Override
public boolean hasGlobalSettingsPanel() {
return true;
}
@Override
public IngestModuleGlobalSettingsPanel getGlobalSettingsPanel() {
CTOptionsPanel optionsPanel = new CTOptionsPanel();
optionsPanel.loadSavedSettings();
return optionsPanel;
}
}

View File

@ -1,5 +1,6 @@
<!DOCTYPE ivy-module [
<!ENTITY javafx.version "17.0.7">
<!ENTITY jackson.version "2.15.2">
]>
<ivy-module version="2.0" xmlns:e="http://ant.apache.org/ivy/extra">
<info organisation="org.sleuthkit.autopsy" module="corelibs"/>
@ -87,7 +88,8 @@
<dependency conf="autopsy_core->default" org="net.htmlparser.jericho" name="jericho-html" rev="3.4"/>
<dependency conf="autopsy_core->default" org="com.fasterxml.jackson.dataformat" name="jackson-dataformat-csv" rev="2.15.2"/>
<dependency conf="autopsy_core->default" org="com.fasterxml.jackson.dataformat" name="jackson-dataformat-csv" rev="&jackson.version;"/>
<dependency conf="autopsy_core->default" org="com.fasterxml.jackson.datatype" name="jackson-datatype-jsr310" rev="&jackson.version;"/>
<!-- better image resizing -->
<dependency conf="autopsy_core->default" org="org.imgscalr" name="imgscalr-lib" rev="4.2" />
@ -142,8 +144,8 @@
<override org="com.google.code.gson" module="gson" rev="2.9.0"/>
<override org="com.google.guava" module="guava" rev="32.0.1-jre"/>
<override org="com.fasterxml.jackson.core" module="jackson-databind" rev="2.15.2"/>
<override org="com.fasterxml.jackson.core" module="jackson-core" rev="2.15.2"/>
<override org="com.fasterxml.jackson.core" module="jackson-databind" rev="&jackson.version;"/>
<override org="com.fasterxml.jackson.core" module="jackson-core" rev="&jackson.version;"/>
<!-- changes to bouncy castle version may also be reflected in thirdparty/IcePDF 6.2.2 -->
<override org="org.bouncycastle" module="bcprov-jdk15on" rev="1.70"/>

View File

@ -84,6 +84,7 @@ file.reference.jackson-annotations-2.15.2.jar=release/modules/ext/jackson-annota
file.reference.jackson-core-2.15.2.jar=release/modules/ext/jackson-core-2.15.2.jar
file.reference.jackson-databind-2.15.2.jar=release/modules/ext/jackson-databind-2.15.2.jar
file.reference.jackson-dataformat-csv-2.15.2.jar=release/modules/ext/jackson-dataformat-csv-2.15.2.jar
file.reference.jackson-datatype-jsr310-2.15.2.jar=release/modules/ext/jackson-datatype-jsr310-2.15.2.jar
file.reference.javafx-base-17.0.7-linux.jar=release/modules/ext/javafx-base-17.0.7-linux.jar
file.reference.javafx-base-17.0.7-mac.jar=release/modules/ext/javafx-base-17.0.7-mac.jar
file.reference.javafx-base-17.0.7-win.jar=release/modules/ext/javafx-base-17.0.7-win.jar

View File

@ -63,6 +63,8 @@
<package>com.fasterxml.jackson.databind.type</package>
<package>com.fasterxml.jackson.databind.util</package>
<package>com.fasterxml.jackson.dataformat.csv</package>
<package>com.fasterxml.jackson.datatype.jsr310</package>
<package>com.fasterxml.jackson.datatype.jsr310.util</package>
<package>com.github.lgooddatepicker.components</package>
<package>com.github.lgooddatepicker.optionalusertools</package>
<package>com.github.lgooddatepicker.zinternaltools</package>
@ -197,8 +199,6 @@
<package>com.google.rpc.context</package>
<package>com.google.thirdparty.publicsuffix</package>
<package>com.google.type</package>
<package>com.microsoft.schemas.vml</package>
<package>com.microsoft.schemas.vml.impl</package>
<package>com.sun.javafx</package>
<package>com.sun.javafx.animation</package>
<package>com.sun.javafx.application</package>
@ -321,9 +321,6 @@
<package>com.twelvemonkeys.util.regex</package>
<package>com.twelvemonkeys.util.service</package>
<package>com.twelvemonkeys.xml</package>
<package>javax.annotation</package>
<package>javax.annotation.concurrent</package>
<package>javax.annotation.meta</package>
<package>javafx.animation</package>
<package>javafx.application</package>
<package>javafx.beans</package>
@ -340,7 +337,6 @@
<package>javafx.event</package>
<package>javafx.fxml</package>
<package>javafx.geometry</package>
<package>javafx.graphics</package>
<package>javafx.print</package>
<package>javafx.scene</package>
<package>javafx.scene.canvas</package>
@ -362,19 +358,9 @@
<package>javafx.stage</package>
<package>javafx.util</package>
<package>javafx.util.converter</package>
<package>javax.jms</package>
<package>javax.mail</package>
<package>javax.mail.event</package>
<package>javax.mail.internet</package>
<package>javax.mail.search</package>
<package>javax.mail.util</package>
<package>javax.servlet</package>
<package>javax.servlet.http</package>
<package>javax.xml.parsers</package>
<package>javax.xml.transform</package>
<package>javax.xml.transform.dom</package>
<package>javax.xml.transform.sax</package>
<package>javax.xml.transform.stream</package>
<package>javax.annotation</package>
<package>javax.annotation.concurrent</package>
<package>javax.annotation.meta</package>
<package>jfxtras.animation</package>
<package>jfxtras.css</package>
<package>jfxtras.css.converters</package>
@ -442,16 +428,6 @@
<package>org.apache.commons.lang3.tuple</package>
<package>org.apache.commons.logging</package>
<package>org.apache.commons.logging.impl</package>
<package>org.apache.log</package>
<package>org.apache.log.filter</package>
<package>org.apache.log.format</package>
<package>org.apache.log.output</package>
<package>org.apache.log.output.db</package>
<package>org.apache.log.output.io</package>
<package>org.apache.log.output.io.rotate</package>
<package>org.apache.log.output.jms</package>
<package>org.apache.log.output.net</package>
<package>org.apache.log.util</package>
<package>org.apache.commons.text</package>
<package>org.apache.commons.validator.routines</package>
<package>org.apache.commons.validator.routines.checkdigit</package>
@ -460,14 +436,7 @@
<package>org.apache.log4j.config</package>
<package>org.apache.log4j.helpers</package>
<package>org.apache.log4j.jdbc</package>
<package>org.apache.log4j.jmx</package>
<package>org.apache.log4j.lf5</package>
<package>org.apache.log4j.lf5.util</package>
<package>org.apache.log4j.lf5.viewer</package>
<package>org.apache.log4j.lf5.viewer.categoryexplorer</package>
<package>org.apache.log4j.lf5.viewer.configure</package>
<package>org.apache.log4j.net</package>
<package>org.apache.log4j.nt</package>
<package>org.apache.log4j.or</package>
<package>org.apache.log4j.or.jms</package>
<package>org.apache.log4j.or.sax</package>
@ -931,6 +900,10 @@
<runtime-relative-path>ext/jackson-dataformat-csv-2.15.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackson-dataformat-csv-2.15.2.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jackson-datatype-jsr310-2.15.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jackson-datatype-jsr310-2.15.2.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/javafx-base-17.0.7-linux.jar</runtime-relative-path>
<binary-origin>release/modules/ext/javafx-base-17.0.7-linux.jar</binary-origin>

View File

@ -1,5 +1,5 @@
#Updated by build script
#Wed, 28 Sep 2022 13:57:05 -0400
#Thu, 20 Jul 2023 14:02:30 -0400
LBL_splash_window_title=Starting Autopsy
SPLASH_HEIGHT=314
SPLASH_WIDTH=538
@ -8,4 +8,4 @@ SplashRunningTextBounds=0,289,538,18
SplashRunningTextColor=0x0
SplashRunningTextFontSize=19
currentVersion=Autopsy 4.19.3
currentVersion=Autopsy 4.20.0

View File

@ -1,4 +1,4 @@
#Updated by build script
#Wed, 28 Sep 2022 13:57:05 -0400
CTL_MainWindow_Title=Autopsy 4.19.3
CTL_MainWindow_Title_No_Project=Autopsy 4.19.3
#Thu, 20 Jul 2023 14:02:30 -0400
CTL_MainWindow_Title=Autopsy 4.20.0
CTL_MainWindow_Title_No_Project=Autopsy 4.20.0