19package com.basistech.df.cybertriage.autopsy.malwarescan;
21import com.basistech.df.cybertriage.autopsy.ctapi.CTApiDAO;
22import com.basistech.df.cybertriage.autopsy.ctapi.CTCloudException;
23import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthTokenResponse;
24import com.basistech.df.cybertriage.autopsy.ctapi.json.AuthenticatedRequestData;
25import com.basistech.df.cybertriage.autopsy.ctapi.json.CTCloudBean;
26import com.basistech.df.cybertriage.autopsy.ctapi.json.FileUploadRequest;
27import com.basistech.df.cybertriage.autopsy.ctapi.json.LicenseInfo;
28import com.basistech.df.cybertriage.autopsy.ctapi.json.MalwareResultBean.Status;
29import com.basistech.df.cybertriage.autopsy.ctapi.json.MetadataUploadRequest;
30import com.basistech.df.cybertriage.autopsy.ctoptions.ctcloud.CTLicensePersistence;
31import java.security.MessageDigest;
32import java.security.NoSuchAlgorithmException;
33import java.text.MessageFormat;
34import java.util.ArrayList;
35import java.util.Collections;
36import java.util.HashMap;
37import java.util.HexFormat;
40import java.util.Optional;
42import java.util.logging.Level;
43import java.util.stream.Collectors;
44import java.util.stream.Stream;
45import org.apache.commons.collections4.CollectionUtils;
46import org.apache.commons.collections4.MapUtils;
47import org.apache.commons.lang3.StringUtils;
48import org.apache.curator.shaded.com.google.common.collect.Lists;
49import org.openide.util.NbBundle.Messages;
50import org.sleuthkit.autopsy.casemodule.Case;
51import org.sleuthkit.autopsy.coreutils.Logger;
52import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
53import org.sleuthkit.autopsy.ingest.FileIngestModule;
54import org.sleuthkit.autopsy.ingest.IngestJobContext;
55import org.sleuthkit.autopsy.ingest.IngestModule;
56import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
57import org.sleuthkit.datamodel.AbstractFile;
58import org.sleuthkit.datamodel.AnalysisResult;
59import org.sleuthkit.datamodel.Blackboard;
60import org.sleuthkit.datamodel.BlackboardArtifact;
61import org.sleuthkit.datamodel.ReadContentInputStream;
62import org.sleuthkit.datamodel.HashUtility;
63import org.sleuthkit.datamodel.HashUtility.HashResult;
64import org.sleuthkit.datamodel.HashUtility.HashType;
65import org.sleuthkit.datamodel.Score;
66import org.sleuthkit.datamodel.SleuthkitCase;
67import org.sleuthkit.datamodel.TskCoreException;
68import org.sleuthkit.datamodel.TskData;
76 private boolean uploadFiles;
77 private boolean queryFiles;
79 MalwareScanIngestModule(MalwareScanIngestSettings settings) {
80 uploadFiles = settings.shouldUploadFiles();
81 queryFiles = settings.shouldQueryFiles();
86 sharedProcessing.startUp(context, uploadFiles);
91 return sharedProcessing.process(af);
96 sharedProcessing.shutDown();
125 "application/x-dosexec",
126 "application/vnd.microsoft.portable-executable",
127 "application/x-msdownload",
130 "application/dos-exe",
132 "application/x-winexe",
133 "application/msdos-windows",
134 "application/x-msdos-program"
135 ).collect(Collectors.toSet());
141 private final BatchProcessor<FileRecord>
batchProcessor =
new BatchProcessor<FileRecord>(
152 "MalwareScanIngestModule_malwareTypeDisplayName=Malware",
153 "MalwareScanIngestModule_ShareProcessing_noLicense_title=No Cyber Triage License",
154 "MalwareScanIngestModule_ShareProcessing_noLicense_desc=No Cyber Triage license could be loaded. Cyber Triage processing will be disabled.",
155 "MalwareScanIngestModule_ShareProcessing_noLookupsRemaining_title=No remaining lookups",
156 "MalwareScanIngestModule_ShareProcessing_noLookupsRemaining_desc=There are no more remaining hash lookups for this license at this time. Malware scanning will be disabled.",
157 "MalwareScanIngestModule_ShareProcessing_lowLookupsLimitWarning_title=Hash Lookups Low",
158 "# {0} - remainingLookups",
159 "MalwareScanIngestModule_ShareProcessing_lowLookupsLimitWarning_desc=This license only has {0} lookups remaining.",
160 "MalwareScanIngestModule_ShareProcessing_noUploadsRemaining_title=No remaining file uploads",
161 "MalwareScanIngestModule_ShareProcessing_noUploadsRemaining_desc=There are no more remaining file uploads for this license at this time. File uploading will be disabled.",
162 "MalwareScanIngestModule_ShareProcessing_lowUploadsLimitWarning_title=File Uploads Limit Low",
163 "# {0} - remainingUploads",
164 "MalwareScanIngestModule_ShareProcessing_lowUploadsLimitWarning_desc=This license only has {0} file uploads remaining.",
165 "MalwareScanIngestModule_ShareProcessing_startup_generalException_desc=An exception occurred on MalwareScanIngestModule startup. See the log for more information.",
166 "MalwareScanIngestModule_ShareProcessing_startup_invalidLicenseWarning_title=Invalid License",
167 "MalwareScanIngestModule_ShareProcessing_startup_invalidLicenseWarning_desc=The current Cyber Triage license is no longer valid. Please remove the license from the Cyber Triage options panel."})
176 }
catch (CTCloudException cloudEx) {
178 logger.log(Level.WARNING,
"An error occurred while starting the MalwareScanIngestModule.", cloudEx);
179 throw new IngestModuleException(cloudEx.getErrorDetails(), cloudEx);
180 }
catch (IllegalStateException stateEx) {
182 logger.log(Level.WARNING,
"An error occurred while starting the MalwareScanIngestModule.", stateEx);
183 throw new IngestModuleException(stateEx.getMessage(), stateEx);
184 }
catch (Exception ex) {
186 logger.log(Level.WARNING,
"An error occurred while starting the MalwareScanIngestModule.", ex);
187 throw new IngestModuleException(Bundle.MalwareScanIngestModule_ShareProcessing_startup_generalException_desc(), ex);
202 if (licenseInfoOpt.isEmpty() || licenseInfoOpt.get().getDecryptedLicense() ==
null) {
203 throw new IllegalStateException(Bundle.MalwareScanIngestModule_ShareProcessing_noLicense_desc());
211 if (lookupsRemaining <= 0) {
213 Bundle.MalwareScanIngestModule_ShareProcessing_noLookupsRemaining_title(),
214 Bundle.MalwareScanIngestModule_ShareProcessing_noLookupsRemaining_desc(),
217 return IngestJobState.DISABLED;
220 Bundle.MalwareScanIngestModule_ShareProcessing_lowLookupsLimitWarning_title(),
221 Bundle.MalwareScanIngestModule_ShareProcessing_lowLookupsLimitWarning_desc(lookupsRemaining),
228 if (uploadsRemaining <= 0) {
230 Bundle.MalwareScanIngestModule_ShareProcessing_noUploadsRemaining_title(),
231 Bundle.MalwareScanIngestModule_ShareProcessing_noUploadsRemaining_desc(),
236 Bundle.MalwareScanIngestModule_ShareProcessing_lowUploadsLimitWarning_title(),
237 Bundle.MalwareScanIngestModule_ShareProcessing_lowUploadsLimitWarning_desc(lookupsRemaining),
244 return new IngestJobState(
247 new PathNormalizer(tskCase),
249 licenseInfoOpt.get(),
250 BlackboardArtifact.Type.TSK_MALWARE,
264 limit = limit ==
null ? 0 : limit;
265 used = used ==
null ? 0 : used;
278 if (StringUtils.isNotBlank(af.getMd5Hash())) {
279 return af.getMd5Hash();
283 if (StringUtils.isNotBlank(af.getSha256Hash())) {
284 return af.getSha256Hash();
289 List<HashResult> hashResults = HashUtility.calculateHashes(af, Collections.singletonList(hashType));
290 if (CollectionUtils.isNotEmpty(hashResults)) {
291 for (HashResult hashResult : hashResults) {
292 if (hashResult.getType() == hashType) {
293 return hashResult.getValue();
297 }
catch (TskCoreException ex) {
299 MessageFormat.format(
"An error occurred while processing hash for file name: {0} and obj id: {1} and hash type {2}.",
335 private static String
getOrCalcSha1(AbstractFile af)
throws NoSuchAlgorithmException, ReadContentInputStream.ReadContentInputStreamException {
336 if (StringUtils.isNotBlank(af.getSha1Hash())) {
337 return af.getSha1Hash();
340 MessageDigest digest = MessageDigest.getInstance(
"SHA-1");
341 ReadContentInputStream afStream =
new ReadContentInputStream(af);
343 byte[] buffer =
new byte[8192];
345 n = afStream.read(buffer);
347 digest.update(buffer, 0, n);
350 byte[] hashBytes = digest.digest();
351 String hashString = HexFormat.of().formatHex(hashBytes);
365 "MalwareScanIngestModule_ShareProcessing_batchTimeout_title=Batch Processing Timeout",
366 "MalwareScanIngestModule_ShareProcessing_batchTimeout_desc=Batch processing timed out"
373 && af.getKnown() != TskData.FileKnown.KNOWN
375 && CollectionUtils.isEmpty(af.getAnalysisResults(
ingestJobState.getMalwareType()))) {
378 if (StringUtils.isNotBlank(md5)) {
382 return ProcessResult.OK;
383 }
catch (TskCoreException ex) {
385 Bundle.MalwareScanIngestModule_SharedProcessing_generalProcessingError_title(),
386 Bundle.MalwareScanIngestModule_SharedProcessing_generalProcessingError_desc(),
388 return IngestModule.ProcessResult.ERROR;
389 }
catch (InterruptedException ex) {
391 Bundle.MalwareScanIngestModule_ShareProcessing_batchTimeout_title(),
392 Bundle.MalwareScanIngestModule_ShareProcessing_batchTimeout_desc(),
394 return IngestModule.ProcessResult.ERROR;
406 "MalwareScanIngestModule_SharedProcessing_authTokenResponseError_title=Authentication API error",
407 "# {0} - errorResponse",
408 "MalwareScanIngestModule_SharedProcessing_authTokenResponseError_desc=Received error: ''{0}'' when fetching the API authentication token for the license",
409 "MalwareScanIngestModule_SharedProcessing_repServicenResponseError_title=Lookup API error",
410 "# {0} - errorResponse",
411 "MalwareScanIngestModule_SharedProcessing_repServicenResponseError_desc=Received error: ''{0}'' when fetching hash lookup results",
412 "MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_title=Hash Lookups Exhausted",
413 "MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_desc=The remaining hash lookups for this license have been exhausted",
414 "MalwareScanIngestModule_SharedProcessing_generalProcessingError_title=Hash Lookup Error",
415 "MalwareScanIngestModule_SharedProcessing_generalProcessingError_desc=An error occurred while processing hash lookup results",})
420 || fileRecords ==
null
421 || fileRecords.isEmpty()) {
426 Map<String, List<Long>> md5ToObjId =
new HashMap<>();
428 for (FileRecord fr : fileRecords) {
429 if (fr ==
null || StringUtils.isBlank(fr.getMd5hash()) || fr.getObjId() <= 0) {
435 .computeIfAbsent(sanitizedMd5, (k) ->
new ArrayList<>())
439 List<String> md5Hashes =
new ArrayList<>(md5ToObjId.keySet());
441 if (md5Hashes.isEmpty()) {
448 }
catch (Exception ex) {
450 Bundle.MalwareScanIngestModule_SharedProcessing_generalProcessingError_title(),
451 Bundle.MalwareScanIngestModule_SharedProcessing_generalProcessingError_desc(),
467 "MalwareScanIngestModule_SharedProcessing_exhaustedResultsHashLookups_title=Lookup Limits Exceeded",
468 "MalwareScanIngestModule_SharedProcessing_exhaustedResultsHashLookups_desc=Not all files were processed because hash lookup limits were exceeded. Please try again when your limits reset.",})
469 private void handleLookupResults(IngestJobState
ingestJobState, Map<String, List<Long>> md5ToObjId, List<CTCloudBean> repResult)
throws Blackboard.BlackboardException, TskCoreException, TskCoreException,
CTCloudException, NoSuchAlgorithmException, ReadContentInputStream.ReadContentInputStreamException {
470 if (CollectionUtils.isEmpty(repResult)) {
474 Map<Status, List<CTCloudBean>> statusGroupings = repResult.stream()
475 .filter(bean -> bean.getMalwareResult() !=
null)
476 .collect(Collectors.groupingBy(bean -> bean.getMalwareResult().getStatus()));
479 List<CTCloudBean> found = statusGroupings.get(
Status.
FOUND);
489 if (CollectionUtils.isNotEmpty(statusGroupings.get(
Status.
ERROR))) {
491 Bundle.MalwareScanIngestModule_SharedProcessing_generalProcessingError_title(),
492 Bundle.MalwareScanIngestModule_SharedProcessing_generalProcessingError_desc(),
499 Bundle.MalwareScanIngestModule_SharedProcessing_exhaustedResultsHashLookups_title(),
500 Bundle.MalwareScanIngestModule_SharedProcessing_exhaustedResultsHashLookups_desc(),
516 private void handleNonFoundResults(IngestJobState
ingestJobState, Map<String, List<Long>> md5ToObjId, List<CTCloudBean> results,
boolean performFileUpload)
throws CTCloudException, TskCoreException, NoSuchAlgorithmException, ReadContentInputStream.ReadContentInputStreamException {
517 if (CollectionUtils.isNotEmpty(results)
521 for (
CTCloudBean beingScanned : CollectionUtils.emptyIfNull(results)) {
523 String sanitizedMd5 =
normalizedMd5(beingScanned.getMd5HashValue());
524 if (StringUtils.isBlank(sanitizedMd5)) {
527 List<Long> correspondingObjIds = md5ToObjId.get(sanitizedMd5);
528 if (CollectionUtils.isEmpty(correspondingObjIds)) {
532 if (performFileUpload) {
536 ingestJobState.getUnidentifiedHashes().put(sanitizedMd5, correspondingObjIds);
552 if (
ingestJobState.getIngestJobContext().fileIngestIsCancelled()) {
553 return Collections.emptyList();
561 if (remainingScans <= 0) {
564 Bundle.MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_title(),
565 Bundle.MalwareScanIngestModule_SharedProcessing_exhaustedHashLookups_desc(),
567 return Collections.emptyList();
568 }
else if (
ingestJobState.getIngestJobContext().fileIngestIsCancelled()) {
569 return Collections.emptyList();
575 if (remainingUploads <= 0) {
578 Bundle.MalwareScanIngestModule_uploadFile_noRemainingFileUploads_title(),
579 Bundle.MalwareScanIngestModule_uploadFile_noRemainingFileUploads_desc(),
585 return ctApiDAO.getReputationResults(
598 return StringUtils.defaultString(orig).trim().toLowerCase();
609 long size = af.getSize();
623 "MalwareScanIngestModule_uploadFile_notUploadable_title=Not Able to Upload",
625 "MalwareScanIngestModule_uploadFile_notUploadable_desc=A file did not meet requirements for upload (object id: {0}).",
626 "MalwareScanIngestModule_uploadFile_noRemainingFileUploads_title=No Remaining File Uploads",
627 "MalwareScanIngestModule_uploadFile_noRemainingFileUploads_desc=There are no more file uploads on this license at this time. File uploads will be disabled for remaining uploads.",})
633 AbstractFile af =
ingestJobState.getTskCase().getAbstractFileById(objId);
640 Bundle.MalwareScanIngestModule_uploadFile_notUploadable_title(),
641 Bundle.MalwareScanIngestModule_uploadFile_notUploadable_desc(objId),
654 Bundle.MalwareScanIngestModule_uploadFile_noRemainingFileUploads_title(),
655 Bundle.MalwareScanIngestModule_uploadFile_noRemainingFileUploads_desc(),
659 }
else if (
ingestJobState.getIngestJobContext().fileIngestIsCancelled()) {
664 ReadContentInputStream fileInputStream =
new ReadContentInputStream(af);
667 .setContentLength(af.getSize())
697 "MalwareScanIngestModule_longPollForNotFound_fileLookupPolling_title=Waiting for File Upload Results",
698 "MalwareScanIngestModule_longPollForNotFound_fileLookupPolling_desc=Waiting for all uploaded files to complete scanning.",
699 "MalwareScanIngestModule_longPollForNotFound_timeout_title=File Upload Results Timeout",
700 "MalwareScanIngestModule_longPollForNotFound_timeout_desc=There was a timeout while waiting for file uploads to be processed. Please try again later.",})
705 ||
ingestJobState.getIngestJobContext().fileIngestIsCancelled()) {
710 Bundle.MalwareScanIngestModule_longPollForNotFound_fileLookupPolling_title(),
711 Bundle.MalwareScanIngestModule_longPollForNotFound_fileLookupPolling_desc()
713 logger.log(Level.INFO,
"Begin polling for malware status of file uploads.");
718 List<List<String>> md5Batches = Lists.partition(
new ArrayList<>(
remaining.keySet()),
BATCH_SIZE);
719 for (List<String> batch : md5Batches) {
727 Map<Status, List<CTCloudBean>> statusGroupings = repResult.stream()
728 .filter(bean -> bean.getMalwareResult() !=
null)
729 .collect(Collectors.groupingBy(bean -> bean.getMalwareResult().getStatus()));
732 List<CTCloudBean> found = statusGroupings.get(
Status.
FOUND);
737 for (
CTCloudBean foundItem : CollectionUtils.emptyIfNull(found)) {
748 long waitMultiplier = ((long) Math.pow(2, retry));
750 logger.log(Level.INFO, MessageFormat.format(
"Waiting {0} milliseconds before polling again for malware status of file uploads.", (waitMultiplier *
FILE_UPLOAD_RETRY_SLEEP_MILLIS)));
752 for (
int i = 0; i < waitMultiplier; i++) {
762 Bundle.MalwareScanIngestModule_longPollForNotFound_timeout_title(),
763 Bundle.MalwareScanIngestModule_longPollForNotFound_timeout_desc(),
779 private void createAnalysisResults(IngestJobState
ingestJobState, List<CTCloudBean> repResult, Map<String, List<Long>> md5ToObjId)
throws Blackboard.BlackboardException, TskCoreException {
780 if (CollectionUtils.isEmpty(repResult)) {
784 List<BlackboardArtifact> createdArtifacts =
new ArrayList<>();
785 SleuthkitCase.CaseDbTransaction trans =
null;
789 String sanitizedMd5 =
normalizedMd5(result.getMd5HashValue());
790 List<Long> objIds = md5ToObjId.remove(sanitizedMd5);
791 if (CollectionUtils.isEmpty(objIds)) {
795 for (Long objId : objIds) {
799 Score score = res.getScore();
800 if (score.getSignificance() == Score.Significance.NOTABLE || score.getSignificance() == Score.Significance.LIKELY_NOTABLE) {
801 createdArtifacts.add(res);
812 createdArtifacts.clear();
817 if (!CollectionUtils.isEmpty(createdArtifacts)) {
820 Bundle.MalwareScanIngestModuleFactory_displayName(),
839 "MalwareScanIngestModule_SharedProcessing_createAnalysisResult_Yes=YES",
840 "MalwareScanIngestModule_SharedProcessing_createAnalysisResult_No=NO"
844 logger.log(Level.WARNING, MessageFormat.format(
"Attempting to create analysis result with invalid parameters [objId: {0}, cloud bean status: {1}]",
856 ? Score.SCORE_UNKNOWN
859 String conclusion = score.getSignificance() == Score.Significance.NOTABLE || score.getSignificance() == Score.Significance.LIKELY_NOTABLE
860 ? Bundle.MalwareScanIngestModule_SharedProcessing_createAnalysisResult_Yes()
861 : Bundle.MalwareScanIngestModule_SharedProcessing_createAnalysisResult_No();
865 return ingestJobState.getTskCase().getBlackboard().newAnalysisResult(
873 Collections.emptyList(),
874 trans).getAnalysisResult();
881 "MalwareScanIngestModule_SharedProcessing_flushTimeout_title=Processing Timeout",
882 "MalwareScanIngestModule_SharedProcessing_flushTimeout_desc=A timeout occurred while finishing processing"
894 }
catch (InterruptedException ex) {
896 Bundle.MalwareScanIngestModule_SharedProcessing_flushTimeout_title(),
897 Bundle.MalwareScanIngestModule_SharedProcessing_flushTimeout_desc(),
899 }
catch (Exception ex) {
901 Bundle.MalwareScanIngestModule_SharedProcessing_generalProcessingError_title(),
902 Bundle.MalwareScanIngestModule_SharedProcessing_generalProcessingError_desc(),
918 private static void notifyWarning(String title, String message, Exception ex) {
920 logger.log(Level.WARNING, message, ex);
925 private final long objId;
926 private final String md5hash;
928 FileRecord(
long objId, String md5hash) {
930 this.md5hash = md5hash;
937 String getMd5hash() {
953 static class IngestJobState {
955 static final IngestJobState DISABLED =
new IngestJobState(
966 private final SleuthkitCase tskCase;
967 private final FileTypeDetector fileTypeDetector;
968 private final LicenseInfo licenseInfo;
969 private final BlackboardArtifact.Type malwareType;
970 private final long dsId;
971 private final long ingestJobId;
972 private final boolean queryForMissing;
973 private final Map<String, List<Long>> unidentifiedHashes =
new HashMap<>();
976 private boolean uploadUnknownFiles;
977 private boolean doFileLookups;
978 private final IngestJobContext ingestJobContext;
979 private final PathNormalizer pathNormalizer;
981 IngestJobState(IngestJobContext ingestJobContext, SleuthkitCase tskCase, PathNormalizer pathNormalizer, FileTypeDetector fileTypeDetector, LicenseInfo licenseInfo, BlackboardArtifact.Type malwareType,
boolean uploadUnknownFiles,
boolean doFileLookups) {
982 this.tskCase = tskCase;
983 this.fileTypeDetector = fileTypeDetector;
984 this.pathNormalizer = pathNormalizer;
985 this.licenseInfo = licenseInfo;
986 this.malwareType = malwareType;
987 this.dsId = ingestJobContext ==
null ? 0L : ingestJobContext.getDataSource().getId();
988 this.ingestJobId = ingestJobContext ==
null ? 0L : ingestJobContext.getJobId();
989 this.ingestJobContext = ingestJobContext;
991 this.queryForMissing = uploadUnknownFiles && doFileLookups;
992 this.uploadUnknownFiles = uploadUnknownFiles;
993 this.doFileLookups = doFileLookups;
996 SleuthkitCase getTskCase() {
1000 IngestJobContext getIngestJobContext() {
1001 return ingestJobContext;
1004 FileTypeDetector getFileTypeDetector() {
1005 return fileTypeDetector;
1008 LicenseInfo getLicenseInfo() {
1012 BlackboardArtifact.Type getMalwareType() {
1020 long getIngestJobId() {
1024 Map<String, List<Long>> getUnidentifiedHashes() {
1025 return unidentifiedHashes;
1028 boolean isQueryForMissing() {
1029 return queryForMissing;
1032 boolean isUploadUnknownFiles() {
1033 return uploadUnknownFiles;
1036 void disableUploadUnknownFiles() {
1037 this.uploadUnknownFiles =
false;
1040 boolean isDoFileLookups() {
1041 return doFileLookups;
1044 void disableDoFileLookups() {
1045 this.doFileLookups =
false;
1048 public PathNormalizer getPathNormalizer() {
1049 return pathNormalizer;
static CTApiDAO getInstance()
Long getHashLookupCount()
Long getHashLookupLimit()
Long getFileUploadCount()
String getFileUploadUrl()
Long getFileUploadLimit()
MalwareResultBean getMalwareResult()
FileUploadRequest setFileInputStream(InputStream fileInputStream)
FileUploadRequest setFullUrlPath(String fullUrlPath)
FileUploadRequest setFileName(String fileName)
String getStatusDescription()
static CTLicensePersistence getInstance()
static final long MAX_UPLOAD_SIZE
static String getOrCalcHash(AbstractFile af, HashType hashType)
void handleNonFoundResults(IngestJobState ingestJobState, Map< String, List< Long > > md5ToObjId, List< CTCloudBean > results, boolean performFileUpload)
List< CTCloudBean > getHashLookupResults(IngestJobState ingestJobState, List< String > md5Hashes)
static String getOrCalcSha256(AbstractFile af)
static boolean isUploadable(AbstractFile af)
final CTLicensePersistence ctSettingsPersistence
static final String MALWARE_CONFIG
static long remaining(Long limit, Long used)
static final long FILE_UPLOAD_RETRY_SLEEP_MILLIS
void handleLookupResults(IngestJobState ingestJobState, Map< String, List< Long > > md5ToObjId, List< CTCloudBean > repResult)
void longPollForNotFound(IngestJobState ingestJobState)
void createAnalysisResults(IngestJobState ingestJobState, List< CTCloudBean > repResult, Map< String, List< Long > > md5ToObjId)
static final long FLUSH_SECS_TIMEOUT
static final long MIN_UPLOAD_SIZE
static String getOrCalcSha1(AbstractFile af)
static final long LOW_LOOKUPS_REMAINING
IngestJobState getNewJobState(IngestJobContext context, boolean uploadFiles)
static final Set< String > EXECUTABLE_MIME_TYPES
static String getOrCalcMd5(AbstractFile af)
AnalysisResult createAnalysisResult(IngestJobState ingestJobState, SleuthkitCase.CaseDbTransaction trans, CTCloudBean cloudBean, Long objId)
static final int NUM_FILE_UPLOAD_RETRIES
IngestJobState ingestJobState
static String normalizedMd5(String orig)
static final long LOW_UPLOADS_REMAINING
static final int BATCH_SIZE
void handleBatch(IngestJobState ingestJobState, List< FileRecord > fileRecords)
static final Logger logger
static void notifyWarning(String title, String message, Exception ex)
final BatchProcessor< FileRecord > batchProcessor
boolean uploadFile(IngestJobState ingestJobState, String md5, long objId)
SleuthkitCase getSleuthkitCase()
static Case getCurrentCaseThrows()
synchronized static Logger getLogger(String name)
static void warn(String title, String message)
static void info(String title, String message)
boolean fileIngestIsCancelled()
String getMIMEType(AbstractFile file)