mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-06 21:00:22 +00:00
Merge pull request #7828 from gdicristofaro/CT-7161-fileUpload
CT-7161 file upload
This commit is contained in:
commit
56e7958ba6
@ -27,7 +27,9 @@ 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.json.MetadataUploadRequest;
|
||||
import com.basistech.df.cybertriage.autopsy.ctapi.util.CTHostIDGenerationUtil;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -45,6 +47,8 @@ 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 CTCLOUD_UPLOAD_FILE_METADATA_PATH = "/_ah/api/reputation/v1/upload/meta";
|
||||
|
||||
private static final String AUTOPSY_PRODUCT = "AUTOPSY";
|
||||
|
||||
private static final CTApiDAO instance = new CTApiDAO();
|
||||
@ -74,15 +78,27 @@ public class CTApiDAO {
|
||||
}
|
||||
|
||||
public AuthTokenResponse getAuthToken(DecryptedLicenseResponse decrypted) throws CTCloudException {
|
||||
return getAuthToken(decrypted, false);
|
||||
}
|
||||
|
||||
public AuthTokenResponse getAuthToken(DecryptedLicenseResponse decrypted, boolean fileUpload) throws CTCloudException {
|
||||
AuthTokenRequest authTokenRequest = new AuthTokenRequest()
|
||||
.setAutopsyVersion(getAppVersion())
|
||||
.setRequestFileUpload(false)
|
||||
.setRequestFileUpload(fileUpload)
|
||||
.setBoostLicenseId(decrypted.getBoostLicenseId())
|
||||
.setHostId(decrypted.getLicenseHostId());
|
||||
|
||||
return httpClient.doPost(AUTH_TOKEN_REQUEST_PATH, authTokenRequest, AuthTokenResponse.class);
|
||||
}
|
||||
|
||||
public void uploadFile(String url, String fileName, InputStream fileIs) throws CTCloudException {
|
||||
httpClient.doFileUploadPost(url, fileName, fileIs);
|
||||
}
|
||||
|
||||
public void uploadMeta(AuthenticatedRequestData authenticatedRequestData, MetadataUploadRequest metaRequest) throws CTCloudException {
|
||||
httpClient.doPost(CTCLOUD_UPLOAD_FILE_METADATA_PATH, getAuthParams(authenticatedRequestData), metaRequest, null);
|
||||
}
|
||||
|
||||
private static Map<String, String> getAuthParams(AuthenticatedRequestData authenticatedRequestData) {
|
||||
return new HashMap<String, String>() {
|
||||
{
|
||||
|
@ -76,8 +76,7 @@ public class CTCloudException extends Exception{
|
||||
|
||||
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.",
|
||||
return String.format("An API error %s occurred. Please try again, and contact Basis support at %s for help if the problem persists.",
|
||||
StringUtils.isNotBlank(getCause().getLocalizedMessage()) ? "("+getCause().getLocalizedMessage()+")": "(Unknown)",
|
||||
Constants.SUPPORT_AT_CYBERTRIAGE_DOT_COM );
|
||||
}else {
|
||||
|
@ -21,42 +21,37 @@ 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.io.InputStream;
|
||||
import java.net.Proxy;
|
||||
import java.net.ProxySelector;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStore;
|
||||
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.Collection;
|
||||
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 java.util.stream.Stream;
|
||||
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.lang.ArrayUtils;
|
||||
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;
|
||||
@ -64,102 +59,83 @@ 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.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||
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.apache.http.impl.conn.SystemDefaultRoutePlanner;
|
||||
import org.apache.http.ssl.SSLInitializationException;
|
||||
import org.netbeans.core.ProxySettings;
|
||||
import org.openide.util.Lookup;
|
||||
import org.sleuthkit.autopsy.coreutils.Version;
|
||||
|
||||
/**
|
||||
* Makes the http requests to CT cloud.
|
||||
*
|
||||
* NOTE: regarding proxy settings, the host and port are handled by the
|
||||
* NbProxySelector. Any proxy authentication is handled by NbAuthenticator which
|
||||
* is installed at startup (i.e. NbAuthenticator.install). See
|
||||
* GeneralOptionsModel.testHttpConnection to see how the general options panel
|
||||
* tests the connection.
|
||||
*/
|
||||
public class CTCloudHttpClient {
|
||||
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 String NB_PROXY_SELECTOR_NAME = "org.netbeans.core.NbProxySelector";
|
||||
|
||||
private static final int CONNECTION_TIMEOUT_MS = 58 * 1000; // milli sec
|
||||
|
||||
private static final CTCloudHttpClient instance = new CTCloudHttpClient();
|
||||
|
||||
public static CTCloudHttpClient getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private final ObjectMapper mapper = ObjectMapperUtil.getInstance().getDefaultObjectMapper();
|
||||
private final SSLContext sslContext;
|
||||
private String hostName = null;
|
||||
private final ProxySelector proxySelector;
|
||||
|
||||
private CTCloudHttpClient() {
|
||||
// leave as null for now unless we want to customize this at a later date
|
||||
this.sslContext = null;
|
||||
this.sslContext = createSSLContext();
|
||||
this.proxySelector = getProxySelector();
|
||||
}
|
||||
|
||||
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);
|
||||
private static URI getUri(String host, String path, Map<String, String> urlReqParams) throws URISyntaxException {
|
||||
String url = host + path;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
URI postURI = null;
|
||||
try {
|
||||
|
||||
postURI = getUri(HOST_URL, urlPath, urlReqParams);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
try (CloseableHttpClient httpclient = createConnection(proxySelector, sslContext)) {
|
||||
|
||||
URI postURI = builder.build();
|
||||
HttpPost postRequest = new HttpPost(postURI);
|
||||
|
||||
|
||||
configureRequestTimeout(postRequest);
|
||||
postRequest.setHeader("Content-type", "application/json");
|
||||
|
||||
@ -177,10 +153,14 @@ public class CTCloudHttpClient {
|
||||
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;
|
||||
if (classType != null) {
|
||||
HttpEntity entity = response.getEntity();
|
||||
String entityStr = EntityUtils.toString(entity);
|
||||
O respObj = mapper.readValue(entityStr, classType);
|
||||
return respObj;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
LOGGER.log(Level.WARNING, "Response Received. - Status Error {}", response.getStatusLine());
|
||||
handleNonOKResponse(response, "");
|
||||
@ -191,16 +171,64 @@ public class CTCloudHttpClient {
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.WARNING, "IO Exception raised when connecting to CT Cloud using " + url, ex);
|
||||
LOGGER.log(Level.WARNING, "IO Exception raised when connecting to CT Cloud using " + postURI, ex);
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.NETWORK_ERROR, ex);
|
||||
} catch (SSLInitializationException ex) {
|
||||
LOGGER.log(Level.WARNING, "No such algorithm exception raised when creating SSL connection for CT Cloud using " + postURI, ex);
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.NETWORK_ERROR, ex);
|
||||
} catch (URISyntaxException ex) {
|
||||
LOGGER.log(Level.WARNING, "Wrong URL syntax for CT Cloud " + url, ex);
|
||||
LOGGER.log(Level.WARNING, "Wrong URL syntax for CT Cloud " + postURI, ex);
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.UNKNOWN, ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void doFileUploadPost(String fullUrlPath, String fileName, InputStream fileIs) throws CTCloudException {
|
||||
URI postUri;
|
||||
try {
|
||||
postUri = new URI(fullUrlPath);
|
||||
} catch (URISyntaxException ex) {
|
||||
LOGGER.log(Level.WARNING, "Wrong URL syntax for CT Cloud " + fullUrlPath, ex);
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.UNKNOWN, ex);
|
||||
}
|
||||
|
||||
try (CloseableHttpClient httpclient = createConnection(proxySelector, sslContext)) {
|
||||
LOGGER.log(Level.INFO, "initiating http post request to ctcloud server " + fullUrlPath);
|
||||
HttpPost post = new HttpPost(postUri);
|
||||
configureRequestTimeout(post);
|
||||
|
||||
post.addHeader("Connection", "keep-alive");
|
||||
|
||||
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
|
||||
builder.addBinaryBody(
|
||||
"file",
|
||||
fileIs,
|
||||
ContentType.APPLICATION_OCTET_STREAM,
|
||||
fileName
|
||||
);
|
||||
|
||||
HttpEntity multipart = builder.build();
|
||||
post.setEntity(multipart);
|
||||
|
||||
try (CloseableHttpResponse response = httpclient.execute(post)) {
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_NO_CONTENT) {
|
||||
LOGGER.log(Level.INFO, "Response Received. - Status OK");
|
||||
} else {
|
||||
LOGGER.log(Level.WARNING, MessageFormat.format("Response Received. - Status Error {0}", response.getStatusLine()));
|
||||
handleNonOKResponse(response, fileName);
|
||||
}
|
||||
}
|
||||
} catch (SSLInitializationException ex) {
|
||||
LOGGER.log(Level.WARNING, "SSL exception raised when connecting to Reversing Labs for file content upload ", ex);
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.NETWORK_ERROR, ex);
|
||||
} catch (IOException ex) {
|
||||
LOGGER.log(Level.WARNING, "IO Exception raised when connecting to Reversing Labs for file content upload ", ex);
|
||||
throw new CTCloudException(CTCloudException.ErrorCode.NETWORK_ERROR, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic way to handle the HTTP response - when the response code is NOT
|
||||
* 200 OK.
|
||||
@ -263,147 +291,140 @@ public class CTCloudHttpClient {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Get ProxySelector present (favoring NbProxySelector if present).
|
||||
*
|
||||
* @return The found ProxySelector or null.
|
||||
*/
|
||||
private static CloseableHttpClient createConnection(ProxySettingArgs proxySettings, SSLContext sslContext) {
|
||||
HttpClientBuilder builder = getHttpClientBuilder(proxySettings);
|
||||
|
||||
if (sslContext != null) {
|
||||
builder.setSSLContext(sslContext);
|
||||
}
|
||||
return builder.build();
|
||||
private static ProxySelector getProxySelector() {
|
||||
Collection<? extends ProxySelector> selectors = Lookup.getDefault().lookupAll(ProxySelector.class);
|
||||
return (selectors != null ? selectors.stream() : Stream.empty())
|
||||
.filter(s -> s != null)
|
||||
.map(s -> (ProxySelector) s)
|
||||
.sorted((a, b) -> {
|
||||
String aName = a.getClass().getCanonicalName();
|
||||
String bName = b.getClass().getCanonicalName();
|
||||
boolean aIsNb = aName.equalsIgnoreCase(NB_PROXY_SELECTOR_NAME);
|
||||
boolean bIsNb = bName.equalsIgnoreCase(NB_PROXY_SELECTOR_NAME);
|
||||
if (aIsNb == bIsNb) {
|
||||
return StringUtils.compareIgnoreCase(aName, bName);
|
||||
} else {
|
||||
return aIsNb ? -1 : 1;
|
||||
}
|
||||
})
|
||||
.findFirst()
|
||||
// TODO take this out to remove proxy selector logging
|
||||
.map(s -> new LoggingProxySelector(s))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private static HttpClientBuilder getHttpClientBuilder(ProxySettingArgs proxySettings) {
|
||||
/**
|
||||
* Create an SSLContext object using our in-memory keystore.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static SSLContext createSSLContext() {
|
||||
LOGGER.log(Level.INFO, "Creating custom SSL context");
|
||||
try {
|
||||
|
||||
if (proxySettings.isSystemOrManualProxy()) {
|
||||
// I'm not sure how much of this is really necessary to set up, but it works
|
||||
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
|
||||
KeyManager[] keyManagers = getKeyManagers();
|
||||
TrustManager[] trustManagers = getTrustManagers();
|
||||
sslContext.init(keyManagers, trustManagers, new SecureRandom());
|
||||
return sslContext;
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error creating SSL context", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
LOGGER.info("Requesting Password Authentication...");
|
||||
return super.getPasswordAuthentication();
|
||||
}
|
||||
});
|
||||
// jvm default key manager
|
||||
// based in part on this: https://stackoverflow.com/questions/1793979/registering-multiple-keystores-in-jvm/16229909
|
||||
private static KeyManager[] getKeyManagers() {
|
||||
LOGGER.log(Level.INFO, "Using default algorithm to create trust store: " + KeyManagerFactory.getDefaultAlgorithm());
|
||||
try {
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
kmf.init(null, null);
|
||||
return kmf.getKeyManagers();
|
||||
} catch (NoSuchAlgorithmException | KeyStoreException | UnrecoverableKeyException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error getting KeyManagers", ex);
|
||||
return new KeyManager[0];
|
||||
}
|
||||
|
||||
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());
|
||||
// jvm default trust store
|
||||
// based in part on this: https://stackoverflow.com/questions/1793979/registering-multiple-keystores-in-jvm/16229909
|
||||
private static TrustManager[] getTrustManagers() {
|
||||
try {
|
||||
LOGGER.log(Level.INFO, "Using default algorithm to create trust store: " + TrustManagerFactory.getDefaultAlgorithm());
|
||||
TrustManagerFactory tmf
|
||||
= TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init((KeyStore) null);
|
||||
X509TrustManager tm = (X509TrustManager) tmf.getTrustManagers()[0];
|
||||
|
||||
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();
|
||||
return new TrustManager[]{tm};
|
||||
} catch (KeyStoreException | NoSuchAlgorithmException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error getting TrustManager", ex);
|
||||
return new TrustManager[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a CredentialsProvider for proxy, if one is configured.
|
||||
* Creates a connection to CT Cloud with the given arguments.
|
||||
*
|
||||
* @return CredentialsProvider, if a proxy is configured with credentials,
|
||||
* null otherwise
|
||||
* @param proxySelector The proxy selector.
|
||||
* @param sslContext The ssl context or null.
|
||||
* @return The connection to CT Cloud.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
}
|
||||
private static CloseableHttpClient createConnection(ProxySelector proxySelector, SSLContext sslContext) throws SSLInitializationException {
|
||||
HttpClientBuilder builder;
|
||||
|
||||
if (ProxySettings.getProxyType() != ProxySettings.DIRECT_CONNECTION
|
||||
&& StringUtils.isBlank(ProxySettings.getAuthenticationUsername())
|
||||
&& ArrayUtils.isEmpty(ProxySettings.getAuthenticationPassword())
|
||||
&& WinHttpClients.isWinAuthAvailable()) {
|
||||
|
||||
builder = WinHttpClients.custom();
|
||||
builder.useSystemProperties();
|
||||
LOGGER.log(Level.WARNING, "Using Win HTTP Client");
|
||||
} else {
|
||||
builder = HttpClients.custom();
|
||||
// builder.setDefaultRequestConfig(config);
|
||||
LOGGER.log(Level.WARNING, "Using default http client");
|
||||
}
|
||||
|
||||
return proxyCredsProvider;
|
||||
if (sslContext != null) {
|
||||
builder.setSSLContext(sslContext);
|
||||
}
|
||||
|
||||
if (proxySelector != null) {
|
||||
builder.setRoutePlanner(new SystemDefaultRoutePlanner(proxySelector));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static class ProxySettingArgs {
|
||||
private static class LoggingProxySelector extends ProxySelector {
|
||||
|
||||
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;
|
||||
private final ProxySelector delegate;
|
||||
|
||||
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;
|
||||
public LoggingProxySelector(ProxySelector delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
boolean isSystemOrManualProxy() {
|
||||
return systemOrManualProxy;
|
||||
@Override
|
||||
public List<Proxy> select(URI uri) {
|
||||
List<Proxy> selectedProxies = delegate.select(uri);
|
||||
LOGGER.log(Level.INFO, MessageFormat.format("Proxy selected for {0} are {1}", uri, selectedProxies));
|
||||
return selectedProxies;
|
||||
}
|
||||
|
||||
String getHostName() {
|
||||
return hostName;
|
||||
@Override
|
||||
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
|
||||
LOGGER.log(Level.WARNING, MessageFormat.format("Connection failed connecting to {0} socket address {1}", uri, sa), ioe);
|
||||
delegate.connectFailed(uri, sa, ioe);
|
||||
}
|
||||
|
||||
String getProxyHostname() {
|
||||
return proxyHostname;
|
||||
}
|
||||
|
||||
int getProxyPort() {
|
||||
return proxyPort;
|
||||
}
|
||||
|
||||
String getProxyUserId() {
|
||||
return proxyUserId;
|
||||
}
|
||||
|
||||
char[] getProxyPassword() {
|
||||
return proxyPassword;
|
||||
}
|
||||
|
||||
public String getAuthScheme() {
|
||||
return authScheme;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ import java.net.URI;
|
||||
/**
|
||||
* Constants regarding connections to cyber triage cloud.
|
||||
*/
|
||||
final public class Constants {
|
||||
final class Constants {
|
||||
|
||||
public static final String CYBER_TRIAGE = "CyberTriage";
|
||||
|
||||
|
@ -1,446 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
@ -38,7 +38,7 @@ public class DecryptedLicenseResponse {
|
||||
private final Long fileUploads;
|
||||
private final Instant activationTime;
|
||||
private final String product;
|
||||
private final String limitType;
|
||||
private final LicenseLimitType limitType;
|
||||
private final String timezone;
|
||||
private final String customerEmail;
|
||||
private final String customerName;
|
||||
@ -54,7 +54,7 @@ public class DecryptedLicenseResponse {
|
||||
@JsonDeserialize(using = InstantEpochMillisDeserializer.class)
|
||||
@JsonProperty("activationTime") Instant activationTime,
|
||||
@JsonProperty("product") String product,
|
||||
@JsonProperty("limitType") String limitType,
|
||||
@JsonProperty("limitType") LicenseLimitType limitType,
|
||||
@JsonProperty("timezone") String timezone,
|
||||
@JsonProperty("customerEmail") String customerEmail,
|
||||
@JsonProperty("customerName") String customerName
|
||||
@ -96,7 +96,7 @@ public class DecryptedLicenseResponse {
|
||||
return product;
|
||||
}
|
||||
|
||||
public String getLimitType() {
|
||||
public LicenseLimitType getLimitType() {
|
||||
return limitType;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* The limit type (and reset) for the license.
|
||||
*/
|
||||
public enum LicenseLimitType {
|
||||
HOURLY,
|
||||
DAILY,
|
||||
WEEKLY,
|
||||
MONTHLY,
|
||||
NO_RESET;
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class MetadataUploadRequest {
|
||||
|
||||
@JsonProperty("file_upload_url")
|
||||
private String fileUploadUrl;
|
||||
|
||||
@JsonProperty("sha1")
|
||||
private String sha1;
|
||||
|
||||
@JsonProperty("sha256")
|
||||
private String sha256;
|
||||
|
||||
@JsonProperty("md5")
|
||||
private String md5;
|
||||
|
||||
@JsonProperty("filePath")
|
||||
private String filePath;
|
||||
|
||||
@JsonProperty("fileSize")
|
||||
private Long fileSizeBytes;
|
||||
|
||||
@JsonProperty("createdDate")
|
||||
private Long createdDate;
|
||||
|
||||
public String getFileUploadUrl() {
|
||||
return fileUploadUrl;
|
||||
}
|
||||
|
||||
public MetadataUploadRequest setFileUploadUrl(String fileUploadUrl) {
|
||||
this.fileUploadUrl = fileUploadUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getSha1() {
|
||||
return sha1;
|
||||
}
|
||||
|
||||
public MetadataUploadRequest setSha1(String sha1) {
|
||||
this.sha1 = sha1;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getSha256() {
|
||||
return sha256;
|
||||
}
|
||||
|
||||
public MetadataUploadRequest setSha256(String sha256) {
|
||||
this.sha256 = sha256;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getMd5() {
|
||||
return md5;
|
||||
}
|
||||
|
||||
public MetadataUploadRequest setMd5(String md5) {
|
||||
this.md5 = md5;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public MetadataUploadRequest setFilePath(String filePath) {
|
||||
this.filePath = filePath;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Long getFileSizeBytes() {
|
||||
return fileSizeBytes;
|
||||
}
|
||||
|
||||
public MetadataUploadRequest setFileSizeBytes(Long fileSizeBytes) {
|
||||
this.fileSizeBytes = fileSizeBytes;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Long getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
|
||||
public MetadataUploadRequest setCreatedDate(Long createdDate) {
|
||||
this.createdDate = createdDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
# 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.disclaimer.text=<html>The Cyber Triage Malware Scanner module uses 40+ malware scanning engines to identify if Windows executables are malicious. It requires a paid subscription 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
|
||||
LicenseDisclaimerPanel.trialLabel.text=You can try a free 7-day trial from
|
||||
|
@ -3,7 +3,7 @@
|
||||
# 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.disclaimer.text=<html>The Cyber Triage Malware Scanner module uses 40+ malware scanning engines to identify if Windows executables are malicious. It requires a paid subscription 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
|
||||
LicenseDisclaimerPanel.trialLabel.text=You can try a free 7-day trial from
|
||||
|
@ -6,17 +6,18 @@
|
||||
<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}")"/>
|
||||
<Color PropertyName="color" blue="0" green="0" red="ff" type="rgb"/>
|
||||
</TitledBorder>
|
||||
</Border>
|
||||
</Property>
|
||||
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[2147483647, 90]"/>
|
||||
<Dimension value="[2147483647, 108]"/>
|
||||
</Property>
|
||||
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[562, 90]"/>
|
||||
<Dimension value="[562, 108]"/>
|
||||
</Property>
|
||||
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
|
||||
<Dimension value="[400, 90]"/>
|
||||
<Dimension value="[400, 108]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
@ -29,7 +30,7 @@
|
||||
<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"/>
|
||||
<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,108,0,0,2,50"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
@ -47,45 +48,7 @@
|
||||
</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"/>
|
||||
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" 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>
|
||||
@ -96,7 +59,7 @@
|
||||
</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"/>
|
||||
<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="0.0" weightY="1.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
@ -113,5 +76,111 @@
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="trialPanel">
|
||||
<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="5" insetsBottom="5" insetsRight="5" anchor="10" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="javax.swing.JLabel" name="trialLabel">
|
||||
<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.trialLabel.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="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="trialLink">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="getHtmlLink(TRIAL_URL)" type="code"/>
|
||||
</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="trialLinkMouseClicked"/>
|
||||
</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="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="purchasePanel">
|
||||
<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="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="10" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<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="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="purchaseLink">
|
||||
<Properties>
|
||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
|
||||
<Connection code="getHtmlLink(PURCHASE_URL)" type="code"/>
|
||||
</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="purchaseLinkMouseClicked"/>
|
||||
</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="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
|
@ -32,7 +32,12 @@ 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";
|
||||
private static final String TRIAL_URL = "https://cybertriage.com/autopsy-trial";
|
||||
private static final String PURCHASE_URL = "https://cybertriage.com/autopsy-checkout";
|
||||
|
||||
private static String getHtmlLink(String url) {
|
||||
return "<html><span style=\"color: blue; text-decoration: underline\">" + url + "</span></html>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new form LicenseDisclaimerPanel
|
||||
@ -52,14 +57,18 @@ public class LicenseDisclaimerPanel extends javax.swing.JPanel {
|
||||
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();
|
||||
javax.swing.JPanel trialPanel = new javax.swing.JPanel();
|
||||
javax.swing.JLabel trialLabel = new javax.swing.JLabel();
|
||||
javax.swing.JLabel trialLink = new javax.swing.JLabel();
|
||||
javax.swing.JPanel purchasePanel = new javax.swing.JPanel();
|
||||
javax.swing.JLabel purchaseFromLabel = new javax.swing.JLabel();
|
||||
javax.swing.JLabel purchaseLink = new javax.swing.JLabel();
|
||||
|
||||
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));
|
||||
setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(LicenseDisclaimerPanel.class, "LicenseDisclaimerPanel.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Segoe UI", 0, 12), new java.awt.Color(255, 0, 0))); // NOI18N
|
||||
setMaximumSize(new java.awt.Dimension(2147483647, 108));
|
||||
setMinimumSize(new java.awt.Dimension(562, 108));
|
||||
setPreferredSize(new java.awt.Dimension(400, 108));
|
||||
setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(disclaimer, org.openide.util.NbBundle.getMessage(LicenseDisclaimerPanel.class, "LicenseDisclaimerPanel.disclaimer.text")); // NOI18N
|
||||
@ -67,34 +76,12 @@ public class LicenseDisclaimerPanel extends javax.swing.JPanel {
|
||||
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(
|
||||
@ -108,24 +95,94 @@ public class LicenseDisclaimerPanel extends javax.swing.JPanel {
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 2;
|
||||
gridBagConstraints.gridy = 3;
|
||||
gridBagConstraints.weighty = 1.0;
|
||||
add(spacer, gridBagConstraints);
|
||||
|
||||
trialPanel.setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(trialLabel, org.openide.util.NbBundle.getMessage(LicenseDisclaimerPanel.class, "LicenseDisclaimerPanel.trialLabel.text")); // NOI18N
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 0;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
trialPanel.add(trialLabel, gridBagConstraints);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(trialLink, getHtmlLink(TRIAL_URL));
|
||||
trialLink.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
|
||||
trialLink.addMouseListener(new java.awt.event.MouseAdapter() {
|
||||
public void mouseClicked(java.awt.event.MouseEvent evt) {
|
||||
trialLinkMouseClicked(evt);
|
||||
}
|
||||
});
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 1;
|
||||
gridBagConstraints.gridy = 0;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);
|
||||
trialPanel.add(trialLink, gridBagConstraints);
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 1;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
|
||||
add(trialPanel, gridBagConstraints);
|
||||
|
||||
purchasePanel.setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(purchaseFromLabel, org.openide.util.NbBundle.getMessage(LicenseDisclaimerPanel.class, "LicenseDisclaimerPanel.purchaseFromLabel.text")); // NOI18N
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 0;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
purchasePanel.add(purchaseFromLabel, gridBagConstraints);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(purchaseLink, getHtmlLink(PURCHASE_URL));
|
||||
purchaseLink.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
|
||||
purchaseLink.addMouseListener(new java.awt.event.MouseAdapter() {
|
||||
public void mouseClicked(java.awt.event.MouseEvent evt) {
|
||||
purchaseLinkMouseClicked(evt);
|
||||
}
|
||||
});
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 1;
|
||||
gridBagConstraints.gridy = 0;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);
|
||||
purchasePanel.add(purchaseLink, gridBagConstraints);
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 2;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
|
||||
add(purchasePanel, gridBagConstraints);
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void linkMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_linkMouseClicked
|
||||
private void purchaseLinkMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_purchaseLinkMouseClicked
|
||||
gotoLink(PURCHASE_URL);
|
||||
}//GEN-LAST:event_purchaseLinkMouseClicked
|
||||
|
||||
private void trialLinkMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_trialLinkMouseClicked
|
||||
gotoLink(TRIAL_URL);
|
||||
}//GEN-LAST:event_trialLinkMouseClicked
|
||||
|
||||
private void gotoLink(String url) {
|
||||
if (Desktop.isDesktopSupported()) {
|
||||
try {
|
||||
Desktop.getDesktop().browse(new URI(CHECKOUT_PAGE_URL));
|
||||
Desktop.getDesktop().browse(new URI(url));
|
||||
} catch (IOException | URISyntaxException e) {
|
||||
LOGGER.log(Level.SEVERE, "Error opening link to: " + CHECKOUT_PAGE_URL, e);
|
||||
LOGGER.log(Level.SEVERE, "Error opening link to: " + 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
|
||||
}
|
||||
|
@ -24,3 +24,5 @@ CTMalwareScannerOptionsPanel.licenseInfoUserLabel.text=
|
||||
EULADialog.cancelButton.text=Cancel
|
||||
EULADialog.acceptButton.text=Accept
|
||||
EULADialog.title=Cyber Triage End User License Agreement
|
||||
CTMalwareScannerOptionsPanel.fileUploadCheckbox.text=Upload file if hash lookup produces no results
|
||||
CTMalwareScannerOptionsPanel.fileUploadPanel.border.title=File Upload
|
||||
|
@ -22,6 +22,10 @@ CTMalwareScannerOptionsPanel.licenseInfoIdLabel.text=
|
||||
CTMalwareScannerOptionsPanel.licenseInfoExpiresLabel.text=
|
||||
CTMalwareScannerOptionsPanel.fileUploadsRemainingLabel.text=
|
||||
CTMalwareScannerOptionsPanel.licenseInfoUserLabel.text=
|
||||
CTMalwareScannerOptionsPanel_getResetSuffix_daily=/day
|
||||
CTMalwareScannerOptionsPanel_getResetSuffix_hourly=/hour
|
||||
CTMalwareScannerOptionsPanel_getResetSuffix_monthly=/month
|
||||
CTMalwareScannerOptionsPanel_getResetSuffix_weekly=/week
|
||||
CTMalwareScannerOptionsPanel_licenseAddDialog_desc=License Number:
|
||||
CTMalwareScannerOptionsPanel_licenseAddDialog_title=Add a License...
|
||||
CTMalwareScannerOptionsPanel_licenseAddDialogEnteredErr_desc=The license number has already been entered
|
||||
@ -45,9 +49,11 @@ CTMalwareScannerOptionsPanel_malwareScans_fileUploadsRemaining=File uploads rema
|
||||
# {0} - hashLookupsRemaining
|
||||
CTMalwareScannerOptionsPanel_malwareScans_hashLookupsRemaining=Hash lookups remaining: {0}
|
||||
# {0} - maxDailyFileLookups
|
||||
CTMalwareScannerOptionsPanel_malwareScans_maxDailyFileLookups=Max file uploads: {0}/day
|
||||
# {1} - resetSuffix
|
||||
CTMalwareScannerOptionsPanel_malwareScans_maxDailyFileLookups=Max file uploads: {0}{1}
|
||||
# {0} - maxDailyLookups
|
||||
CTMalwareScannerOptionsPanel_malwareScans_maxDailyHashLookups=Max Hash lookups: {0}/day
|
||||
# {1} - resetSuffix
|
||||
CTMalwareScannerOptionsPanel_malwareScans_maxDailyHashLookups=Max Hash lookups: {0}{1}
|
||||
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
|
||||
@ -56,3 +62,5 @@ CTOPtionsPanel_loadMalwareScansInfo_loading=Loading...
|
||||
EULADialog.cancelButton.text=Cancel
|
||||
EULADialog.acceptButton.text=Accept
|
||||
EULADialog.title=Cyber Triage End User License Agreement
|
||||
CTMalwareScannerOptionsPanel.fileUploadCheckbox.text=Upload file if hash lookup produces no results
|
||||
CTMalwareScannerOptionsPanel.fileUploadPanel.border.title=File Upload
|
||||
|
@ -27,7 +27,7 @@ import org.openide.util.NbBundle.Messages;
|
||||
/**
|
||||
* License dialog
|
||||
*/
|
||||
public class CTLicenseDialog extends javax.swing.JDialog {
|
||||
class CTLicenseDialog extends javax.swing.JDialog {
|
||||
|
||||
private static final Pattern LICENSE_PATTERN = Pattern.compile("^\\s*[a-zA-Z0-9\\-]+?\\s*$");
|
||||
private String licenseString = null;
|
||||
|
@ -26,7 +26,6 @@ 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;
|
||||
@ -40,6 +39,7 @@ public class CTLicensePersistence {
|
||||
|
||||
private static final String CT_SETTINGS_DIR = "CyberTriage";
|
||||
private static final String CT_LICENSE_FILENAME = "CyberTriageLicense.json";
|
||||
private static final String MALWARE_INGEST_SETTINGS_FILENAME = "MalwareIngestSettings.json";
|
||||
|
||||
private static final Logger logger = Logger.getLogger(CTLicensePersistence.class.getName());
|
||||
|
||||
@ -91,7 +91,44 @@ public class CTLicensePersistence {
|
||||
});
|
||||
}
|
||||
|
||||
public synchronized boolean saveMalwareSettings(MalwareIngestSettings malwareIngestSettings) {
|
||||
if (malwareIngestSettings != null) {
|
||||
File settingsFile = getMalwareIngestFile();
|
||||
try {
|
||||
settingsFile.getParentFile().mkdirs();
|
||||
objectMapper.writeValue(settingsFile, malwareIngestSettings);
|
||||
return true;
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, "There was an error writing malware ingest settings to file: " + settingsFile.getAbsolutePath(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public synchronized MalwareIngestSettings loadMalwareIngestSettings() {
|
||||
MalwareIngestSettings settings = null;
|
||||
File settingsFile = getMalwareIngestFile();
|
||||
if (settingsFile.exists() && settingsFile.isFile()) {
|
||||
try {
|
||||
settings = objectMapper.readValue(settingsFile, MalwareIngestSettings.class);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, "There was an error reading malware ingest settings from file: " + settingsFile.getAbsolutePath(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (settings == null) {
|
||||
settings = new MalwareIngestSettings();
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
private File getCTLicenseFile() {
|
||||
return Paths.get(PlatformUtil.getModuleConfigDirectory(), CT_SETTINGS_DIR, CT_LICENSE_FILENAME).toFile();
|
||||
}
|
||||
|
||||
private File getMalwareIngestFile() {
|
||||
return Paths.get(PlatformUtil.getModuleConfigDirectory(), CT_SETTINGS_DIR, MALWARE_INGEST_SETTINGS_FILENAME).toFile();
|
||||
}
|
||||
}
|
||||
|
@ -11,11 +11,54 @@
|
||||
<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"/>
|
||||
<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,-69,0,0,1,-29"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JPanel" name="fileUploadPanel">
|
||||
<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="File Upload">
|
||||
<ResourceString PropertyName="titleX" bundle="com/basistech/df/cybertriage/autopsy/ctoptions/ctcloud/Bundle.properties" key="CTMalwareScannerOptionsPanel.fileUploadPanel.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="0" 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.JCheckBox" name="fileUploadCheckbox">
|
||||
<Properties>
|
||||
<Property name="selected" type="boolean" value="true"/>
|
||||
<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.fileUploadCheckbox.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="[32767, 20]"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="fileUploadCheckboxActionPerformed"/>
|
||||
</Events>
|
||||
<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="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="1.0"/>
|
||||
</Constraint>
|
||||
</Constraints>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
<Container class="javax.swing.JPanel" name="licenseInfoPanel">
|
||||
<Properties>
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
|
@ -24,6 +24,7 @@ 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.LicenseLimitType;
|
||||
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;
|
||||
@ -33,6 +34,7 @@ import java.io.IOException;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@ -112,6 +114,7 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
|
||||
@Override
|
||||
public synchronized void saveSettings() {
|
||||
ctPersistence.saveLicenseResponse(getLicenseInfo());
|
||||
ctPersistence.saveMalwareSettings(getIngestSettings());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -128,12 +131,27 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
|
||||
if (licenseInfo != null) {
|
||||
loadMalwareScansInfo(licenseInfo);
|
||||
}
|
||||
|
||||
MalwareIngestSettings ingestSettings = ctPersistence.loadMalwareIngestSettings();
|
||||
setIngestSettings(ingestSettings);
|
||||
}
|
||||
|
||||
private synchronized LicenseResponse getLicenseInfo() {
|
||||
return this.licenseInfo == null ? null : this.licenseInfo.getLicenseResponse();
|
||||
}
|
||||
|
||||
private MalwareIngestSettings getIngestSettings() {
|
||||
return new MalwareIngestSettings()
|
||||
.setUploadFiles(this.fileUploadCheckbox.isSelected());
|
||||
}
|
||||
|
||||
private void setIngestSettings(MalwareIngestSettings ingestSettings) {
|
||||
if (ingestSettings == null) {
|
||||
ingestSettings = new MalwareIngestSettings();
|
||||
}
|
||||
this.fileUploadCheckbox.setSelected(ingestSettings.isUploadFiles());
|
||||
}
|
||||
|
||||
private synchronized void setLicenseDisplay(LicenseInfo licenseInfo, String licenseMessage) {
|
||||
this.licenseInfo = licenseInfo;
|
||||
this.licenseInfoMessage = licenseMessage;
|
||||
@ -202,6 +220,8 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
|
||||
private void initComponents() {
|
||||
java.awt.GridBagConstraints gridBagConstraints;
|
||||
|
||||
javax.swing.JPanel fileUploadPanel = new javax.swing.JPanel();
|
||||
fileUploadCheckbox = new javax.swing.JCheckBox();
|
||||
javax.swing.JPanel licenseInfoPanel = new javax.swing.JPanel();
|
||||
licenseInfoMessageLabel = new javax.swing.JLabel();
|
||||
licenseInfoUserLabel = new javax.swing.JLabel();
|
||||
@ -218,6 +238,35 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
|
||||
|
||||
setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
fileUploadPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.fileUploadPanel.border.title"))); // NOI18N
|
||||
fileUploadPanel.setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
fileUploadCheckbox.setSelected(true);
|
||||
org.openide.awt.Mnemonics.setLocalizedText(fileUploadCheckbox, org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.fileUploadCheckbox.text")); // NOI18N
|
||||
fileUploadCheckbox.setMaximumSize(new java.awt.Dimension(32767, 20));
|
||||
fileUploadCheckbox.addActionListener(new java.awt.event.ActionListener() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
fileUploadCheckboxActionPerformed(evt);
|
||||
}
|
||||
});
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 0;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
gridBagConstraints.weighty = 1.0;
|
||||
gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
|
||||
fileUploadPanel.add(fileUploadCheckbox, gridBagConstraints);
|
||||
|
||||
gridBagConstraints = new java.awt.GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 0;
|
||||
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
|
||||
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
|
||||
gridBagConstraints.weightx = 1.0;
|
||||
add(fileUploadPanel, gridBagConstraints);
|
||||
|
||||
licenseInfoPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CTMalwareScannerOptionsPanel.class, "CTMalwareScannerOptionsPanel.licenseInfoPanel.border.title"))); // NOI18N
|
||||
licenseInfoPanel.setLayout(new java.awt.GridBagLayout());
|
||||
|
||||
@ -378,6 +427,10 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
|
||||
}
|
||||
}//GEN-LAST:event_licenseInfoAddButtonActionPerformed
|
||||
|
||||
private void fileUploadCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileUploadCheckboxActionPerformed
|
||||
this.firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||
}//GEN-LAST:event_fileUploadCheckboxActionPerformed
|
||||
|
||||
@NbBundle.Messages({
|
||||
"# {0} - userName",
|
||||
"# {1} - email",
|
||||
@ -387,9 +440,11 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
|
||||
"# {0} - idNumber",
|
||||
"CTMalwareScannerOptionsPanel_licenseInfo_id=ID: {0}",
|
||||
"# {0} - maxDailyLookups",
|
||||
"CTMalwareScannerOptionsPanel_malwareScans_maxDailyHashLookups=Max Hash lookups: {0}/day",
|
||||
"# {1} - resetSuffix",
|
||||
"CTMalwareScannerOptionsPanel_malwareScans_maxDailyHashLookups=Max Hash lookups: {0}{1}",
|
||||
"# {0} - maxDailyFileLookups",
|
||||
"CTMalwareScannerOptionsPanel_malwareScans_maxDailyFileLookups=Max file uploads: {0}/day",
|
||||
"# {1} - resetSuffix",
|
||||
"CTMalwareScannerOptionsPanel_malwareScans_maxDailyFileLookups=Max file uploads: {0}{1}",
|
||||
"# {0} - countersResetDate",
|
||||
"CTMalwareScannerOptionsPanel_malwareScans_countersReset=Counters reset: {0}",
|
||||
"# {0} - hashLookupsRemaining",
|
||||
@ -425,7 +480,7 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
|
||||
this.malwareScansMessageLabel.setVisible(StringUtils.isNotBlank(this.authTokenMessage));
|
||||
this.malwareScansMessageLabel.setText(this.authTokenMessage);
|
||||
|
||||
if (authTokenResponse == null) {
|
||||
if (authTokenResponse == null || this.licenseInfo == null) {
|
||||
this.maxHashLookupsLabel.setVisible(false);
|
||||
this.maxFileUploadsLabel.setVisible(false);
|
||||
this.countersResetLabel.setVisible(false);
|
||||
@ -433,15 +488,62 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
|
||||
this.fileUploadsRemainingLabel.setVisible(false);
|
||||
} else {
|
||||
this.maxHashLookupsLabel.setVisible(true);
|
||||
this.maxHashLookupsLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_maxDailyHashLookups(this.authTokenResponse.getHashLookupLimit()));
|
||||
this.maxHashLookupsLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_maxDailyHashLookups(
|
||||
this.authTokenResponse.getHashLookupLimit(),
|
||||
getResetSuffix(this.licenseInfo.getDecryptedLicense().getLimitType())));
|
||||
|
||||
this.maxFileUploadsLabel.setVisible(true);
|
||||
this.maxFileUploadsLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_maxDailyFileLookups(this.authTokenResponse.getFileUploadLimit()));
|
||||
this.maxFileUploadsLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_maxDailyFileLookups(
|
||||
this.authTokenResponse.getFileUploadLimit(),
|
||||
getResetSuffix(this.licenseInfo.getDecryptedLicense().getLimitType())));
|
||||
|
||||
this.countersResetLabel.setVisible(true);
|
||||
this.countersResetLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_countersReset(this.authTokenResponse.getResetDate() == null ? "" : MALWARE_SCANS_RESET_FORMAT.format(this.authTokenResponse.getResetDate())));
|
||||
this.countersResetLabel.setText(getCountersResetText(this.licenseInfo.getDecryptedLicense().getLimitType(), this.authTokenResponse));
|
||||
|
||||
this.hashLookupsRemainingLabel.setVisible(true);
|
||||
this.hashLookupsRemainingLabel.setText(Bundle.CTMalwareScannerOptionsPanel_malwareScans_hashLookupsRemaining(remaining(this.authTokenResponse.getHashLookupLimit(), this.authTokenResponse.getHashLookupCount())));
|
||||
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())));
|
||||
this.fileUploadsRemainingLabel.setText(
|
||||
Bundle.CTMalwareScannerOptionsPanel_malwareScans_fileUploadsRemaining(
|
||||
remaining(this.authTokenResponse.getFileUploadLimit(), this.authTokenResponse.getFileUploadCount())));
|
||||
}
|
||||
}
|
||||
|
||||
private static String getCountersResetText(LicenseLimitType limitType, AuthTokenResponse authTokenResponse) {
|
||||
if (limitType == null || limitType == LicenseLimitType.NO_RESET) {
|
||||
return "";
|
||||
} else {
|
||||
return Bundle.CTMalwareScannerOptionsPanel_malwareScans_countersReset(
|
||||
MALWARE_SCANS_RESET_FORMAT.format(authTokenResponse.getResetDate()));
|
||||
}
|
||||
}
|
||||
|
||||
@Messages({
|
||||
"CTMalwareScannerOptionsPanel_getResetSuffix_hourly=/hour",
|
||||
"CTMalwareScannerOptionsPanel_getResetSuffix_daily=/day",
|
||||
"CTMalwareScannerOptionsPanel_getResetSuffix_weekly=/week",
|
||||
"CTMalwareScannerOptionsPanel_getResetSuffix_monthly=/month"
|
||||
})
|
||||
private String getResetSuffix(LicenseLimitType limitType) {
|
||||
if (limitType == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
switch (limitType) {
|
||||
case HOURLY:
|
||||
return Bundle.CTMalwareScannerOptionsPanel_getResetSuffix_hourly();
|
||||
case DAILY:
|
||||
return Bundle.CTMalwareScannerOptionsPanel_getResetSuffix_daily();
|
||||
case WEEKLY:
|
||||
return Bundle.CTMalwareScannerOptionsPanel_getResetSuffix_weekly();
|
||||
case MONTHLY:
|
||||
return Bundle.CTMalwareScannerOptionsPanel_getResetSuffix_monthly();
|
||||
case NO_RESET:
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@ -501,7 +603,7 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
|
||||
try {
|
||||
LicenseResponse licenseResponse = get();
|
||||
SwingUtilities.invokeLater(() -> acceptEula(licenseResponse));
|
||||
} catch (InterruptedException ex) {
|
||||
} catch (InterruptedException | CancellationException ex) {
|
||||
// ignore cancellation; just load current license
|
||||
setLicenseDisplay(licenseInfo, null);
|
||||
loadMalwareScansInfo(licenseInfo);
|
||||
@ -557,7 +659,7 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
|
||||
AuthTokenResponse authTokenResponse = null;
|
||||
try {
|
||||
authTokenResponse = get();
|
||||
} catch (InterruptedException ex) {
|
||||
} catch (InterruptedException | CancellationException ex) {
|
||||
// ignore cancellation
|
||||
} catch (ExecutionException ex) {
|
||||
if (ex.getCause() != null && ex.getCause() instanceof CTCloudException cloudEx) {
|
||||
@ -589,6 +691,7 @@ public class CTMalwareScannerOptionsPanel extends CTOptionsSubPanel {
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JLabel countersResetLabel;
|
||||
private javax.swing.JCheckBox fileUploadCheckbox;
|
||||
private javax.swing.JLabel fileUploadsRemainingLabel;
|
||||
private javax.swing.JLabel hashLookupsRemainingLabel;
|
||||
private javax.swing.JButton licenseInfoAddButton;
|
||||
|
@ -36,7 +36,7 @@ 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 {
|
||||
class EULADialog extends javax.swing.JDialog {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(EULADialog.class.getName());
|
||||
private static final String EULA_RESOURCE = "EULA.htm";
|
||||
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Settings for the malware ingest module.
|
||||
*/
|
||||
public class MalwareIngestSettings {
|
||||
|
||||
private boolean uploadFiles = true;
|
||||
|
||||
public boolean isUploadFiles() {
|
||||
return uploadFiles;
|
||||
}
|
||||
|
||||
public MalwareIngestSettings setUploadFiles(boolean uploadFiles) {
|
||||
this.uploadFiles = uploadFiles;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -21,14 +21,10 @@ 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;
|
||||
|
||||
/**
|
||||
@ -36,7 +32,7 @@ import java.util.function.Consumer;
|
||||
* blocks (and subsequently add and flush operations) until previous batch
|
||||
* finishes.
|
||||
*/
|
||||
public class BatchProcessor<T> {
|
||||
class BatchProcessor<T> {
|
||||
|
||||
private ExecutorService processingExecutorService = Executors.newSingleThreadExecutor();
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
MalwareScanIngestModule_longPollForNotFound_fileLookupPolling_desc=Waiting for all uploaded files to complete scanning.
|
||||
MalwareScanIngestModule_longPollForNotFound_fileLookupPolling_title=Waiting for File Upload Results
|
||||
MalwareScanIngestModule_longPollForNotFound_timeout_desc=There was a timeout while waiting for file uploads to be processed. Please try again later.
|
||||
MalwareScanIngestModule_longPollForNotFound_timeout_title=File Upload Results Timeout
|
||||
MalwareScanIngestModule_malwareTypeDisplayName=Malware
|
||||
# {0} - errorResponse
|
||||
MalwareScanIngestModule_SharedProcessing_authTokenResponseError_desc=Received error: ''{0}'' when fetching the API authentication token for the license
|
||||
@ -6,6 +10,8 @@ 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_exhaustedResultsHashLookups_desc=Not all files were processed because hash lookup limits were exceeded. Please try again when your limits reset.
|
||||
MalwareScanIngestModule_SharedProcessing_exhaustedResultsHashLookups_title=Lookup Limits Exceeded
|
||||
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
|
||||
@ -16,12 +22,22 @@ MalwareScanIngestModule_SharedProcessing_repServicenResponseError_title=Lookup A
|
||||
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_lowLookupsLimitWarning_desc=This license only has {0} lookups remaining.
|
||||
MalwareScanIngestModule_ShareProcessing_lowLookupsLimitWarning_title=Hash Lookups Low
|
||||
# {0} - remainingUploads
|
||||
MalwareScanIngestModule_ShareProcessing_lowUploadsLimitWarning_desc=This license only has {0} file uploads remaining.
|
||||
MalwareScanIngestModule_ShareProcessing_lowUploadsLimitWarning_title=File Uploads Limit 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
|
||||
MalwareScanIngestModule_ShareProcessing_noLookupsRemaining_desc=There are no more remaining hash lookups for this license at this time. Malware scanning will be disabled.
|
||||
MalwareScanIngestModule_ShareProcessing_noLookupsRemaining_title=No remaining lookups
|
||||
MalwareScanIngestModule_ShareProcessing_noUploadsRemaining_desc=There are no more remaining file uploads for this license at this time. File uploading will be disabled.
|
||||
MalwareScanIngestModule_ShareProcessing_noUploadsRemaining_title=No remaining file uploads
|
||||
MalwareScanIngestModule_uploadFile_noRemainingFileUploads_desc=There are no more file uploads on this license at this time. File uploads will be disabled for remaining uploads.
|
||||
MalwareScanIngestModule_uploadFile_noRemainingFileUploads_title=No Remaining File Uploads
|
||||
# {0} - objectId
|
||||
MalwareScanIngestModule_uploadFile_notUploadable_desc=A file did not meet requirements for upload (object id: {0}).
|
||||
MalwareScanIngestModule_uploadFile_notUploadable_title=Not Able to Upload
|
||||
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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* 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.google.common.net.InetAddresses;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Utility class to anonymize paths.
|
||||
*/
|
||||
class PathNormalizer {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(PathNormalizer.class.getName());
|
||||
|
||||
private static final String ANONYMIZED_USERNAME = "<user>";
|
||||
private static final String ANONYMIZED_IP = "<private_ip>";
|
||||
private static final String ANONYMIZED_HOSTNAME = "<hostname>";
|
||||
private static final String FORWARD_SLASH = "/";
|
||||
private static final String BACK_SLASH = "\\";
|
||||
|
||||
private static final Pattern USER_PATH_FORWARD_SLASH_REGEX = Pattern.compile("(?<!all )([/]{0,1}\\Qusers\\E/)(?!(public|Default|defaultAccount|All Users))([^/]+)(/){0,1}", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern USER_PATH_BACK_SLASH_REGEX = Pattern.compile("(?<!all )([\\\\]{0,1}\\Qusers\\E\\\\)(?!(public|Default|defaultAccount|All Users))([^\\\\]+)([\\\\]){0,1}", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private static final Pattern USER_PATH_FORWARD_SLASH_REGEX_XP = Pattern.compile("([/]{0,1}\\Qdocuments and settings\\E/)(?!(Default User|All Users))([^/]+)(/){0,1}", Pattern.CASE_INSENSITIVE);
|
||||
private static final Pattern USER_PATH_BACK_SLASH_REGEX_XP = Pattern.compile("([\\\\]{0,1}\\Qdocuments and settings\\E\\\\)(?!(Default User|All Users))([^\\\\]+)(\\\\){0,1}", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
private static final Pattern UNC_PATH_FORWARD_SLASH_PATTERN = Pattern.compile("(//)([^/]+)(/){0,1}");
|
||||
private static final Pattern UNC_PATH_BACK_SLASH_PATTERN = Pattern.compile("(\\\\\\\\)([^\\\\]+)(\\\\){0,1}");
|
||||
|
||||
private static final String USERNAME_REGEX_REPLACEMENT = "$1" + ANONYMIZED_USERNAME + "$4";
|
||||
|
||||
private final SleuthkitCase skCase;
|
||||
|
||||
PathNormalizer(SleuthkitCase skCase) {
|
||||
this.skCase = skCase;
|
||||
}
|
||||
|
||||
protected List<String> getUsernames() {
|
||||
try {
|
||||
return this.skCase.getOsAccountManager().getOsAccounts().stream()
|
||||
.filter(acct -> acct != null)
|
||||
.map(acct -> acct.getLoginName().orElse(null))
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.collect(Collectors.toList());
|
||||
} catch (TskCoreException ex) {
|
||||
LOGGER.log(Level.WARNING, "There was an error getting current os accounts", ex);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
public String normalizePath(String inputString) {
|
||||
if (StringUtils.isBlank(inputString)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String anonymousString = anonymizeUserFromPathsWithForwardSlashes(inputString);
|
||||
anonymousString = anonymizeUserFromPathsWithBackSlashes(anonymousString);
|
||||
anonymousString = anonymizeServerFromUNCPath(anonymousString);
|
||||
|
||||
return anonymousString;
|
||||
}
|
||||
|
||||
private String anonymizeUserFromPathsWithForwardSlashes(String stringWithUsername) {
|
||||
String anonymousString = stringWithUsername;
|
||||
anonymousString = regexReplace(anonymousString, USER_PATH_FORWARD_SLASH_REGEX_XP, USERNAME_REGEX_REPLACEMENT);
|
||||
anonymousString = regexReplace(anonymousString, USER_PATH_FORWARD_SLASH_REGEX, USERNAME_REGEX_REPLACEMENT);
|
||||
anonymousString = replaceFolder(anonymousString, getUsernames(), ANONYMIZED_USERNAME, FORWARD_SLASH);
|
||||
return anonymousString;
|
||||
}
|
||||
|
||||
// Most paths in CyberTriage are normalized with forward slashes
|
||||
// but there can still be strings containing paths that are not normalized such paths contained in arguments or event log payloads
|
||||
private String anonymizeUserFromPathsWithBackSlashes(String stringWithUsername) {
|
||||
String anonymousString = stringWithUsername;
|
||||
anonymousString = regexReplace(anonymousString, USER_PATH_BACK_SLASH_REGEX_XP, USERNAME_REGEX_REPLACEMENT);
|
||||
anonymousString = regexReplace(anonymousString, USER_PATH_BACK_SLASH_REGEX, USERNAME_REGEX_REPLACEMENT);
|
||||
anonymousString = replaceFolder(anonymousString, getUsernames(), ANONYMIZED_USERNAME, BACK_SLASH);
|
||||
|
||||
return anonymousString;
|
||||
}
|
||||
|
||||
private String anonymizeServerFromUNCPath(String inputString) {
|
||||
|
||||
Set<String> serverNames = new HashSet<>();
|
||||
String anonymousString = inputString.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
Matcher forwardSlashMatcher = UNC_PATH_FORWARD_SLASH_PATTERN.matcher(anonymousString);
|
||||
while (forwardSlashMatcher.find()) {
|
||||
String serverName = forwardSlashMatcher.group(2);
|
||||
serverNames.add(serverName);
|
||||
}
|
||||
|
||||
Matcher backSlashMatcher = UNC_PATH_BACK_SLASH_PATTERN.matcher(anonymousString);
|
||||
while (backSlashMatcher.find()) {
|
||||
String serverName = backSlashMatcher.group(2);
|
||||
serverNames.add(serverName);
|
||||
}
|
||||
|
||||
for (String serverName : serverNames) {
|
||||
|
||||
if (StringUtils.isBlank(serverName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (InetAddresses.isInetAddress(serverName) && isLocalIP(serverName)) {
|
||||
anonymousString = replaceFolder(anonymousString, Collections.singletonList(serverName), ANONYMIZED_IP);
|
||||
} else {
|
||||
anonymousString = replaceFolder(anonymousString, Collections.singletonList(serverName), ANONYMIZED_HOSTNAME);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return anonymousString;
|
||||
}
|
||||
|
||||
private static String regexReplace(String orig, Pattern pattern, String regexReplacement) {
|
||||
Matcher matcher = pattern.matcher(orig);
|
||||
return matcher.replaceAll(regexReplacement);
|
||||
}
|
||||
|
||||
private static String replaceFolder(String orig, List<String> valuesToReplace, String replacementValue) {
|
||||
String anonymized = orig;
|
||||
anonymized = replaceFolder(anonymized, valuesToReplace, replacementValue, FORWARD_SLASH);
|
||||
anonymized = replaceFolder(anonymized, valuesToReplace, replacementValue, BACK_SLASH);
|
||||
return anonymized;
|
||||
}
|
||||
|
||||
private static String replaceFolder(String orig, List<String> valuesToReplace, String replacementValue, String folderDelimiter) {
|
||||
if (orig == null || valuesToReplace == null) {
|
||||
return orig;
|
||||
}
|
||||
|
||||
String anonymousString = orig;
|
||||
|
||||
// ensure non-null
|
||||
folderDelimiter = StringUtils.defaultString(folderDelimiter);
|
||||
replacementValue = StringUtils.defaultString(replacementValue);
|
||||
|
||||
// replace
|
||||
for (String valueToReplace : valuesToReplace) {
|
||||
if (StringUtils.isNotEmpty(valueToReplace)) {
|
||||
anonymousString = StringUtils.replace(anonymousString,
|
||||
folderDelimiter + valueToReplace + folderDelimiter,
|
||||
folderDelimiter + replacementValue + folderDelimiter);
|
||||
}
|
||||
}
|
||||
|
||||
return anonymousString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if IP Address is Any Local / Site Local / Link Local / Loop
|
||||
* back local. Sample list "0.0.0.0", wildcard addres
|
||||
* "10.1.1.1","10.10.10.10", site local address "127.0.0.0","127.2.2.2",
|
||||
* loopback address "169.254.0.0","169.254.10.10", Link local address
|
||||
* "172.16.0.0","172.31.245.245", site local address
|
||||
*
|
||||
* @param ipAddress
|
||||
* @return
|
||||
*/
|
||||
public static boolean isLocalIP(String ipAddress) {
|
||||
try {
|
||||
InetAddress a = InetAddresses.forString(ipAddress);
|
||||
return a.isAnyLocalAddress() || a.isSiteLocalAddress()
|
||||
|| a.isLoopbackAddress() || a.isLinkLocalAddress();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
LOGGER.log(Level.WARNING, "Invalid IP string", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
BIN
docs/doxygen-user/images/ct_malware_license_agreement.png
Normal file
BIN
docs/doxygen-user/images/ct_malware_license_agreement.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 55 KiB |
BIN
docs/doxygen-user/images/ct_malware_scanner_options_panel.png
Normal file
BIN
docs/doxygen-user/images/ct_malware_scanner_options_panel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
docs/doxygen-user/images/ct_upload_file.png
Normal file
BIN
docs/doxygen-user/images/ct_upload_file.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
Loading…
x
Reference in New Issue
Block a user