mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
Merge branch 'develop' of github.com:sleuthkit/autopsy into 8425-snap
This commit is contained in:
commit
c50db9cf35
13
Core/ivy.xml
13
Core/ivy.xml
@ -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>
|
||||
|
@ -4,6 +4,7 @@
|
||||
<chain name="main">
|
||||
<ibiblio name="central" root="https://repo1.maven.org/maven2" m2compatible="true"/>
|
||||
<ibiblio name="maven.restlet.org" root="http://maven.restlet.com" m2compatible="true" />
|
||||
<ibiblio name="license4j.com" root="http://www.license4j.com/maven/" m2compatible="true" />
|
||||
</chain>
|
||||
</resolvers>
|
||||
<property name="packaging.type" value="jar" />
|
||||
|
@ -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
|
||||
|
@ -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/>
|
||||
@ -323,6 +323,7 @@
|
||||
</test-type>
|
||||
</test-dependencies>
|
||||
<public-packages>
|
||||
<package>com.basistech.df.cybertriage.autopsy.ctoptions.subpanel</package>
|
||||
<package>net.sf.sevenzipjbinding</package>
|
||||
<package>net.sf.sevenzipjbinding.impl</package>
|
||||
<package>net.sf.sevenzipjbinding.simple</package>
|
||||
@ -448,6 +449,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 +505,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 +581,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 +621,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>
|
||||
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi;
|
||||
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenRequest;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenResponse;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthenticatedRequestData;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.CTCloudBean;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.CTCloudBeanResponse;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.DecryptedLicenseResponse;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.FileReputationRequest;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseRequest;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseResponse;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.util.CTHostIDGenerationUtil;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
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 String CTCLOUD_SERVER_HASH_PATH = "/_ah/api/reputation/v1/query/file/hash/md5?query_types=CORRELATION,MALWARE";
|
||||
private static final String AUTOPSY_PRODUCT = "AUTOPSY";
|
||||
|
||||
private static final CTApiDAO instance = new CTApiDAO();
|
||||
|
||||
private CTApiDAO() {
|
||||
}
|
||||
|
||||
public static CTApiDAO getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static String getAppVersion() {
|
||||
return Version.getVersion();
|
||||
}
|
||||
|
||||
private final CTCloudHttpClient httpClient = CTCloudHttpClient.getInstance();
|
||||
|
||||
public LicenseResponse getLicenseInfo(String licenseString) throws CTCloudException {
|
||||
LicenseRequest licenseRequest = new LicenseRequest()
|
||||
.setBoostLicenseCode(licenseString)
|
||||
.setHostId(CTHostIDGenerationUtil.generateLicenseHostID())
|
||||
.setProduct(AUTOPSY_PRODUCT)
|
||||
.setTimeZoneId(UserPreferences.getInferredUserTimeZone());
|
||||
|
||||
return httpClient.doPost(LICENSE_REQUEST_PATH, licenseRequest, LicenseResponse.class);
|
||||
|
||||
}
|
||||
|
||||
public AuthTokenResponse getAuthToken(DecryptedLicenseResponse decrypted) throws CTCloudException {
|
||||
AuthTokenRequest authTokenRequest = new AuthTokenRequest()
|
||||
.setAutopsyVersion(getAppVersion())
|
||||
.setRequestFileUpload(false)
|
||||
.setBoostLicenseId(decrypted.getBoostLicenseId())
|
||||
.setHostId(decrypted.getLicenseHostId());
|
||||
|
||||
return httpClient.doPost(AUTH_TOKEN_REQUEST_PATH, authTokenRequest, AuthTokenResponse.class);
|
||||
}
|
||||
|
||||
private static Map<String, String> getAuthParams(AuthenticatedRequestData authenticatedRequestData) {
|
||||
return new HashMap<String, String>() {
|
||||
{
|
||||
put("api_key", authenticatedRequestData.getApiKey());
|
||||
put("token", authenticatedRequestData.getToken());
|
||||
put("host_id", authenticatedRequestData.getHostId());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public List<CTCloudBean> getReputationResults(AuthenticatedRequestData authenticatedRequestData, List<String> md5Hashes) throws CTCloudException {
|
||||
if (CollectionUtils.isEmpty(md5Hashes)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
FileReputationRequest fileRepReq = new FileReputationRequest()
|
||||
.setHashes(md5Hashes);
|
||||
|
||||
CTCloudBeanResponse resp = httpClient.doPost(
|
||||
CTCLOUD_SERVER_HASH_PATH,
|
||||
getAuthParams(authenticatedRequestData),
|
||||
fileRepReq,
|
||||
CTCloudBeanResponse.class
|
||||
);
|
||||
|
||||
return resp == null || resp.getItems() == null
|
||||
? Collections.emptyList()
|
||||
: resp.getItems();
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi;
|
||||
|
||||
|
||||
import java.util.Objects;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
|
||||
/**
|
||||
* An exception thrown due to an error that occurs while making a CT Cloud REST
|
||||
* API request.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi;
|
||||
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import java.io.IOException;
|
||||
import java.net.Authenticator;
|
||||
import java.net.InetAddress;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.NTCredentials;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.client.config.AuthSchemes;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.client.SystemDefaultCredentialsProvider;
|
||||
import org.apache.http.impl.client.WinHttpClients;
|
||||
import org.sleuthkit.autopsy.coreutils.Version;
|
||||
|
||||
/**
|
||||
* Makes the http requests to CT cloud.
|
||||
*/
|
||||
public class CTCloudHttpClient {
|
||||
|
||||
private static final CTCloudHttpClient instance = new CTCloudHttpClient();
|
||||
private static final Logger LOGGER = Logger.getLogger(CTCloudHttpClient.class.getName());
|
||||
private static final String HOST_URL = Version.getBuildType() == Version.Type.RELEASE ? Constants.CT_CLOUD_SERVER : Constants.CT_CLOUD_DEV_SERVER;
|
||||
|
||||
private static final List<String> DEFAULT_SCHEME_PRIORITY
|
||||
= new ArrayList<>(Arrays.asList(
|
||||
AuthSchemes.SPNEGO,
|
||||
AuthSchemes.KERBEROS,
|
||||
AuthSchemes.NTLM,
|
||||
AuthSchemes.CREDSSP,
|
||||
AuthSchemes.DIGEST,
|
||||
AuthSchemes.BASIC));
|
||||
|
||||
private static final int CONNECTION_TIMEOUT_MS = 58 * 1000; // milli sec
|
||||
|
||||
public static CTCloudHttpClient getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private final ObjectMapper mapper = ObjectMapperUtil.getInstance().getDefaultObjectMapper();
|
||||
private final SSLContext sslContext;
|
||||
private String hostName = null;
|
||||
|
||||
private CTCloudHttpClient() {
|
||||
// leave as null for now unless we want to customize this at a later date
|
||||
this.sslContext = null;
|
||||
}
|
||||
|
||||
private ProxySettingArgs getProxySettings() {
|
||||
if (StringUtils.isBlank(hostName)) {
|
||||
try {
|
||||
hostName = InetAddress.getLocalHost().getCanonicalHostName();
|
||||
} catch (UnknownHostException ex) {
|
||||
LOGGER.log(Level.WARNING, "An error occurred while fetching the hostname", ex);
|
||||
}
|
||||
}
|
||||
|
||||
int proxyPort = 0;
|
||||
if (StringUtils.isNotBlank(ProxySettings.getHttpPort())) {
|
||||
try {
|
||||
proxyPort = Integer.parseInt(ProxySettings.getHttpsPort());
|
||||
} catch (NumberFormatException ex) {
|
||||
LOGGER.log(Level.WARNING, "Unable to convert port to integer");
|
||||
}
|
||||
}
|
||||
|
||||
return new ProxySettingArgs(
|
||||
ProxySettings.getProxyType() != ProxySettings.DIRECT_CONNECTION,
|
||||
hostName,
|
||||
ProxySettings.getHttpsHost(),
|
||||
proxyPort,
|
||||
ProxySettings.getAuthenticationUsername(),
|
||||
ProxySettings.getAuthenticationPassword(),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
public <O> O doPost(String urlPath, Object jsonBody, Class<O> classType) throws CTCloudException {
|
||||
return doPost(urlPath, Collections.emptyMap(), jsonBody, classType);
|
||||
}
|
||||
|
||||
public <O> O doPost(String urlPath, Map<String, String> urlReqParams, Object jsonBody, Class<O> classType) throws CTCloudException {
|
||||
String url = HOST_URL + urlPath;
|
||||
try {
|
||||
|
||||
LOGGER.log(Level.INFO, "initiating http connection to ctcloud server");
|
||||
try (CloseableHttpClient httpclient = createConnection(getProxySettings(), sslContext)) {
|
||||
URIBuilder builder = new URIBuilder(url);
|
||||
|
||||
if (!MapUtils.isEmpty(urlReqParams)) {
|
||||
for (Entry<String, String> e : urlReqParams.entrySet()) {
|
||||
String key = e.getKey();
|
||||
String value = e.getValue();
|
||||
if (StringUtils.isNotBlank(key) || StringUtils.isNotBlank(value)) {
|
||||
builder.addParameter(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
URI postURI = builder.build();
|
||||
HttpPost postRequest = new HttpPost(postURI);
|
||||
|
||||
|
||||
configureRequestTimeout(postRequest);
|
||||
postRequest.setHeader("Content-type", "application/json");
|
||||
|
||||
if (jsonBody != null) {
|
||||
String requestBody = mapper.writeValueAsString(jsonBody);
|
||||
if (StringUtils.isNotBlank(requestBody)) {
|
||||
HttpEntity entity = new StringEntity(requestBody, "UTF-8");
|
||||
postRequest.setEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.log(Level.INFO, "initiating http post request to ctcloud server " + postRequest.getURI());
|
||||
try (CloseableHttpResponse response = httpclient.execute(postRequest)) {
|
||||
|
||||
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
|
||||
LOGGER.log(Level.INFO, "Response Received. - Status OK");
|
||||
// Parse Response
|
||||
HttpEntity entity = response.getEntity();
|
||||
String entityStr = EntityUtils.toString(entity);
|
||||
O respObj = mapper.readValue(entityStr, classType);
|
||||
return respObj;
|
||||
} else {
|
||||
LOGGER.log(Level.WARNING, "Response Received. - Status Error {}", response.getStatusLine());
|
||||
handleNonOKResponse(response, "");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
LOGGER.log(Level.WARNING, "Error when parsing response from CyberTriage Cloud", ex);
|
||||
throw new CTCloudException(CTCloudException.parseUnknownException(ex), ex);
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.WARNING, "IO Exception raised when connecting to CT Cloud using " + url, ex);
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.NETWORK_ERROR, ex);
|
||||
} catch (URISyntaxException ex) {
|
||||
LOGGER.log(Level.WARNING, "Wrong URL syntax for CT Cloud " + url, ex);
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.UNKNOWN, ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic way to handle the HTTP response - when the response code is NOT
|
||||
* 200 OK.
|
||||
*
|
||||
* @param response
|
||||
* @param fileName - used only for logging.
|
||||
* @throws MalwareScannerException
|
||||
* @throws IOException
|
||||
*/
|
||||
private void handleNonOKResponse(CloseableHttpResponse response, String fileName) throws CTCloudException, IOException {
|
||||
LOGGER.log(Level.WARNING, MessageFormat.format(
|
||||
"Response code {0}. Message Body {1}",
|
||||
response.getStatusLine().getStatusCode(),
|
||||
EntityUtils.toString(response.getEntity())));
|
||||
|
||||
switch (response.getStatusLine().getStatusCode()) {
|
||||
|
||||
case HttpStatus.SC_BAD_REQUEST:
|
||||
//400: Bad request => Unsupported HTTP method or invalid http request (e.g., empty body).
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.BAD_REQUEST);
|
||||
case HttpStatus.SC_UNAUTHORIZED:
|
||||
//401 Invalid API key => An invalid API key, or no API key, has been provided
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.INVALID_KEY);
|
||||
case HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED:
|
||||
// 407 Proxy server authentication required.
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.PROXY_UNAUTHORIZED);
|
||||
case HttpStatus.SC_FORBIDDEN:
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.UN_AUTHORIZED);
|
||||
case HttpStatus.SC_INTERNAL_SERVER_ERROR:
|
||||
//500 Internal error Server temporarily unavailable; please try again later. If the issue persists, please contact RL.
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.TEMP_UNAVAILABLE);
|
||||
case HttpStatus.SC_SERVICE_UNAVAILABLE:
|
||||
//503 Server is too busy. Try again later.
|
||||
//503 Failed to request scan. Try again later. The server is currently unable to handle the request due to a temporary overloading or maintenance of the server. If the issue persists, please contact RL.
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.TEMP_UNAVAILABLE);
|
||||
case HttpStatus.SC_GATEWAY_TIMEOUT:
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.GATEWAY_TIMEOUT);
|
||||
default:
|
||||
String returnData = EntityUtils.toString(response.getEntity());
|
||||
LOGGER.log(Level.WARNING, MessageFormat.format("upload response content for {0}:\n {1}", fileName, returnData));
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.NETWORK_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE That this is not a perfect solution as timeouts set this way does
|
||||
* not terminate a connection forcefully after a specified interval. so if
|
||||
* there is data streaming in from the server at a small speed the
|
||||
* connection will be kept open.
|
||||
*
|
||||
* @param request
|
||||
*/
|
||||
private void configureRequestTimeout(HttpRequestBase request) {
|
||||
RequestConfig config = RequestConfig.custom()
|
||||
.setConnectionRequestTimeout(CONNECTION_TIMEOUT_MS)
|
||||
.setConnectTimeout(CONNECTION_TIMEOUT_MS)
|
||||
.setSocketTimeout(CONNECTION_TIMEOUT_MS)
|
||||
.build();
|
||||
request.setConfig(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a connection to CT Cloud with the given arguments.
|
||||
* @param proxySettings The network proxy settings.
|
||||
* @param sslContext The ssl context or null.
|
||||
* @return The connection to CT Cloud.
|
||||
*/
|
||||
private static CloseableHttpClient createConnection(ProxySettingArgs proxySettings, SSLContext sslContext) {
|
||||
HttpClientBuilder builder = getHttpClientBuilder(proxySettings);
|
||||
|
||||
if (sslContext != null) {
|
||||
builder.setSSLContext(sslContext);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static HttpClientBuilder getHttpClientBuilder(ProxySettingArgs proxySettings) {
|
||||
|
||||
if (proxySettings.isSystemOrManualProxy()) {
|
||||
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
LOGGER.info("Requesting Password Authentication...");
|
||||
return super.getPasswordAuthentication();
|
||||
}
|
||||
});
|
||||
|
||||
HttpClientBuilder builder = null;
|
||||
HttpHost proxyHost = null;
|
||||
CredentialsProvider proxyCredsProvider = null;
|
||||
RequestConfig config = null;
|
||||
|
||||
if (Objects.nonNull(proxySettings.getProxyHostname()) && proxySettings.getProxyPort() > 0) {
|
||||
proxyHost = new HttpHost(proxySettings.getProxyHostname(), proxySettings.getProxyPort());
|
||||
|
||||
proxyCredsProvider = getProxyCredentialsProvider(proxySettings);
|
||||
if (StringUtils.isNotBlank(proxySettings.getAuthScheme())) {
|
||||
if (!DEFAULT_SCHEME_PRIORITY.get(0).equalsIgnoreCase(proxySettings.getAuthScheme())) {
|
||||
DEFAULT_SCHEME_PRIORITY.removeIf(s -> s.equalsIgnoreCase(proxySettings.getAuthScheme()));
|
||||
DEFAULT_SCHEME_PRIORITY.add(0, proxySettings.getAuthScheme());
|
||||
}
|
||||
}
|
||||
config = RequestConfig.custom().setProxyPreferredAuthSchemes(DEFAULT_SCHEME_PRIORITY).build();
|
||||
}
|
||||
|
||||
if (Objects.isNull(proxyCredsProvider) && WinHttpClients.isWinAuthAvailable()) {
|
||||
builder = WinHttpClients.custom();
|
||||
builder.useSystemProperties();
|
||||
LOGGER.log(Level.WARNING, "Using Win HTTP Client");
|
||||
} else {
|
||||
builder = HttpClients.custom();
|
||||
builder.setDefaultRequestConfig(config);
|
||||
if (Objects.nonNull(proxyCredsProvider)) { // make sure non null proxycreds before setting it
|
||||
builder.setDefaultCredentialsProvider(proxyCredsProvider);
|
||||
}
|
||||
LOGGER.log(Level.WARNING, "Using default http client");
|
||||
}
|
||||
if (Objects.nonNull(proxyHost)) {
|
||||
builder.setProxy(proxyHost);
|
||||
LOGGER.log(Level.WARNING, MessageFormat.format("Using proxy {0}", proxyHost));
|
||||
}
|
||||
|
||||
return builder;
|
||||
} else {
|
||||
return HttpClients.custom();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a CredentialsProvider for proxy, if one is configured.
|
||||
*
|
||||
* @return CredentialsProvider, if a proxy is configured with credentials,
|
||||
* null otherwise
|
||||
*/
|
||||
private static CredentialsProvider getProxyCredentialsProvider(ProxySettingArgs proxySettings) {
|
||||
CredentialsProvider proxyCredsProvider = null;
|
||||
if (proxySettings.isSystemOrManualProxy()) {
|
||||
if (StringUtils.isNotBlank(proxySettings.getProxyUserId())) {
|
||||
if (null != proxySettings.getProxyPassword() && proxySettings.getProxyPassword().length > 0) { // Password will be blank for KERBEROS / NEGOTIATE schemes.
|
||||
proxyCredsProvider = new SystemDefaultCredentialsProvider();
|
||||
String userId = proxySettings.getProxyUserId();
|
||||
String domain = null;
|
||||
if (userId.contains("\\")) {
|
||||
domain = userId.split("\\\\")[0];
|
||||
userId = userId.split("\\\\")[1];
|
||||
}
|
||||
String workStation = proxySettings.getHostName();
|
||||
proxyCredsProvider.setCredentials(new AuthScope(proxySettings.getProxyHostname(), proxySettings.getProxyPort()),
|
||||
new NTCredentials(userId, new String(proxySettings.getProxyPassword()), workStation, domain));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return proxyCredsProvider;
|
||||
}
|
||||
|
||||
private static class ProxySettingArgs {
|
||||
|
||||
private final boolean systemOrManualProxy;
|
||||
private final String hostName;
|
||||
private final String proxyHostname;
|
||||
private final int proxyPort;
|
||||
private final String proxyUserId;
|
||||
private final char[] proxyPassword;
|
||||
private final String authScheme;
|
||||
|
||||
ProxySettingArgs(boolean systemOrManualProxy, String hostName, String proxyHostname, int proxyPort, String proxyUserId, char[] proxyPassword, String authScheme) {
|
||||
this.systemOrManualProxy = systemOrManualProxy;
|
||||
this.hostName = hostName;
|
||||
this.proxyHostname = proxyHostname;
|
||||
this.proxyPort = proxyPort;
|
||||
this.proxyUserId = proxyUserId;
|
||||
this.proxyPassword = proxyPassword;
|
||||
this.authScheme = authScheme;
|
||||
}
|
||||
|
||||
boolean isSystemOrManualProxy() {
|
||||
return systemOrManualProxy;
|
||||
}
|
||||
|
||||
String getHostName() {
|
||||
return hostName;
|
||||
}
|
||||
|
||||
String getProxyHostname() {
|
||||
return proxyHostname;
|
||||
}
|
||||
|
||||
int getProxyPort() {
|
||||
return proxyPort;
|
||||
}
|
||||
|
||||
String getProxyUserId() {
|
||||
return proxyUserId;
|
||||
}
|
||||
|
||||
char[] getProxyPassword() {
|
||||
return proxyPassword;
|
||||
}
|
||||
|
||||
public String getAuthScheme() {
|
||||
return authScheme;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* Constants regarding connections to cyber triage cloud.
|
||||
*/
|
||||
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_DEV_SERVER = "https://cyber-triage-dev.appspot.com";
|
||||
|
||||
public static final String CT_CLOUD_SERVER = "https://rep1.cybertriage.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 `~!@#$&^*(){}[]\\\\|;'\",<>/?";
|
||||
|
||||
}
|
@ -0,0 +1,446 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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();
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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;
|
||||
|
||||
@JsonProperty("host_id")
|
||||
private String hostId;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public String getHostId() {
|
||||
return hostId;
|
||||
}
|
||||
|
||||
public AuthTokenRequest setHostId(String hostId) {
|
||||
this.hostId = hostId;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil.InstantEpochMillisDeserializer;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil.InstantEpochSecsDeserializer;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* POJO for an auth token response.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class AuthTokenResponse {
|
||||
|
||||
private final Long hashLookupCount;
|
||||
private final Long hashLookupLimit;
|
||||
private final Long fileUploadLimit;
|
||||
private final Long fileUploadCount;
|
||||
private final String fileUploadUrl;
|
||||
private final Instant expiration;
|
||||
private final String token;
|
||||
private final String apiKey;
|
||||
private final Instant resetDate;
|
||||
|
||||
@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,
|
||||
@JsonDeserialize(using = InstantEpochSecsDeserializer.class)
|
||||
@JsonProperty("expiration") Instant expiration,
|
||||
@JsonDeserialize(using = InstantEpochMillisDeserializer.class)
|
||||
@JsonProperty("resetDate") Instant resetDate
|
||||
) {
|
||||
this.token = token;
|
||||
this.apiKey = apiKey;
|
||||
this.hashLookupCount = hashLookupCount;
|
||||
this.hashLookupLimit = hashLookupLimit;
|
||||
this.fileUploadLimit = fileUploadLimit;
|
||||
this.fileUploadCount = fileUploadCount;
|
||||
this.fileUploadUrl = fileUploadUrl;
|
||||
this.expiration = expiration;
|
||||
this.resetDate = resetDate;
|
||||
}
|
||||
|
||||
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 Instant getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public String getApiKey() {
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
public Instant getResetDate() {
|
||||
return resetDate;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
/**
|
||||
* Data required for an authenticated request.
|
||||
*/
|
||||
public class AuthenticatedRequestData {
|
||||
|
||||
private final String token;
|
||||
private final String apiKey;
|
||||
private final String hostId;
|
||||
|
||||
public AuthenticatedRequestData(DecryptedLicenseResponse decrypted, AuthTokenResponse authResp) {
|
||||
this(authResp.getToken(), authResp.getApiKey(), decrypted.getLicenseHostId());
|
||||
}
|
||||
|
||||
public AuthenticatedRequestData(String token, String apiKey, String hostId) {
|
||||
this.token = token;
|
||||
this.apiKey = apiKey;
|
||||
this.hostId = hostId;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public String getApiKey() {
|
||||
return apiKey;
|
||||
}
|
||||
|
||||
public String getHostId() {
|
||||
return hostId;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* POJO for a boost license response object that is a part of the license
|
||||
* response.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class BoostLicenseResponse {
|
||||
|
||||
private final String version;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author rishwanth
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class CTCloudBean {
|
||||
|
||||
public static enum Status {
|
||||
FOUND,
|
||||
NOT_FOUND,
|
||||
ERROR,
|
||||
LIMITS_EXCEEDED,
|
||||
BEING_SCANNED;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@JsonProperty("malware")
|
||||
private MalwareResultBean malwareResult;
|
||||
|
||||
@JsonProperty("correlation")
|
||||
private CorrelationResultBean correlationResult;
|
||||
|
||||
@Nonnull
|
||||
@JsonProperty("md5_hash")
|
||||
private String md5HashValue;
|
||||
|
||||
@Nullable
|
||||
@JsonProperty("sha1_hash")
|
||||
private String sha1HashValue;
|
||||
|
||||
public String getMd5HashValue() {
|
||||
return md5HashValue;
|
||||
}
|
||||
|
||||
public String getSha1HashValue() {
|
||||
return sha1HashValue;
|
||||
}
|
||||
|
||||
public void setMd5HashValue(String md5HashValue) {
|
||||
this.md5HashValue = md5HashValue;
|
||||
}
|
||||
|
||||
public void setSha1HashValue(String sha1HashValue) {
|
||||
this.sha1HashValue = sha1HashValue;
|
||||
}
|
||||
|
||||
public MalwareResultBean getMalwareResult() {
|
||||
return malwareResult;
|
||||
}
|
||||
|
||||
public void setMalwareResult(MalwareResultBean malwareResult) {
|
||||
this.malwareResult = malwareResult;
|
||||
}
|
||||
|
||||
public CorrelationResultBean getCorrelationResult() {
|
||||
return correlationResult;
|
||||
}
|
||||
|
||||
public void setCorrelationResult(CorrelationResultBean correlationResult) {
|
||||
this.correlationResult = correlationResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CTCloudBean{"
|
||||
+ "status=" + malwareResult.getStatus()
|
||||
+ ", malwareDescription=" + malwareResult.getMalwareDescription()
|
||||
+ ", score=" + malwareResult.getCTScore()
|
||||
+ ", md5HashValue=" + md5HashValue
|
||||
+ ", sha1HashValue=" + sha1HashValue
|
||||
+ ", firstSeen=" + malwareResult.getFirstAnalyzedDate()
|
||||
+ ", lastSeen=" + malwareResult.getLastAnalyzedDate()
|
||||
+ ", statusDescription=" + malwareResult.getStatusDescription()
|
||||
+ ", metadata=" + malwareResult.getMetadata()
|
||||
+ '}';
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Container for file reputation result list response.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class CTCloudBeanResponse {
|
||||
|
||||
private final List<CTCloudBean> items;
|
||||
|
||||
@JsonCreator
|
||||
public CTCloudBeanResponse(
|
||||
@JsonProperty("items") List<CTCloudBean> items
|
||||
) {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public List<CTCloudBean> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class CTCloudCorrelationResultBean {
|
||||
|
||||
@JsonProperty("correlation")
|
||||
private CorrelationResultBean correlationResult;
|
||||
|
||||
@Nonnull
|
||||
@JsonProperty("signature")
|
||||
private String signature;
|
||||
|
||||
public CorrelationResultBean getCorrelationResult() {
|
||||
return correlationResult;
|
||||
}
|
||||
|
||||
public void setCorrelationResult(CorrelationResultBean correlationResult) {
|
||||
this.correlationResult = correlationResult;
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setSignature(String signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CTCloudCorrelationResultBean{"
|
||||
+ "correlationResult=" + correlationResult
|
||||
+ ", signature=" + signature
|
||||
+ '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author rishwanth
|
||||
*/
|
||||
class CTCloudCostBean {
|
||||
|
||||
private final String provider;
|
||||
|
||||
private final Integer units;
|
||||
|
||||
public CTCloudCostBean(@JsonProperty("provider") String provider, @JsonProperty("units") Integer units) {
|
||||
this.provider = provider;
|
||||
this.units = units;
|
||||
}
|
||||
|
||||
public String getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
public Integer getUnits() {
|
||||
return units;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author rishwanth
|
||||
*/
|
||||
public enum CorrelationFrequency {
|
||||
UNIQUE,
|
||||
RARE,
|
||||
COMMON;
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author rishwanth
|
||||
*/
|
||||
public class CorrelationResultBean {
|
||||
|
||||
@JsonProperty("frequency")
|
||||
private CorrelationFrequency frequency;
|
||||
|
||||
@JsonProperty("frequency_description")
|
||||
private String frequencyDescription;
|
||||
|
||||
public CorrelationFrequency getFrequency() {
|
||||
return frequency;
|
||||
}
|
||||
|
||||
public String getFrequencyDescription() {
|
||||
return frequencyDescription;
|
||||
}
|
||||
|
||||
public void setFrequency(CorrelationFrequency frequency) {
|
||||
this.frequency = frequency;
|
||||
}
|
||||
|
||||
public void setFrequencyDescription(String frequencyDescription) {
|
||||
this.frequencyDescription = frequencyDescription;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil.InstantEpochMillisDeserializer;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* POJO for after encrypted boost license has been decrypted.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class DecryptedLicenseResponse {
|
||||
|
||||
private final String boostLicenseId;
|
||||
private final String licenseHostId;
|
||||
private final Instant expirationDate;
|
||||
private final Long hashLookups;
|
||||
private final Long fileUploads;
|
||||
private final Instant activationTime;
|
||||
private final String product;
|
||||
private final String limitType;
|
||||
private final String timezone;
|
||||
private final String customerEmail;
|
||||
private final String customerName;
|
||||
|
||||
@JsonCreator
|
||||
public DecryptedLicenseResponse(
|
||||
@JsonProperty("boostLicenseId") String boostLicenseId,
|
||||
@JsonProperty("licenseHostId") String licenseHostId,
|
||||
@JsonDeserialize(using = InstantEpochMillisDeserializer.class)
|
||||
@JsonProperty("expirationDate") Instant expirationDate,
|
||||
@JsonProperty("hashLookups") Long hashLookups,
|
||||
@JsonProperty("fileUploads") Long fileUploads,
|
||||
@JsonDeserialize(using = InstantEpochMillisDeserializer.class)
|
||||
@JsonProperty("activationTime") Instant activationTime,
|
||||
@JsonProperty("product") String product,
|
||||
@JsonProperty("limitType") String limitType,
|
||||
@JsonProperty("timezone") String timezone,
|
||||
@JsonProperty("customerEmail") String customerEmail,
|
||||
@JsonProperty("customerName") String customerName
|
||||
) {
|
||||
this.boostLicenseId = boostLicenseId;
|
||||
this.licenseHostId = licenseHostId;
|
||||
this.expirationDate = expirationDate;
|
||||
this.hashLookups = hashLookups;
|
||||
this.fileUploads = fileUploads;
|
||||
this.activationTime = activationTime;
|
||||
this.product = product;
|
||||
this.limitType = limitType;
|
||||
this.timezone = timezone;
|
||||
this.customerEmail = customerEmail;
|
||||
this.customerName = customerName;
|
||||
}
|
||||
|
||||
public String getBoostLicenseId() {
|
||||
return boostLicenseId;
|
||||
}
|
||||
|
||||
public String getLicenseHostId() {
|
||||
return licenseHostId;
|
||||
}
|
||||
|
||||
public Long getHashLookups() {
|
||||
return hashLookups;
|
||||
}
|
||||
|
||||
public Long getFileUploads() {
|
||||
return fileUploads;
|
||||
}
|
||||
|
||||
public Instant getActivationTime() {
|
||||
return activationTime;
|
||||
}
|
||||
|
||||
public String getProduct() {
|
||||
return product;
|
||||
}
|
||||
|
||||
public String getLimitType() {
|
||||
return limitType;
|
||||
}
|
||||
|
||||
public Instant getExpirationDate() {
|
||||
return expirationDate;
|
||||
}
|
||||
|
||||
public String getTimezone() {
|
||||
return timezone;
|
||||
}
|
||||
|
||||
public String getCustomerEmail() {
|
||||
return customerEmail;
|
||||
}
|
||||
|
||||
public String getCustomerName() {
|
||||
return customerName;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Request for file reputation results.
|
||||
*/
|
||||
public class FileReputationRequest {
|
||||
|
||||
@JsonProperty("hashes")
|
||||
private List<String> hashes;
|
||||
|
||||
public List<String> getHashes() {
|
||||
return hashes;
|
||||
}
|
||||
|
||||
public FileReputationRequest setHashes(List<String> hashes) {
|
||||
this.hashes = hashes;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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;
|
||||
|
||||
@JsonProperty("time_zone_id")
|
||||
private String timeZoneId;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public String getTimeZoneId() {
|
||||
return timeZoneId;
|
||||
}
|
||||
|
||||
public LicenseRequest setTimeZoneId(String timeZoneId) {
|
||||
this.timeZoneId = timeZoneId;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Response POJO for request for license.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class LicenseResponse {
|
||||
|
||||
private final Boolean success;
|
||||
private final Boolean hostChanged;
|
||||
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;
|
||||
}
|
||||
}
|
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.util.ObjectMapperUtil.ZonedDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author rishwanth
|
||||
*/
|
||||
public class MalwareResultBean {
|
||||
|
||||
public static enum Status {
|
||||
FOUND,
|
||||
NOT_FOUND,
|
||||
ERROR,
|
||||
LIMITS_EXCEEDED,
|
||||
BEING_SCANNED;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@JsonProperty("malware_description")
|
||||
private String malwareDescription;
|
||||
|
||||
@Nonnull
|
||||
@JsonProperty("status")
|
||||
private Status status;
|
||||
|
||||
@Nonnull
|
||||
@JsonProperty("score")
|
||||
private String score;
|
||||
|
||||
private CTScore ctScore;
|
||||
|
||||
@Nullable
|
||||
@JsonProperty("first_scan_date")
|
||||
@JsonDeserialize(using = ZonedDateTimeDeserializer.class)
|
||||
private ZonedDateTime firstAnalyzedDate;
|
||||
|
||||
@Nullable
|
||||
@JsonProperty("last_scan_date")
|
||||
@JsonDeserialize(using = ZonedDateTimeDeserializer.class)
|
||||
private ZonedDateTime lastAnalyzedDate;
|
||||
|
||||
@JsonProperty("metadata")
|
||||
private List<MetadataLabel> metadata;
|
||||
|
||||
@Nullable
|
||||
@JsonProperty("status_description")
|
||||
private String statusDescription;
|
||||
|
||||
|
||||
@Nullable
|
||||
@JsonProperty
|
||||
private List<CTCloudCostBean> cost;
|
||||
|
||||
@JsonIgnore
|
||||
public CTScore getCTScore() {
|
||||
return ctScore;
|
||||
}
|
||||
|
||||
public String getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
public ZonedDateTime getFirstAnalyzedDate() {
|
||||
return firstAnalyzedDate;
|
||||
}
|
||||
|
||||
public ZonedDateTime getLastAnalyzedDate() {
|
||||
return lastAnalyzedDate;
|
||||
}
|
||||
|
||||
public List<MetadataLabel> getMetadata() {
|
||||
if (metadata != null) {
|
||||
return List.copyOf(metadata);
|
||||
} else {
|
||||
return List.of(); // empty list
|
||||
}
|
||||
}
|
||||
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public String getStatusDescription() {
|
||||
return statusDescription;
|
||||
}
|
||||
|
||||
|
||||
public String getMalwareDescription() {
|
||||
return malwareDescription;
|
||||
}
|
||||
|
||||
public void setMalwareDescription(String malwareDescription) {
|
||||
this.malwareDescription = malwareDescription;
|
||||
}
|
||||
|
||||
public void setStatus(Status status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public void setScore(String score) {
|
||||
this.score = score;
|
||||
switch(score) {
|
||||
case "GOOD_HIGH":
|
||||
this.ctScore = CTScore.NONE;
|
||||
break;
|
||||
case "GOOD_MEDIUM":
|
||||
this.ctScore = CTScore.LIKELY_NONE;
|
||||
break;
|
||||
case "BAD_HIGH":
|
||||
this.ctScore = CTScore.NOTABLE;
|
||||
break;
|
||||
case "BAD_MEDIUM":
|
||||
this.ctScore = CTScore.LIKELY_NOTABLE;
|
||||
break;
|
||||
default:
|
||||
this.ctScore = CTScore.UNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void setFirstAnalyzedDate(ZonedDateTime firstAnalyzedDate) {
|
||||
this.firstAnalyzedDate = firstAnalyzedDate;
|
||||
}
|
||||
|
||||
public void setLastAnalyzedDate(ZonedDateTime lastAnalyzedDate) {
|
||||
this.lastAnalyzedDate = lastAnalyzedDate;
|
||||
}
|
||||
|
||||
public void setMetadata(List<MetadataLabel> metadata) {
|
||||
this.metadata = List.copyOf(metadata);
|
||||
}
|
||||
|
||||
public void setStatusDescription(String statusDescription) {
|
||||
this.statusDescription = statusDescription;
|
||||
}
|
||||
|
||||
public List<CTCloudCostBean> getCost() {
|
||||
return List.copyOf(cost);
|
||||
}
|
||||
|
||||
public void setCost(List<CTCloudCostBean> cost) {
|
||||
this.cost = List.copyOf(cost);
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.json;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Metadata entry.
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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 cachedId = "";
|
||||
|
||||
/**
|
||||
* 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(cachedId)) {
|
||||
try {
|
||||
String hostName = StringUtils.defaultString(InetAddress.getLocalHost().getCanonicalHostName());
|
||||
String macAddressMd5 = StringUtils.isNotBlank(HardwareID.getHardwareIDFromEthernetAddress())
|
||||
? Md5HashUtil.getMD5MessageDigest(HardwareID.getHardwareIDFromEthernetAddress()).substring(0, 16)
|
||||
: Md5HashUtil.getMD5MessageDigest(hostName).substring(0, 16);
|
||||
|
||||
String usernameMd5 = StringUtils.isNotBlank(USER_NAME)
|
||||
? Md5HashUtil.getMD5MessageDigest(USER_NAME).substring(0, 16)
|
||||
: Md5HashUtil.getMD5MessageDigest(hostName).substring(0, 16);
|
||||
|
||||
cachedId = macAddressMd5 + "_" + usernameMd5;
|
||||
|
||||
} catch (UnknownHostException ex) {
|
||||
LOGGER.log(Level.WARNING, "Unable to determine host name.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
return cachedId;
|
||||
}
|
||||
}
|
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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 (!"AUTOPSY".equalsIgnoreCase(decryptedLicense.getProduct())) {
|
||||
// license file is expected to contain product of "CYBERTRIAGE"
|
||||
throw new InvalidLicenseException("Not a valid Autopsy 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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 "";
|
||||
}
|
||||
}
|
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctapi.util;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JacksonException;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import java.io.IOException;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 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.registerModule(new JavaTimeModule());
|
||||
return defaultMapper;
|
||||
}
|
||||
|
||||
public static class UTCBaseZonedDateTimeDeserializer extends JsonDeserializer<ZonedDateTime> {
|
||||
|
||||
private final DateTimeFormatter formatter;
|
||||
|
||||
public UTCBaseZonedDateTimeDeserializer(DateTimeFormatter formatter) {
|
||||
this.formatter = formatter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZonedDateTime deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JacksonException {
|
||||
String date = jp.getText();
|
||||
if (date == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
LocalDateTime ldt = LocalDateTime.parse(date, formatter);
|
||||
return ZonedDateTime.of(ldt, ZoneOffset.UTC);
|
||||
} catch (DateTimeParseException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ZonedDateTimeDeserializer extends UTCBaseZonedDateTimeDeserializer {
|
||||
|
||||
public ZonedDateTimeDeserializer() {
|
||||
super(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MDYDateDeserializer extends JsonDeserializer<ZonedDateTime> {
|
||||
|
||||
private final DateTimeFormatter formatter;
|
||||
|
||||
public MDYDateDeserializer() {
|
||||
this.formatter = new DateTimeFormatterBuilder()
|
||||
.parseCaseInsensitive()
|
||||
.appendPattern("MMM d, [uuuu][uu]")
|
||||
.toFormatter(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZonedDateTime deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JacksonException {
|
||||
String date = jp.getText();
|
||||
if (date == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
LocalDate ld = LocalDate.parse(date, formatter);
|
||||
LocalDateTime ldt = ld.atStartOfDay();
|
||||
return ZonedDateTime.of(ldt, ZoneOffset.UTC);
|
||||
} catch (DateTimeParseException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class EpochTimeDeserializer<T> extends JsonDeserializer<T> {
|
||||
|
||||
private final Function<Long, T> timeDeserializer;
|
||||
|
||||
public EpochTimeDeserializer(Function<Long, T> timeDeserializer) {
|
||||
this.timeDeserializer = timeDeserializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JacksonException {
|
||||
JsonNode node = jp.getCodec().readTree(jp);
|
||||
|
||||
Long timeVal = null;
|
||||
if (node.isNumber()) {
|
||||
timeVal = node.asLong();
|
||||
} else {
|
||||
String nodeText = node.asText();
|
||||
try {
|
||||
timeVal = Long.parseLong(nodeText);
|
||||
} catch (NumberFormatException ex) {
|
||||
// do nothing if can't parse as number
|
||||
}
|
||||
}
|
||||
|
||||
if (timeVal != null) {
|
||||
try {
|
||||
return timeDeserializer.apply(timeVal);
|
||||
} catch (DateTimeException ex) {
|
||||
// do nothing if can't parse to epoch
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class InstantEpochMillisDeserializer extends EpochTimeDeserializer<Instant> {
|
||||
|
||||
public InstantEpochMillisDeserializer() {
|
||||
super(InstantEpochMillisDeserializer::convert);
|
||||
}
|
||||
|
||||
private static Instant convert(Long longVal) {
|
||||
try {
|
||||
return Instant.ofEpochMilli(longVal);
|
||||
} catch (DateTimeException ex) {
|
||||
// do nothing if can't parse to epoch
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class InstantEpochSecsDeserializer extends EpochTimeDeserializer<Instant> {
|
||||
|
||||
public InstantEpochSecsDeserializer() {
|
||||
super(InstantEpochSecsDeserializer::convert);
|
||||
}
|
||||
|
||||
private static Instant convert(Long longVal) {
|
||||
try {
|
||||
return Instant.ofEpochSecond(longVal);
|
||||
} catch (DateTimeException ex) {
|
||||
// do nothing if can't parse to epoch
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
|
||||
# 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=Cyber Triage
|
||||
OptionsCategory_Keywords_CyberTriage=Cyber Triage,Cyber,Triage
|
||||
LicenseDisclaimerPanel.disclaimer.text=<html>The Cyber Triage Malware Scanner module uses 40+ malware scanning engines to identify if Windows executables are malicious. It requires a non-free license to use.</html>
|
||||
LicenseDisclaimerPanel.purchaseFromLabel.text=You can purchase a license from
|
||||
LicenseDisclaimerPanel.link.text=<html><span style="color: blue; text-decoration: underline">https://cybertriage.com/autopsy-checkout</span></html>
|
||||
LicenseDisclaimerPanel.border.title=Disclaimer
|
@ -0,0 +1,9 @@
|
||||
|
||||
# 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=Cyber Triage
|
||||
OptionsCategory_Keywords_CyberTriage=Cyber Triage,Cyber,Triage
|
||||
LicenseDisclaimerPanel.disclaimer.text=<html>The Cyber Triage Malware Scanner module uses 40+ malware scanning engines to identify if Windows executables are malicious. It requires a non-free license to use.</html>
|
||||
LicenseDisclaimerPanel.purchaseFromLabel.text=You can purchase a license from
|
||||
LicenseDisclaimerPanel.link.text=<html><span style="color: blue; text-decoration: underline">https://cybertriage.com/autopsy-checkout</span></html>
|
||||
LicenseDisclaimerPanel.border.title=Disclaimer
|
@ -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>
|
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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 Cyber Triage.
|
||||
*/
|
||||
public class CTOptionsPanel extends IngestModuleGlobalSettingsPanel {
|
||||
|
||||
private static final int MAX_SUBPANEL_WIDTH = 650;
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CTOptionsPanel.class.getName());
|
||||
|
||||
private final List<CTOptionsSubPanel> subPanels;
|
||||
|
||||
/**
|
||||
* Creates new form CTOptions loading any CTOptionsSubPanel instances to be
|
||||
* displayed.
|
||||
*/
|
||||
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
|
||||
.map(panel -> {
|
||||
try {
|
||||
// lookup is returning singleton instances which means this panel gets messed up when accessed
|
||||
// from multiple places because the panel's children are being added to a different CTOptionsPanel
|
||||
return (CTOptionsSubPanel) panel.getClass().getConstructor().newInstance();
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(item -> item != null)
|
||||
.sorted(Comparator.comparing(p -> p.getClass().getSimpleName().toUpperCase()))
|
||||
.collect(Collectors.toList());
|
||||
addSubOptionsPanels(new LicenseDisclaimerPanel(), this.subPanels);
|
||||
}
|
||||
|
||||
private void addSubOptionsPanels(JPanel disclaimerPanel, List<CTOptionsSubPanel> subPanels) {
|
||||
GridBagConstraints disclaimerConstraints = new GridBagConstraints();
|
||||
disclaimerConstraints.gridx = 0;
|
||||
disclaimerConstraints.gridy = 0;
|
||||
disclaimerConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
disclaimerConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
disclaimerConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
|
||||
disclaimerConstraints.weighty = 0;
|
||||
disclaimerConstraints.weightx = 0;
|
||||
|
||||
contentPane.add(disclaimerPanel, disclaimerConstraints);
|
||||
|
||||
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 + 1;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.insets = new java.awt.Insets(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() + 1;
|
||||
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
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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);
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||
<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="Disclaimer">
|
||||
<ResourceString PropertyName="titleX" bundle="com/basistech/df/cybertriage/autopsy/ctoptions/Bundle.properties" key="LicenseDisclaimerPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</TitledBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[2147483647, 90]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[562, 90]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[400, 90]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<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,90,0,0,2,50"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="disclaimer">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/Bundle.properties" key="LicenseDisclaimerPanel.disclaimer.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="verticalAlignment" type="int" value="1"/>
|
||||
</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="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="purchaseFromLabel">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/Bundle.properties" key="LicenseDisclaimerPanel.purchaseFromLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</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="-1" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="3" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="link">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||
<ResourceString bundle="com/basistech/df/cybertriage/autopsy/ctoptions/Bundle.properties" key="LicenseDisclaimerPanel.link.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
|
||||
<Color id="Hand Cursor"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="linkMouseClicked"/>
|
||||
</Events>
|
||||
<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="-1" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Container class="javax.swing.JPanel" name="spacer">
|
||||
<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="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="1.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>
|
||||
</SubComponents>
|
||||
</Form>
|
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctoptions;
|
||||
|
||||
import java.awt.Desktop;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
/**
|
||||
* Disclaimer for license and place to purchase CT license.
|
||||
*/
|
||||
public class LicenseDisclaimerPanel extends javax.swing.JPanel {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(LicenseDisclaimerPanel.class.getName());
|
||||
|
||||
private static final String CHECKOUT_PAGE_URL = "https://cybertriage.com/autopsy-checkout";
|
||||
|
||||
/**
|
||||
* Creates new form LicenseDisclaimerPanel
|
||||
*/
|
||||
public LicenseDisclaimerPanel() {
|
||||
initComponents();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 disclaimer = new javax.swing.JLabel();
|
||||
javax.swing.JLabel purchaseFromLabel = new javax.swing.JLabel();
|
||||
javax.swing.JLabel link = new javax.swing.JLabel();
|
||||
javax.swing.JPanel spacer = new javax.swing.JPanel();
|
||||
|
||||
setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(LicenseDisclaimerPanel.class, "LicenseDisclaimerPanel.border.title"))); // NOI18N
|
||||
setMaximumSize(new java.awt.Dimension(2147483647, 90));
|
||||
setMinimumSize(new java.awt.Dimension(562, 90));
|
||||
setPreferredSize(new java.awt.Dimension(400, 90));
|
||||
setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(disclaimer, org.openide.util.NbBundle.getMessage(LicenseDisclaimerPanel.class, "LicenseDisclaimerPanel.disclaimer.text")); // NOI18N
|
||||
disclaimer.setVerticalAlignment(javax.swing.SwingConstants.TOP);
|
||||
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);
|
||||
add(disclaimer, gridBagConstraints);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(purchaseFromLabel, org.openide.util.NbBundle.getMessage(LicenseDisclaimerPanel.class, "LicenseDisclaimerPanel.purchaseFromLabel.text")); // NOI18N
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 3);
|
||||
add(purchaseFromLabel, gridBagConstraints);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(link, org.openide.util.NbBundle.getMessage(LicenseDisclaimerPanel.class, "LicenseDisclaimerPanel.link.text")); // NOI18N
|
||||
link.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
|
||||
link.addMouseListener(new java.awt.event.MouseAdapter() {
|
||||
public void mouseClicked(java.awt.event.MouseEvent evt) {
|
||||
linkMouseClicked(evt);
|
||||
}
|
||||
});
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
|
||||
add(link, gridBagConstraints);
|
||||
|
||||
javax.swing.GroupLayout spacerLayout = new javax.swing.GroupLayout(spacer);
|
||||
spacer.setLayout(spacerLayout);
|
||||
spacerLayout.setHorizontalGroup(
|
||||
spacerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 0, Short.MAX_VALUE)
|
||||
);
|
||||
spacerLayout.setVerticalGroup(
|
||||
spacerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 0, Short.MAX_VALUE)
|
||||
);
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 2;
|
||||
gridBagConstraints.weighty = 1.0;
|
||||
add(spacer, gridBagConstraints);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void linkMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_linkMouseClicked
|
||||
if (Desktop.isDesktopSupported()) {
|
||||
try {
|
||||
Desktop.getDesktop().browse(new URI(CHECKOUT_PAGE_URL));
|
||||
} catch (IOException | URISyntaxException e) {
|
||||
LOGGER.log(Level.SEVERE, "Error opening link to: " + CHECKOUT_PAGE_URL, e);
|
||||
}
|
||||
} else {
|
||||
LOGGER.log(Level.WARNING, "Desktop API is not supported. Link cannot be opened.");
|
||||
}
|
||||
}//GEN-LAST:event_linkMouseClicked
|
||||
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
|
||||
# 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.title=Add a License...
|
||||
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=
|
||||
EULADialog.cancelButton.text=Cancel
|
||||
EULADialog.acceptButton.text=Accept
|
||||
EULADialog.title=Cyber Triage End User License Agreement
|
@ -0,0 +1,58 @@
|
||||
|
||||
# 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.title=Add a License...
|
||||
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...
|
||||
EULADialog.cancelButton.text=Cancel
|
||||
EULADialog.acceptButton.text=Accept
|
||||
EULADialog.title=Cyber Triage End User License Agreement
|
@ -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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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>
|
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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*[a-zA-Z0-9\\-]+?\\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
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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.Files;
|
||||
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 {
|
||||
licenseFile.getParentFile().mkdirs();
|
||||
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.exists() && 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();
|
||||
}
|
||||
}
|
@ -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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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>
|
@ -0,0 +1,604 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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.DecryptedLicenseResponse;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseInfo;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseResponse;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.util.LicenseDecryptorUtil;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.util.LicenseDecryptorUtil.InvalidLicenseException;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.io.IOException;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
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.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.netbeans.spi.options.OptionsPanelController;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||
|
||||
/**
|
||||
* Options panel to be displayed in the CTOptionsPanel for settings regarding
|
||||
* Cyber Triage Malware Scanner settings and license setup.
|
||||
*/
|
||||
@ServiceProvider(service = CTOptionsSubPanel.class)
|
||||
public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CTMalwareScannerOptionsPanel.class.getName());
|
||||
|
||||
private static final DateTimeFormatter LICENSE_EXPIRES_FORMAT = DateTimeFormatter
|
||||
.ofPattern("MMMM d, YYYY")
|
||||
.withZone(ZoneId.of(UserPreferences.getInferredUserTimeZone()));
|
||||
|
||||
private static final DateTimeFormatter MALWARE_SCANS_RESET_FORMAT = DateTimeFormatter
|
||||
.ofPattern("MMM d, YYYY' at 'h:mma")
|
||||
.withZone(ZoneId.of(UserPreferences.getInferredUserTimeZone()));
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* Main constructor.
|
||||
*/
|
||||
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());
|
||||
setMalwareScansDisplay(null, null);
|
||||
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);
|
||||
}
|
||||
|
||||
if (licenseInfo == null || licenseInfo.getDecryptedLicense() == null) {
|
||||
setMalwareScansDisplay(null, null);
|
||||
return;
|
||||
}
|
||||
|
||||
setMalwareScansDisplay(null, Bundle.CTOPtionsPanel_loadMalwareScansInfo_loading());
|
||||
|
||||
this.authTokenFetcher = new AuthTokenFetcher(licenseInfo.getDecryptedLicense());
|
||||
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(
|
||||
this.licenseInfo.getDecryptedLicense().getExpirationDate() == null
|
||||
? ""
|
||||
: LICENSE_EXPIRES_FORMAT.format(this.licenseInfo.getDecryptedLicense().getExpirationDate())));
|
||||
this.licenseInfoIdLabel.setVisible(true);
|
||||
this.licenseInfoIdLabel.setText(Bundle.CTMalwareScannerOptionsPanel_licenseInfo_id(StringUtils.defaultString(this.licenseInfo.getDecryptedLicense().getBoostLicenseId())));
|
||||
this.licenseInfoUserLabel.setVisible(true);
|
||||
this.licenseInfoUserLabel.setText(Bundle.CTMalwareScannerOptionsPanel_licenseInfo_userInfo(
|
||||
StringUtils.defaultString(this.licenseInfo.getDecryptedLicense().getCustomerName()),
|
||||
StringUtils.defaultString(this.licenseInfo.getDecryptedLicense().getCustomerEmail())));
|
||||
}
|
||||
|
||||
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(this.authTokenResponse.getResetDate() == null ? "" : MALWARE_SCANS_RESET_FORMAT.format(this.authTokenResponse.getResetDate())));
|
||||
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;
|
||||
}
|
||||
|
||||
private void acceptEula(LicenseResponse licenseResponse) {
|
||||
try {
|
||||
final EULADialog eulaDialog = new EULADialog(WindowManager.getDefault().getMainWindow(), true);
|
||||
eulaDialog.setLocationRelativeTo(this);
|
||||
eulaDialog.setSize(eulaDialog.getPreferredSize());
|
||||
eulaDialog.setVisible(true);
|
||||
|
||||
if (eulaDialog.isAcceptPressed()) {
|
||||
// only indicate a change to save if we have accepted EULA for a license
|
||||
this.licenseInfo = LicenseDecryptorUtil.getInstance().createLicenseInfo(licenseResponse);
|
||||
this.firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||
}
|
||||
} catch (IOException | InvalidLicenseException ex) {
|
||||
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 {
|
||||
setLicenseDisplay(this.licenseInfo, null);
|
||||
loadMalwareScansInfo(this.licenseInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@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<LicenseResponse, Void> {
|
||||
|
||||
private final String licenseText;
|
||||
|
||||
public LicenseFetcher(String licenseText) {
|
||||
this.licenseText = licenseText;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LicenseResponse doInBackground() throws Exception {
|
||||
if (this.isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
return ctApiDAO.getLicenseInfo(licenseText);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
try {
|
||||
LicenseResponse licenseResponse = get();
|
||||
SwingUtilities.invokeLater(() -> acceptEula(licenseResponse));
|
||||
} catch (InterruptedException ex) {
|
||||
// ignore cancellation; just load current license
|
||||
setLicenseDisplay(licenseInfo, null);
|
||||
loadMalwareScansInfo(licenseInfo);
|
||||
} 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);
|
||||
}
|
||||
setLicenseDisplay(licenseInfo, null);
|
||||
loadMalwareScansInfo(licenseInfo);
|
||||
} finally {
|
||||
synchronized (CTMalwareScannerOptionsPanel.this) {
|
||||
CTMalwareScannerOptionsPanel.this.licenseFetcher = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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 DecryptedLicenseResponse decryptedLicense;
|
||||
|
||||
public AuthTokenFetcher(DecryptedLicenseResponse decryptedLicense) {
|
||||
this.decryptedLicense = decryptedLicense;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuthTokenResponse doInBackground() throws Exception {
|
||||
if (this.isCancelled()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ctApiDAO.getAuthToken(decryptedLicense);
|
||||
}
|
||||
|
||||
@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
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,112 @@
|
||||
<?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/ctcloud/Bundle.properties" key="EULADialog.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[32767, 32767]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[550, 550]"/>
|
||||
</Property>
|
||||
<Property name="size" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[550, 550]"/>
|
||||
</Property>
|
||||
</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,2,40,0,0,2,41"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="viewablePanel">
|
||||
<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="1" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="10" weightX="1.0" weightY="1.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="paddingPanel">
|
||||
<Properties>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[32767, 0]"/>
|
||||
</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="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="acceptButton">
|
||||
<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="EULADialog.acceptButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
<Property name="enabled" type="boolean" value="false"/>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="acceptButtonActionPerformed"/>
|
||||
</Events>
|
||||
<Constraints>
|
||||
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
|
||||
<GridBagConstraints gridX="2" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="5" insetsRight="5" anchor="10" 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="EULADialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cancelButtonActionPerformed"/>
|
||||
</Events>
|
||||
<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="1" gridY="1" gridWidth="1" gridHeight="1" fill="0" 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>
|
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.basistech.df.cybertriage.autopsy.ctoptions.ctcloud;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import javafx.application.Platform;
|
||||
import javafx.concurrent.Worker.State;
|
||||
import javafx.embed.swing.JFXPanel;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.web.WebView;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
/**
|
||||
* Dialog for displaying the Cyber Triage EULA before the license is saved.
|
||||
*/
|
||||
public class EULADialog extends javax.swing.JDialog {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(EULADialog.class.getName());
|
||||
private static final String EULA_RESOURCE = "EULA.htm";
|
||||
|
||||
private boolean acceptPressed = false;
|
||||
|
||||
/**
|
||||
* Creates new form EULADialog
|
||||
*/
|
||||
public EULADialog(java.awt.Frame parent, boolean modal) throws IOException {
|
||||
super(parent, modal);
|
||||
initComponents();
|
||||
loadEULA();
|
||||
}
|
||||
|
||||
boolean isAcceptPressed() {
|
||||
return acceptPressed;
|
||||
}
|
||||
|
||||
private void loadEULA() throws IOException {
|
||||
InputStream eulaInputStream = EULADialog.class.getResourceAsStream(EULA_RESOURCE);
|
||||
final String htmlString = IOUtils.toString(eulaInputStream, StandardCharsets.UTF_8);
|
||||
final JFXPanel fxPanel = new JFXPanel();
|
||||
this.viewablePanel.add(fxPanel, BorderLayout.CENTER);
|
||||
Platform.runLater(() -> {
|
||||
WebView webView = new WebView();
|
||||
webView.setMaxSize(Short.MAX_VALUE, Short.MAX_VALUE);
|
||||
webView.setPrefSize(Short.MAX_VALUE, Short.MAX_VALUE);
|
||||
webView.setMinSize(100, 100);
|
||||
webView.getEngine().getLoadWorker().stateProperty().addListener((ov, oldState, newState) -> {
|
||||
if (newState == State.SUCCEEDED) {
|
||||
SwingUtilities.invokeLater(() -> EULADialog.this.acceptButton.setEnabled(true));
|
||||
}
|
||||
});
|
||||
webView.getEngine().loadContent(htmlString, "text/html");
|
||||
VBox root = new VBox(webView);
|
||||
Scene scene = new Scene(root, Color.RED);
|
||||
fxPanel.setScene(scene);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
viewablePanel = new javax.swing.JPanel();
|
||||
javax.swing.JPanel paddingPanel = new javax.swing.JPanel();
|
||||
acceptButton = new javax.swing.JButton();
|
||||
javax.swing.JButton cancelButton = new javax.swing.JButton();
|
||||
|
||||
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
|
||||
setTitle(org.openide.util.NbBundle.getMessage(EULADialog.class, "EULADialog.title")); // NOI18N
|
||||
setMaximumSize(new java.awt.Dimension(32767, 32767));
|
||||
setPreferredSize(new java.awt.Dimension(550, 550));
|
||||
setSize(new java.awt.Dimension(550, 550));
|
||||
getContentPane().setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
viewablePanel.setLayout(new java.awt.BorderLayout());
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 0;
|
||||
gridBagConstraints.gridwidth = 3;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
gridBagConstraints.weighty = 1.0;
|
||||
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
|
||||
getContentPane().add(viewablePanel, gridBagConstraints);
|
||||
|
||||
paddingPanel.setMaximumSize(new java.awt.Dimension(32767, 0));
|
||||
|
||||
javax.swing.GroupLayout paddingPanelLayout = new javax.swing.GroupLayout(paddingPanel);
|
||||
paddingPanel.setLayout(paddingPanelLayout);
|
||||
paddingPanelLayout.setHorizontalGroup(
|
||||
paddingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 0, Short.MAX_VALUE)
|
||||
);
|
||||
paddingPanelLayout.setVerticalGroup(
|
||||
paddingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 0, Short.MAX_VALUE)
|
||||
);
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
getContentPane().add(paddingPanel, gridBagConstraints);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(acceptButton, org.openide.util.NbBundle.getMessage(EULADialog.class, "EULADialog.acceptButton.text")); // NOI18N
|
||||
acceptButton.setEnabled(false);
|
||||
acceptButton.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
acceptButtonActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 2;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 0, 5, 5);
|
||||
getContentPane().add(acceptButton, gridBagConstraints);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(EULADialog.class, "EULADialog.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 = 1;
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
|
||||
getContentPane().add(cancelButton, gridBagConstraints);
|
||||
|
||||
pack();
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void acceptButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_acceptButtonActionPerformed
|
||||
acceptPressed = true;
|
||||
dispose();
|
||||
}//GEN-LAST:event_acceptButtonActionPerformed
|
||||
|
||||
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
|
||||
dispose();
|
||||
}//GEN-LAST:event_cancelButtonActionPerformed
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton acceptButton;
|
||||
private javax.swing.JPanel viewablePanel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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();
|
||||
}
|
BIN
Core/src/com/basistech/df/cybertriage/autopsy/images/logo.png
Normal file
BIN
Core/src/com/basistech/df/cybertriage/autopsy/images/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
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 ExecutorService processingExecutorService = Executors.newSingleThreadExecutor();
|
||||
|
||||
private final BlockingQueue<T> batchingQueue;
|
||||
private final int batchSize;
|
||||
private final Consumer<List<T>> itemsConsumer;
|
||||
private final long secondsTimeout;
|
||||
|
||||
public BatchProcessor(int batchSize, long secondsTimeout, Consumer<List<T>> itemsConsumer) {
|
||||
this.batchingQueue = new LinkedBlockingQueue<>(batchSize);
|
||||
this.batchSize = batchSize;
|
||||
this.itemsConsumer = itemsConsumer;
|
||||
this.secondsTimeout = secondsTimeout;
|
||||
}
|
||||
|
||||
public synchronized void add(T item) throws InterruptedException {
|
||||
batchingQueue.add(item);
|
||||
if (batchingQueue.size() >= batchSize) {
|
||||
asyncProcessBatch();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void flushAndReset() throws InterruptedException {
|
||||
// get any remaining
|
||||
asyncProcessBatch();
|
||||
|
||||
// don't accept any new additions
|
||||
processingExecutorService.shutdown();
|
||||
|
||||
// await termination
|
||||
processingExecutorService.awaitTermination(secondsTimeout, TimeUnit.SECONDS);
|
||||
|
||||
// get new (not shut down executor)
|
||||
processingExecutorService = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
|
||||
private synchronized void asyncProcessBatch() throws InterruptedException {
|
||||
if (!batchingQueue.isEmpty()) {
|
||||
final List<T> processingList = new ArrayList<>();
|
||||
|
||||
// transfer batching queue to processing queue
|
||||
batchingQueue.drainTo(processingList);
|
||||
|
||||
// submit to be processed
|
||||
processingExecutorService.submit(() -> itemsConsumer.accept(processingList));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
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
|
||||
MalwareScanIngestModule_ShareProcessing_noLicense_desc=No Cyber Triage license could be loaded. Cyber Triage processing will be disabled.
|
||||
MalwareScanIngestModule_ShareProcessing_noLicense_title=No Cyber Triage License
|
||||
MalwareScanIngestModule_ShareProcessing_noRemaining_desc=There are no more remaining hash lookups for this license at this time. Cyber Triage processing will be disabled.
|
||||
MalwareScanIngestModule_ShareProcessing_noRemaining_title=No remaining lookups
|
||||
MalwareScanIngestModuleFactory_description=The malware scan ingest module queries the Cyber Triage cloud API for any possible malicious executables.
|
||||
MalwareScanIngestModuleFactory_displayName=Cyber Triage Malware Scanner
|
||||
MalwareScanIngestModuleFactory_version=1.0.0
|
@ -0,0 +1,445 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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.AuthenticatedRequestData;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.CTCloudBean;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseInfo;
|
||||
import com.basistech.df.cybertriage.autopsy.ctoptions.ctcloud.CTLicensePersistence;
|
||||
import java.text.MessageFormat;
|
||||
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.collections4.CollectionUtils;
|
||||
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.AnalysisResult;
|
||||
import org.sleuthkit.datamodel.Blackboard;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.HashUtility;
|
||||
import org.sleuthkit.datamodel.HashUtility.HashResult;
|
||||
import org.sleuthkit.datamodel.HashUtility.HashType;
|
||||
import org.sleuthkit.datamodel.Score;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
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;
|
||||
// 1 day timeout for all API requests
|
||||
private static final long FLUSH_SECS_TIMEOUT = 24 * 60 * 60;
|
||||
|
||||
//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, FLUSH_SECS_TIMEOUT, this::handleBatch);
|
||||
|
||||
private final CTLicensePersistence ctSettingsPersistence = CTLicensePersistence.getInstance();
|
||||
private final CTApiDAO ctApiDAO = CTApiDAO.getInstance();
|
||||
|
||||
private RunState runState = null;
|
||||
|
||||
private SleuthkitCase tskCase = null;
|
||||
private FileTypeDetector fileTypeDetector = null;
|
||||
private LicenseInfo licenseInfo = null;
|
||||
private BlackboardArtifact.Type malwareType = null;
|
||||
private long dsId = 0;
|
||||
private long ingestJobId = 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",
|
||||
"MalwareScanIngestModule_ShareProcessing_noLicense_title=No Cyber Triage License",
|
||||
"MalwareScanIngestModule_ShareProcessing_noLicense_desc=No Cyber Triage license could be loaded. Cyber Triage processing will be disabled.",
|
||||
"MalwareScanIngestModule_ShareProcessing_noRemaining_title=No remaining lookups",
|
||||
"MalwareScanIngestModule_ShareProcessing_noRemaining_desc=There are no more remaining hash lookups for this license at this time. Cyber Triage processing will be disabled."
|
||||
})
|
||||
synchronized void startUp(IngestJobContext context) throws IngestModuleException {
|
||||
// only run this code once per startup
|
||||
if (runState == RunState.STARTED_UP || runState == RunState.DISABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// get saved license
|
||||
Optional<LicenseInfo> licenseInfoOpt = ctSettingsPersistence.loadLicenseInfo();
|
||||
if (licenseInfoOpt.isEmpty() || licenseInfoOpt.get().getDecryptedLicense() == null) {
|
||||
notifyWarning(
|
||||
Bundle.MalwareScanIngestModule_ShareProcessing_noLicense_title(),
|
||||
Bundle.MalwareScanIngestModule_ShareProcessing_noLicense_desc(),
|
||||
null);
|
||||
runState = RunState.DISABLED;
|
||||
return;
|
||||
}
|
||||
|
||||
AuthTokenResponse authTokenResponse = ctApiDAO.getAuthToken(licenseInfoOpt.get().getDecryptedLicense());
|
||||
// syncronously fetch malware scans info
|
||||
|
||||
// determine lookups remaining
|
||||
long lookupsRemaining = remaining(authTokenResponse.getHashLookupLimit(), authTokenResponse.getHashLookupCount());
|
||||
if (lookupsRemaining <= 0) {
|
||||
notifyWarning(
|
||||
Bundle.MalwareScanIngestModule_ShareProcessing_noRemaining_title(),
|
||||
Bundle.MalwareScanIngestModule_ShareProcessing_noRemaining_desc(),
|
||||
null);
|
||||
runState = RunState.DISABLED;
|
||||
return;
|
||||
} 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();
|
||||
ingestJobId = context.getJobId();
|
||||
licenseInfo = licenseInfoOpt.get();
|
||||
|
||||
// set run state to initialized
|
||||
runState = RunState.STARTED_UP;
|
||||
} catch (Exception ex) {
|
||||
runState = RunState.DISABLED;
|
||||
throw new IngestModuleException("An exception occurred on MalwareScanIngestModule startup", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static long remaining(Long limit, Long used) {
|
||||
limit = limit == null ? 0 : limit;
|
||||
used = used == null ? 0 : used;
|
||||
return limit - used;
|
||||
}
|
||||
|
||||
private String getOrCalcHash(AbstractFile af) {
|
||||
if (StringUtils.isNotBlank(af.getMd5Hash())) {
|
||||
return af.getMd5Hash();
|
||||
}
|
||||
|
||||
try {
|
||||
List<HashResult> hashResults = HashUtility.calculateHashes(af, Collections.singletonList(HashType.MD5));
|
||||
if (CollectionUtils.isNotEmpty(hashResults)) {
|
||||
for (HashResult hashResult : hashResults) {
|
||||
if (hashResult.getType() == HashType.MD5) {
|
||||
return hashResult.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING,
|
||||
MessageFormat.format("An error occurred while processing file name: {0} and obj id: {1}.",
|
||||
af.getName(),
|
||||
af.getId()),
|
||||
ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Messages({
|
||||
"MalwareScanIngestModule_ShareProcessing_batchTimeout_title=Batch Processing Timeout",
|
||||
"MalwareScanIngestModule_ShareProcessing_batchTimeout_desc=Batch processing timed out"
|
||||
})
|
||||
IngestModule.ProcessResult process(AbstractFile af) {
|
||||
try {
|
||||
if (runState == RunState.STARTED_UP
|
||||
&& af.getKnown() != TskData.FileKnown.KNOWN
|
||||
&& EXECUTABLE_MIME_TYPES.contains(StringUtils.defaultString(fileTypeDetector.getMIMEType(af)).trim().toLowerCase())
|
||||
&& CollectionUtils.isEmpty(af.getAnalysisResults(malwareType))) {
|
||||
|
||||
String md5 = getOrCalcHash(af);
|
||||
if (StringUtils.isNotBlank(md5)) {
|
||||
batchProcessor.add(new FileRecord(af.getId(), md5));
|
||||
}
|
||||
}
|
||||
return ProcessResult.OK;
|
||||
} catch (TskCoreException ex) {
|
||||
notifyWarning(
|
||||
Bundle.MalwareScanIngestModule_SharedProcessing_generalProcessingError_title(),
|
||||
Bundle.MalwareScanIngestModule_SharedProcessing_generalProcessingError_desc(),
|
||||
ex);
|
||||
return IngestModule.ProcessResult.ERROR;
|
||||
} 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 (runState != RunState.STARTED_UP || fileRecords == null || fileRecords.isEmpty()) {
|
||||
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<>();
|
||||
|
||||
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());
|
||||
|
||||
}
|
||||
|
||||
List<String> md5Hashes = new ArrayList<>(md5ToObjId.keySet());
|
||||
|
||||
if (md5Hashes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// get an auth token with the license
|
||||
AuthTokenResponse authTokenResponse = ctApiDAO.getAuthToken(licenseInfo.getDecryptedLicense());
|
||||
|
||||
// make sure we are in bounds for the remaining scans
|
||||
long remainingScans = remaining(authTokenResponse.getHashLookupLimit(), authTokenResponse.getHashLookupCount());
|
||||
if (remainingScans <= 0) {
|
||||
runState = RunState.DISABLED;
|
||||
notifyWarning(
|
||||
Bundle.MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_title(),
|
||||
Bundle.MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_desc(),
|
||||
null);
|
||||
return;
|
||||
}
|
||||
|
||||
// using auth token, get results
|
||||
List<CTCloudBean> repResult = ctApiDAO.getReputationResults(
|
||||
new AuthenticatedRequestData(licenseInfo.getDecryptedLicense(), authTokenResponse),
|
||||
md5Hashes
|
||||
);
|
||||
|
||||
List<BlackboardArtifact> createdArtifacts = new ArrayList<>();
|
||||
if (!CollectionUtils.isEmpty(repResult)) {
|
||||
SleuthkitCase.CaseDbTransaction trans = null;
|
||||
try {
|
||||
trans = tskCase.beginTransaction();
|
||||
for (CTCloudBean result : repResult) {
|
||||
String sanitizedMd5 = sanitizedMd5(result.getMd5HashValue());
|
||||
List<Long> objIds = md5ToObjId.remove(sanitizedMd5);
|
||||
if (objIds == null || objIds.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Long objId : objIds) {
|
||||
AnalysisResult res = createAnalysisResult(objId, result, trans);
|
||||
if (res != null) {
|
||||
createdArtifacts.add(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trans.commit();
|
||||
trans = null;
|
||||
} finally {
|
||||
if (trans != null) {
|
||||
trans.rollback();
|
||||
createdArtifacts.clear();
|
||||
trans = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!CollectionUtils.isEmpty(createdArtifacts)) {
|
||||
tskCase.getBlackboard().postArtifacts(createdArtifacts, Bundle.MalwareScanIngestModuleFactory_displayName(), ingestJobId);
|
||||
}
|
||||
}
|
||||
} 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 AnalysisResult createAnalysisResult(Long objId, CTCloudBean cloudBean, SleuthkitCase.CaseDbTransaction trans) throws Blackboard.BlackboardException {
|
||||
if (objId == null || cloudBean == null || cloudBean.getMalwareResult() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Score score = cloudBean.getMalwareResult().getCTScore() == null
|
||||
? Score.SCORE_UNKNOWN
|
||||
: cloudBean.getMalwareResult().getCTScore().getTskCore();
|
||||
|
||||
String conclusion = score.getSignificance() == Score.Significance.NOTABLE || score.getSignificance() == Score.Significance.LIKELY_NOTABLE
|
||||
? Bundle.MalwareScanIngestModule_SharedProcessing_createAnalysisResult_Yes()
|
||||
: Bundle.MalwareScanIngestModule_SharedProcessing_createAnalysisResult_No();
|
||||
|
||||
String justification = cloudBean.getMalwareResult().getStatusDescription();
|
||||
|
||||
return tskCase.getBlackboard().newAnalysisResult(
|
||||
malwareType,
|
||||
objId,
|
||||
dsId,
|
||||
score,
|
||||
conclusion,
|
||||
MALWARE_CONFIG,
|
||||
justification,
|
||||
Collections.emptyList(),
|
||||
trans).getAnalysisResult();
|
||||
}
|
||||
|
||||
@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.flushAndReset();
|
||||
} 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
|
||||
runState = RunState.SHUT_DOWN;
|
||||
}
|
||||
}
|
||||
|
||||
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, DISABLED, 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2023 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package 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=Cyber Triage Malware Scanner",
|
||||
"MalwareScanIngestModuleFactory_description=The malware scan ingest module queries the Cyber Triage cloud API for any possible malicious executables.",
|
||||
"MalwareScanIngestModuleFactory_version=1.0.0"
|
||||
})
|
||||
public class MalwareScanIngestModuleFactory extends IngestModuleFactoryAdapter {
|
||||
|
||||
/**
|
||||
* @return The display name for the factory (static method).
|
||||
*/
|
||||
public static String getDisplayName() {
|
||||
return Bundle.MalwareScanIngestModuleFactory_displayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModuleDisplayName() {
|
||||
return MalwareScanIngestModuleFactory.getDisplayName();
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
@ -22,6 +22,7 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
@ -385,6 +386,30 @@ public final class UserPreferences {
|
||||
public static String getTimeZoneForDisplays() {
|
||||
return viewPreferences.get(TIME_ZONE_FOR_DISPLAYS, TimeZone.GMT_ZONE.getID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inferred preferred time zone deriving in order:
|
||||
* 1) Starts with user preference if set
|
||||
* 2) Gets system time zone if can be determined
|
||||
* 3) Otherwise uses GMT
|
||||
*
|
||||
* @return Returns preferred time zone id.
|
||||
*/
|
||||
public static String getInferredUserTimeZone() {
|
||||
String timeZonePref = viewPreferences.get(TIME_ZONE_FOR_DISPLAYS, null);
|
||||
if (StringUtils.isBlank(timeZonePref)) {
|
||||
ZoneId systemZoneId = ZoneId.systemDefault();
|
||||
if (systemZoneId != null) {
|
||||
timeZonePref = systemZoneId.getId();
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(timeZonePref)) {
|
||||
timeZonePref = TimeZone.GMT_ZONE.getID();
|
||||
}
|
||||
|
||||
return timeZonePref;
|
||||
}
|
||||
|
||||
public static void setTimeZoneForDisplays(String timeZone) {
|
||||
viewPreferences.put(TIME_ZONE_FOR_DISPLAYS, timeZone);
|
||||
|
@ -101,7 +101,7 @@ ImageNode.createSheet.name.displayName=Name
|
||||
ImageNode.createSheet.name.desc=no description
|
||||
Installer.exception.tskVerStringNull.msg=Sleuth Kit JNI test call returned without error, but version string was null\!
|
||||
Installer.exception.taskVerStringBang.msg=Sleuth Kit JNI test call returned without error, but version string was ""\!
|
||||
Installer.tskLibErr.msg=Problem with Sleuth Kit JNI. Test call failed\!\n\nDetails: {0}
|
||||
Installer.tskLibErr.msg=Problem with Sleuth Kit JNI. Test call failed\!\n Is Autopsy or Cyber Triage already running?\n\nDetails: {0}
|
||||
Installer.tskLibErr.err=Fatal Error\!
|
||||
InterestingHits.interestingItems.text=INTERESTING ITEMS
|
||||
InterestingHits.displayName.text=Interesting Items
|
||||
|
@ -315,7 +315,7 @@ ImageNode.createSheet.name.displayName=Name
|
||||
ImageNode.createSheet.name.desc=no description
|
||||
Installer.exception.tskVerStringNull.msg=Sleuth Kit JNI test call returned without error, but version string was null\!
|
||||
Installer.exception.taskVerStringBang.msg=Sleuth Kit JNI test call returned without error, but version string was ""\!
|
||||
Installer.tskLibErr.msg=Problem with Sleuth Kit JNI. Test call failed\!\n\nDetails: {0}
|
||||
Installer.tskLibErr.msg=Problem with Sleuth Kit JNI. Test call failed\!\n Is Autopsy or Cyber Triage already running?\n\nDetails: {0}
|
||||
Installer.tskLibErr.err=Fatal Error\!
|
||||
InterestingHits.interestingItems.text=INTERESTING ITEMS
|
||||
InterestingHits.displayName.text=Interesting Items
|
||||
@ -418,6 +418,7 @@ ScoreContent_createSheet_filterType_displayName=Type
|
||||
ScoreContent_createSheet_name_desc=no description
|
||||
ScoreContent_createSheet_name_displayName=Name
|
||||
ScoreContent_ScoreContentNode_name=Score
|
||||
ScoreContent_ScoreFileNode_type=File
|
||||
ScoreContent_susFilter_text=Suspicious Items
|
||||
SlackFileNode.getActions.viewInNewWin.text=View in New Window
|
||||
SlackFileNode.getActions.viewFileInDir.text=View File in Directory
|
||||
|
@ -70,8 +70,9 @@ public class Installer extends ModuleInstall {
|
||||
logger.log(Level.CONFIG, "Sleuth Kit Version: {0}", skVersion); //NON-NLS
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
} catch (Exception | UnsatisfiedLinkError e) {
|
||||
logger.log(Level.SEVERE, "Error calling Sleuth Kit library (test call failed)", e); //NON-NLS
|
||||
logger.log(Level.SEVERE, "Is Autopsy or Cyber Triage already running?)", e); //NON-NLS
|
||||
|
||||
// Normal error box log handler won't be loaded yet, so show error here.
|
||||
final Component parentComponent = null; // Use default window frame.
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.ingest;
|
||||
|
||||
import com.basistech.df.cybertriage.autopsy.malwarescan.MalwareScanIngestModuleFactory;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
@ -33,7 +34,10 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.io.NbObjectInputStream;
|
||||
import org.openide.util.io.NbObjectOutputStream;
|
||||
@ -54,6 +58,11 @@ public final class IngestJobSettings {
|
||||
private static final String LAST_FILE_INGEST_FILTER_PROPERTY = "Last_File_Ingest_Filter"; //NON-NLS
|
||||
private static final String MODULE_SETTINGS_FOLDER_NAME = "IngestSettings"; //NON-NLS
|
||||
|
||||
private static final Set<String> DEFAULT_DISABLED_MODULES = Stream.of(
|
||||
"Plaso",
|
||||
MalwareScanIngestModuleFactory.getDisplayName()
|
||||
).collect(Collectors.toSet());
|
||||
|
||||
private static final String MODULE_SETTINGS_FOLDER = Paths.get(
|
||||
Paths.get(PlatformUtil.getUserConfigDirectory()).relativize(Paths.get(PlatformUtil.getModuleConfigDirectory())).toString(),
|
||||
MODULE_SETTINGS_FOLDER_NAME
|
||||
@ -361,37 +370,36 @@ public final class IngestJobSettings {
|
||||
loadedModuleNames.add(moduleFactory.getModuleDisplayName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Hard coding Plaso to be disabled by default. loadedModuleNames is
|
||||
* passed below as the default list of enabled modules so briefly remove
|
||||
* Plaso from loaded modules to get the list of enabled and disabled
|
||||
* modules names. Then put Plaso back into loadedModulesNames to let the
|
||||
* rest of the code continue as before.
|
||||
*/
|
||||
final String plasoModuleName = "Plaso";
|
||||
boolean plasoLoaded = loadedModuleNames.contains(plasoModuleName);
|
||||
if (plasoLoaded) {
|
||||
loadedModuleNames.remove(plasoModuleName);
|
||||
|
||||
Set<String> defaultEnabledAndLoaded = new HashSet<>();
|
||||
Set<String> defaultDisabledAndLoaded = new HashSet<>();
|
||||
for (String loadedModule: loadedModuleNames) {
|
||||
if (DEFAULT_DISABLED_MODULES.contains(loadedModule)) {
|
||||
defaultDisabledAndLoaded.add(loadedModule);
|
||||
} else {
|
||||
defaultEnabledAndLoaded.add(loadedModule);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the enabled/disabled ingest modules settings for this context. By
|
||||
* default, all loaded modules except Plaso are enabled.
|
||||
*/
|
||||
HashSet<String> enabledModuleNames = getModulesNames(this.executionContext, IngestJobSettings.ENABLED_MODULES_PROPERTY, makeCsvList(loadedModuleNames));
|
||||
HashSet<String> disabledModuleNames = getModulesNames(this.executionContext, IngestJobSettings.DISABLED_MODULES_PROPERTY, plasoModuleName); //NON-NLS
|
||||
HashSet<String> enabledModuleNames = getModulesNames(this.executionContext, IngestJobSettings.ENABLED_MODULES_PROPERTY, makeCsvList(defaultEnabledAndLoaded));
|
||||
HashSet<String> disabledModuleNames = getModulesNames(this.executionContext, IngestJobSettings.DISABLED_MODULES_PROPERTY, makeCsvList(defaultDisabledAndLoaded)); //NON-NLS
|
||||
|
||||
// If plaso was loaded, but appears in neither the enabled nor the
|
||||
// disabled list, add it to the disabled list.
|
||||
if (!enabledModuleNames.contains(plasoModuleName) && !disabledModuleNames.contains(plasoModuleName)) {
|
||||
disabledModuleNames.add(plasoModuleName);
|
||||
// double check to ensure all loaded modules are present in one of the lists in case more modules (in case settings didn't have a module)
|
||||
for (String loadedModule : loadedModuleNames) {
|
||||
// if neither enabled modules or disabled modules contains the loaded module, add it to the default location
|
||||
if (!enabledModuleNames.contains(loadedModule) && !disabledModuleNames.contains(loadedModule)) {
|
||||
if (DEFAULT_DISABLED_MODULES.contains(loadedModule)) {
|
||||
disabledModuleNames.add(loadedModule);
|
||||
} else {
|
||||
enabledModuleNames.add(loadedModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Put plaso back into loadedModuleNames
|
||||
if (plasoLoaded) {
|
||||
loadedModuleNames.add(plasoModuleName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check for missing modules and create warnings if any are found.
|
||||
*/
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.integrationtesting;
|
||||
|
||||
import com.basistech.df.cybertriage.autopsy.malwarescan.MalwareScanIngestModuleFactory;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
@ -46,7 +47,10 @@ public class ConfigurationModuleManager {
|
||||
private static final Logger logger = Logger.getLogger(ConfigurationModuleManager.class.getName());
|
||||
|
||||
private static final IngestJobSettings.IngestType DEFAULT_INGEST_FILTER_TYPE = IngestJobSettings.IngestType.ALL_MODULES;
|
||||
private static final Set<String> DEFAULT_EXCLUDED_MODULES = Stream.of("Plaso").collect(Collectors.toSet());
|
||||
private static final Set<String> DEFAULT_EXCLUDED_MODULES = Stream.of(
|
||||
"Plaso",
|
||||
MalwareScanIngestModuleFactory.getDisplayName()
|
||||
).collect(Collectors.toSet());
|
||||
private static final ConfigDeserializer configDeserializer = new ConfigDeserializer();
|
||||
|
||||
/**
|
||||
|
@ -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"/>
|
||||
|
@ -11,4 +11,4 @@ Specification-Version: 1.0
|
||||
Specification-Vendor: CoreLibs ImageIO Fields
|
||||
Implementation-Title: org.sleuthkit.autopsy.corelibs.ImageIO
|
||||
Implementation-Version: 1.0
|
||||
Implementation-Vendor: CoreLibs ImageIO Fields
|
||||
Implementation-Vendor: CoreLibs ImageIO Fields
|
||||
|
@ -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
|
||||
|
@ -63,6 +63,12 @@
|
||||
<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.deser</package>
|
||||
<package>com.fasterxml.jackson.datatype.jsr310.deser.key</package>
|
||||
<package>com.fasterxml.jackson.datatype.jsr310.ser</package>
|
||||
<package>com.fasterxml.jackson.datatype.jsr310.ser.key</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 +203,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 +325,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 +341,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 +362,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 +432,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 +440,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 +904,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>
|
||||
|
@ -1,5 +1,5 @@
|
||||
#Updated by build script
|
||||
#Wed, 28 Sep 2022 13:57:05 -0400
|
||||
#Thu, 20 Jul 2023 19:55:04 -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
|
||||
|
@ -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 19:55:04 -0400
|
||||
CTL_MainWindow_Title=Autopsy 4.20.0
|
||||
CTL_MainWindow_Title_No_Project=Autopsy 4.20.0
|
||||
|
Loading…
x
Reference in New Issue
Block a user