diff --git a/README.md b/README.md index 0ba8376..ed202a3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ # MalPull -A CLI interface to search for a MD-5/SHA-1/SHA-256 hash on multiple malware databases and download the sample from the first hit. More information can be found here. If there are any questions, feature suggestions, or bug reports: please send me a direct message @Libranalysis, +A CLI interface to search for a MD-5/SHA-1/SHA-256 hash on multiple malware databases and download the sample from the first hit. More information can be found here.If there are any questions, feature suggestions, or bug reports: please send me a message my Twitter (@Libranalysis). diff --git a/pom.xml b/pom.xml index 9d82498..908c5ae 100644 --- a/pom.xml +++ b/pom.xml @@ -1,9 +1,9 @@ 4.0.0 - malwarepuller + malpull MalPull - 1.2.1-stable + 1.3-stable jar UTF-8 @@ -42,7 +42,7 @@ - malpull.MalPull + malpull.cli.MalPullCli @@ -50,6 +50,32 @@ + + org.apache.maven.plugins + 3.2.1 + maven-source-plugin + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + 3.2.0 + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + @@ -63,6 +89,12 @@ json 20190722 + + + net.lingala.zip4j + zip4j + 2.7.0 + MalPull diff --git a/src/main/java/concurrency/DownloadWorker.java b/src/main/java/malpull/DownloadWorker.java similarity index 77% rename from src/main/java/concurrency/DownloadWorker.java rename to src/main/java/malpull/DownloadWorker.java index 4ae1acc..54a6144 100644 --- a/src/main/java/concurrency/DownloadWorker.java +++ b/src/main/java/malpull/DownloadWorker.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * Copyright (C) 2020 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,10 +14,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package concurrency; +package malpull; -import endpoints.*; -import exceptions.SampleNotFoundException; +import malpull.endpoints.IEndpoint; +import malpull.exceptions.SampleNotFoundException; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -30,10 +30,15 @@ * of the endpoints in the list. If it fails, the hash is added to the missing * hashes list in the main class. * - * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] */ public class DownloadWorker implements Runnable { + /** + * The instance of MalPull to connect back to + */ + private MalPull malPull; + /** * The list of endpoints iterate through in an attempt to download the hash */ @@ -64,6 +69,7 @@ public class DownloadWorker implements Runnable { /** * Creates a worker object, which can be queued for the thread pool * + * @param malPull the MalPull instance to connect back to * @param endpoints the list of endpoints to attempt to download from * @param path the location to write the file to the disk * @param hash the hash to look for @@ -71,7 +77,8 @@ public class DownloadWorker implements Runnable { * creation * @param total the total number of samples to be downloaded */ - public DownloadWorker(List endpoints, String path, String hash, int count, int total) { + public DownloadWorker(MalPull malPull, List endpoints, String path, String hash, int count, int total) { + this.malPull = malPull; this.endpoints = endpoints; this.path = path; this.hash = hash; @@ -110,26 +117,29 @@ public void run() { //The file is written to disk writeToDisk(output, filePath); //A message is printed for the user - System.out.println("Wrote " + output.length + " bytes to " + filePath + " from " + endpoint.getName() + " (" + count + " / " + total + ")"); + malPull.log("(" + count + " / " + total + ") Wrote " + output.length + " bytes to " + filePath + " from " + endpoint.getName()); + //Add the hash to the log + malPull.addDownloadedHash(hash, endpoint.getName()); //The boolean is set to true, causing the next iteration to break out of the loop isDownloaded = true; } - } catch (SampleNotFoundException e) { + } catch (SampleNotFoundException ex) { /** * The exception message can be ignored, as failure to * download the sample results in the missing hash, but only * if none of the configured endpoints has the hash */ - //System.out.println(e.getMessage()); } } //If the sample is not downloaded after the loop, it is missing if (isDownloaded == false) { //This method is thread safe - MalPull.addMissingHash(hash); + malPull.addMissingHash(hash); + malPull.log("(" + count + " / " + total + ") Added \"" + hash + "\" to the missing hashes"); } } catch (Exception ex) { - System.out.println(ex.getMessage()); + String message = "(" + count + " / " + total + ") An error occured when downloading " + hash + ":\n" + ex.getMessage(); + malPull.log(message); } } @@ -143,7 +153,7 @@ private void writeToDisk(byte[] output, String path) { try (FileOutputStream fos = new FileOutputStream(path)) { fos.write(output); } catch (IOException ex) { - System.out.println("An error occured when writing the sample to \"" + path + "\". Verify your permissions and try again!"); + malPull.log("An error occured when writing the sample to \"" + path + "\". Check the permissions and try again! Error:\n" + ex.getMessage()); } } } diff --git a/src/main/java/malpull/MalPull.java b/src/main/java/malpull/MalPull.java index 14ea381..8e0637c 100644 --- a/src/main/java/malpull/MalPull.java +++ b/src/main/java/malpull/MalPull.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * Copyright (C) 2020 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,135 +16,192 @@ */ package malpull; -import concurrency.DownloadWorker; -import endpoints.IEndpoint; -import endpoints.Koodous; -import endpoints.MalShare; -import endpoints.MalwareBazaar; -import endpoints.Triage; -import endpoints.VirusTotal; +import java.io.PrintStream; +import malpull.model.Arguments; +import malpull.endpoints.IEndpoint; +import malpull.endpoints.Koodous; +import malpull.endpoints.MalShare; +import malpull.endpoints.MalwareBazaar; +import malpull.endpoints.Triage; +import malpull.endpoints.VirusTotal; import java.time.Instant; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; -import java.util.Set; +import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import malpull.exceptions.NoArgumentsSetException; +import malpull.model.MalPullResult; /** - * This class is the main class of the project, and creates and calls all - * objects. The project is set-up to have one malware repository service per - * class, which is contacted via the service's API. The classes within the - * endpoints package all correspond to a single service. + * This class can be used to use MalPull as a library in any project. The + * constructors provide the option to log data. The download function requires + * all parameters, which can be parsed via any front-end that is made, or + * directly via code if this class is imported as a library.
+ *
+ * To compile this project as a single JAR, use: + * mvn clean compile assembly:single. Install it in your local + * Maven repository to use it as a library in other projects, or copy the code + * into your project. * - * The Downloader class, which resides in this package, functions as a wrapper - * class around the OkHttp3 library that is being used to perform the HTTP - * requests. - * - * To compile this project, use: mvn clean compile assembly:single - * - * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] */ public class MalPull { + /** + * A mapping where the keys are equal to the user-provided hashes, and the + * value per key is the endpoint the hash was downloaded from + */ + private Map downloadedSamples; + /** * A list of hashes that could not be downloaded, taken from the * deduplicated input */ - private static List missingHashes = new ArrayList<>(); + private List missingHashes; /** - * Build using: + * The print stream to write the log to + */ + private PrintStream outputStream; + + /** + * Creates the MalPull object, automatically initialising the required + * fields. * - * mvn clean compile assembly:single + * @param outputStream the stream to write the logs to + */ + public MalPull(PrintStream outputStream) { + //Initialise the downloaded samples mapping + downloadedSamples = new HashMap<>(); + //Initialise the missing hashes list + missingHashes = new ArrayList<>(); + //Set the output stream + this.outputStream = outputStream; + log(getVersionInformation()); + } + + /** + * Creates the MalPull object, automatically initialising the required + * fields. This instance will not have a logger, as it is not provided in + * the constructor + */ + public MalPull() { + //Initialise the downloaded samples mapping + downloadedSamples = new HashMap<>(); + //Initialise the missing hashes list + missingHashes = new ArrayList<>(); + //Set the output stream to null, thereby disabling it + this.outputStream = null; + } + + /** + * Creates a download worker object, which can be scheduled with the thread + * scheduler * - * @param args the command-line arguments + * @param arguments the object that contains the API keys + * @param hash the hash of the sample to use + * @param count the number that corresponds with the hash (used in the + * logging as count/total, where total is the total amount of + * hashes in the arguments object + * @return a list of download workers, ready to be scheduled */ - public static void main(String[] args) { - //Get the start time - long start = Instant.now().getEpochSecond(); - //Show the version information - printVersionInformation(); - /** - * Parse the arguments into a newly created object. If the arguments - * cannot be parsed properly, the error message is displayed and MalPull - * shuts down. - */ - Arguments arguments = ArgumentHandler.handle(args); + private DownloadWorker getDownloadWorker(Arguments arguments, String hash, int count) { + //Create a list of endpoints + List endpoints = new ArrayList<>(); + //Check all keys, and include endpoints for which keys are present + if (arguments.getTriageKey() != null) { + IEndpoint triage = new Triage(arguments.getTriageKey()); + endpoints.add(triage); + } + if (arguments.getMalwareBazaarKey() != null) { + IEndpoint malwareBazaar = new MalwareBazaar(); + endpoints.add(malwareBazaar); + } + if (arguments.getMalShareKey() != null) { + IEndpoint malShare = new MalShare(arguments.getMalShareKey()); + endpoints.add(malShare); + } + if (arguments.getKoodousKey() != null) { + IEndpoint koodous = new Koodous(arguments.getKoodousKey()); + endpoints.add(koodous); + } + if (arguments.getVirusTotalKey() != null) { + IEndpoint virusTotal = new VirusTotal(arguments.getVirusTotalKey()); + endpoints.add(virusTotal); + } + + //Create a download worker for the hash, with all configured endpoints embedded + DownloadWorker worker = new DownloadWorker(this, endpoints, arguments.getOutputPath(), hash, count, arguments.getHashes().size()); + //Return the download worker + return worker; + } - //Show the input back to the user, as this helps to avoid mistakes - System.out.println("Read " + arguments.getHashes().size() + " hashes"); - System.out.println("Downloading will be done using " + arguments.getThreadCount() + " thread(s)"); - System.out.println("Output will be written to: " + arguments.getOutputPath()); - System.out.println(""); + /** + * Downloads all samples that correspond to the given hashes, using the + * given services, to the given folder. Each sample is equal to the given + * hash name. The logging is written to the stream that the constructor of + * this object received. If none is given (or if it is equal to null), the + * logging is not printed.
+ *
+ * This function can take a while to return, depending on the amount of + * hashes that are provided, and the speed of the enabled services. Take + * note of this! + * + * @param arguments the arguments to use + * @return the download result, providing insight into all downloaded + * samples, all missing hashes, and the time it took + * @throws NoArgumentsSetException if the given argument object is null + */ + public MalPullResult download(Arguments arguments) throws NoArgumentsSetException { + //Check if the arguments are set + if (arguments == null) { + throw new NoArgumentsSetException("The arguments need to be set prior to calling the download function"); + } - //Get all hashes in deduplicated form - Set hashes = arguments.getHashes(); + /** + * The validity of the arguments are checked upon the creation of the + * arguments object, meaning that the presence of the object indicates + * that the values can be trusted + */ + //Get the start time + long start = Instant.now().getEpochSecond(); //Get the thread count from the parsed arguments ExecutorService executor = Executors.newFixedThreadPool(arguments.getThreadCount()); - //Keep track of the count so each thread can print what number it had comapred to the total amount of downloads + int count = 0; - //Iterate through all hashes, adding an endpoint for each of the configured endpoints - for (String hash : hashes) { + //Iterate over all hashes + for (String hash : arguments.getHashes()) { + //Increase the count, which indicates is used in the logging to display the progress with respect to the total amount of hashes count++; - List endpoints = new ArrayList<>(); - if (arguments.getTriageKey() != null) { - IEndpoint triage = new Triage(arguments.getTriageKey()); - endpoints.add(triage); - } - if (arguments.getMalwareBazaarKey() != null) { - IEndpoint malwareBazaar = new MalwareBazaar(); - endpoints.add(malwareBazaar); - } - if (arguments.getMalShareKey() != null) { - IEndpoint malShare = new MalShare(arguments.getMalShareKey()); - endpoints.add(malShare); - } - if (arguments.getKoodousKey() != null) { - IEndpoint koodous = new Koodous(arguments.getKoodousKey()); - endpoints.add(koodous); - } - if (arguments.getVirusTotalKey() != null) { - IEndpoint virusTotal = new VirusTotal(arguments.getVirusTotalKey()); - endpoints.add(virusTotal); - } - - //Create a download worker for the hash, with all configured endpoints embedded - DownloadWorker downloadWorker = new DownloadWorker(endpoints, arguments.getOutputPath(), hash, count, hashes.size()); - //Execute the download worker in the future, disregarding when specifically - executor.execute(downloadWorker); + //Get the download worker for the given hash + DownloadWorker worker = getDownloadWorker(arguments, hash, count); + //Schedule the worker + executor.execute(worker); } - //Once all tasks are done, shut the executor down, meaning no new tasks can be added + + //Once all workers are created, shut the executor down, meaning no new tasks can be added executor.shutdown(); //Wait until the executor is terminated, which only happens when all downloads are finished while (!executor.isTerminated()) { } - //Notify the user that all downloads are finished - System.out.println(""); - System.out.println("All downloads finished! The sample number count is not always printed in ascending order, as the threads print the messages."); - - //If some hashes could not be found, these are printed - if (missingHashes.size() > 0) { - System.out.println("\n\nMissing " + missingHashes.size() + " hashes:"); - for (String missingHash : missingHashes) { - System.out.println(missingHash); - } - } - //Get the time since the start of the downloading + + //Get the time since the downloading started String time = getDuration(start); - //Display the time that the download process took - System.out.println("\nDownloaded " + (hashes.size() - missingHashes.size()) + " samples in " + time + "!"); - //Exit the program explicitly, as it sometimes remains open in some edge cases - System.exit(0); + + //Return the result to the caller + return new MalPullResult(downloadedSamples, missingHashes, time); } /** * Gets the duration from the given starting point until the moment this - * function is executed in the format of hh:mm:ss. + * function is executed in the format of hhh:mm:ss. * * @param start the time to start in seconds from epoch */ - private static String getDuration(long start) { + private String getDuration(long start) { //Get the end time long end = Instant.now().getEpochSecond(); //Calculate the time difference @@ -157,23 +214,47 @@ private static String getDuration(long start) { //Calculate the amount of hours long hours = (duration / (60 * 60)) % 24; //Format the times into a single string and return those - return String.format("%02d:%02d:%02d", hours, minutes, seconds); + return String.format("%03d:%02d:%02d", hours, minutes, seconds); + } + + /** + * A thread safe function to write data to the given output stream + * + * @param message the message to log + */ + protected synchronized void log(String message) { + if (outputStream == null) { + return; + } + outputStream.println(message); } /** - * As the add function is not thread safe, this synchronised function is - * used as a wrapper + * A thread safe function to add a hash (and the endpoint it was downloaded + * from) to the mapping + * + * @param hash the hash to add + * @param endpoint the endpoint where the hash was downloaded from + */ + protected synchronized void addDownloadedHash(String hash, String endpoint) { + downloadedSamples.put(hash, endpoint); + } + + /** + * A thread safe function to add a missing hash to the list * * @param missingHash the hash to add */ - public static synchronized void addMissingHash(String missingHash) { + protected synchronized void addMissingHash(String missingHash) { missingHashes.add(missingHash); } /** - * Prints the version information, together with an additional newline + * Gets the version information, together with an additional newline + * + * @return the version information */ - private static void printVersionInformation() { - System.out.println("MalPull version 1.2-stable by Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl]\n"); + public String getVersionInformation() { + return "MalPull version 1.3-stable by Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl]\n"; } } diff --git a/src/main/java/malpull/ArgumentHandler.java b/src/main/java/malpull/cli/ArgumentHandler.java similarity index 89% rename from src/main/java/malpull/ArgumentHandler.java rename to src/main/java/malpull/cli/ArgumentHandler.java index 75b7dbe..4531909 100644 --- a/src/main/java/malpull/ArgumentHandler.java +++ b/src/main/java/malpull/cli/ArgumentHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * Copyright (C) 2020 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,8 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package malpull; +package malpull.cli; +import malpull.model.Arguments; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -24,26 +25,28 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; +import malpull.exceptions.NoHashesFoundException; +import malpull.exceptions.NoServicesSetException; /** * This class parses the given arguments into an Arguments object, thereby * simplifying the code in the main function, and splitting the sanity checks * from the rest of the code * - * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] */ public class ArgumentHandler { /** - * Parses the arguments into an Arguments object. Stops MalPull upon the + * Parses the arguments into an Arguments object.Stops MalPull upon the * occurrence of an exception and prints a help message for the user * * @param args the arguments to parse * @return the parsed arguments + * @throws NoServicesSetException if none of the services are enabled + * @throws NoHashesFoundException if no hashes are provided */ - public static Arguments handle(String[] args) { + public static Arguments handle(String[] args) throws NoServicesSetException, NoHashesFoundException { //Only 4 arguments are accepted: //java -jar malpull.jar threadCount /path/to/keys.txt /path/to/hashes.txt /path/to/write/samples/to if (args.length != 4) { @@ -81,7 +84,7 @@ public static Arguments handle(String[] args) { //Iterate through all keys, note that the endpoint prefix is case insensitive for (String key : keys) { if (key.toLowerCase().startsWith("koodous=".toLowerCase())) { - koodousKey = key.substring("koodous".length(), key.length()); + koodousKey = key.substring("koodous=".length(), key.length()); } else if (key.toLowerCase().startsWith("malwarebazaar=".toLowerCase())) { malwareBazaarKey = key.substring("malwarebazaar=".length(), key.length()); } else if (key.toLowerCase().startsWith("malshare=".toLowerCase())) { @@ -140,7 +143,6 @@ private static List loadFile(String path) { } } catch (IOException ex) { System.out.println("An exception occured when reading " + file.getAbsolutePath() + ":"); - Logger.getLogger(MalPull.class.getName()).log(Level.SEVERE, null, ex); System.exit(0); } return output; @@ -166,7 +168,7 @@ private static void printUsage() { System.out.println("This tool downloads samples from MalShare, MalwareBazaar, Koodous, VirusTotal, and Hatching Triage based on given MD-5, SHA-1, or SHA-256 hashes."); System.out.println("The sample is written to the given output directory. API Keys for any of the used services is required."); System.out.println("Once all samples are downloaded, the hashes that couldn't be found will be listed."); - System.out.println("For detailed information on the usage of MalPull, please visit https://maxkersten.nl/wordpress/projects/malpull/#usage"); + System.out.println("For detailed information on the usage of MalPull, please visit https://maxkersten.nl/projects/malpull/#usage"); System.out.println(""); System.out.println("Sample usage of this program:"); System.out.println("\t\tjava -jar /path/toMalPull.jar threadCount /path/to/keys.txt /path/to/hashes.txt /path/to/write/samples/to"); diff --git a/src/main/java/malpull/cli/MalPullCli.java b/src/main/java/malpull/cli/MalPullCli.java new file mode 100644 index 0000000..fd57f83 --- /dev/null +++ b/src/main/java/malpull/cli/MalPullCli.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2021 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package malpull.cli; + +import malpull.MalPull; +import malpull.exceptions.NoArgumentsSetException; +import malpull.model.Arguments; +import malpull.exceptions.NoHashesFoundException; +import malpull.exceptions.NoServicesSetException; +import malpull.model.MalPullResult; + +/** + * This class is the command-line interface wrapper for the MalPull object.
+ *
+ * Build using: mvn clean compile assembly:single + * + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] + */ +public class MalPullCli { + + /** + * The main function of the program, providing a CLI to use. The + * ArgumentHandler class provides help regarding the CLI arguments that are + * required. + * + * @param args the command-line arguments + */ + public static void main(String[] args) { + //Create the MalPull instance, using the standard system output printstream to print the logging + MalPull malPull = new MalPull(System.out); + + /** + * Parse the arguments into a newly created object. If the arguments + * cannot be parsed properly, the error message is displayed and MalPull + * shuts down. + */ + try { + //Parse the arguments + Arguments arguments = ArgumentHandler.handle(args); + + //Show the input to the user, as this helps to avoid mistakes + System.out.println("Read " + arguments.getHashes().size() + " hashes"); + System.out.println("Downloading will be done using " + arguments.getThreadCount() + " thread(s)"); + System.out.println("Output will be written to: " + arguments.getOutputPath()); + System.out.println(""); + + //Start the downloading, where the progress will be printed to the standard output by the threads + MalPullResult result = malPull.download(arguments); + + //Notify the user that all downloads are finished + System.out.println("\nAll downloads finished! The sample number count is not always printed in ascending order, as the threads print the messages."); + + //If some hashes could not be found, these are printed + if (result.getMissingHashes().size() > 0) { + System.out.println("\n\nMissing " + result.getMissingHashes().size() + " hashes:"); + for (String missingHash : result.getMissingHashes()) { + System.out.println(missingHash); + } + } + //Display the time that the download process took + System.out.println("\nDownloaded " + result.getDownloadedSamples().size() + " samples in " + result.getTime() + "!"); + //Exit the program explicitly, as it sometimes remains open in some edge cases + System.exit(0); + } catch (NoServicesSetException | NoHashesFoundException | NoArgumentsSetException ex) { + System.out.println(ex.getMessage()); + } + } +} diff --git a/src/main/java/endpoints/GenericEndpoint.java b/src/main/java/malpull/endpoints/GenericEndpoint.java similarity index 82% rename from src/main/java/endpoints/GenericEndpoint.java rename to src/main/java/malpull/endpoints/GenericEndpoint.java index 0b85f13..0493471 100644 --- a/src/main/java/endpoints/GenericEndpoint.java +++ b/src/main/java/malpull/endpoints/GenericEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * Copyright (C) 2020 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,22 +14,22 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package endpoints; +package malpull.endpoints; -import malpull.Downloader; +import malpull.network.MalPullConnector; /** * This abstract class contains the shared code base for all endpoints, which is * done to re-use code. * - * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] */ public abstract class GenericEndpoint { /** * The downloader wrapper class that is used to make HTTP requests */ - protected Downloader downloader; + protected MalPullConnector downloader; /** * The name of the endpoint @@ -45,7 +45,7 @@ public GenericEndpoint(String apiBase, String name) { //Sets the apiBase variable this.apiBase = apiBase; //Initialises the downloader class - downloader = new Downloader(); + downloader = new MalPullConnector(); //Sets the name variable this.name = name; } diff --git a/src/main/java/endpoints/IEndpoint.java b/src/main/java/malpull/endpoints/IEndpoint.java similarity index 84% rename from src/main/java/endpoints/IEndpoint.java rename to src/main/java/malpull/endpoints/IEndpoint.java index 5f1cca2..10c5a41 100644 --- a/src/main/java/endpoints/IEndpoint.java +++ b/src/main/java/malpull/endpoints/IEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * Copyright (C) 2020 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,12 +14,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package endpoints; +package malpull.endpoints; /** * The interface to use for all endpoints that are used * - * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] */ public interface IEndpoint { @@ -35,7 +35,7 @@ public interface IEndpoint { /** * Gets the name of the endpoint * - * @return + * @return the name of the endpoint */ public String getName(); } diff --git a/src/main/java/endpoints/Koodous.java b/src/main/java/malpull/endpoints/Koodous.java similarity index 95% rename from src/main/java/endpoints/Koodous.java rename to src/main/java/malpull/endpoints/Koodous.java index 4ed64f9..0d4017a 100644 --- a/src/main/java/endpoints/Koodous.java +++ b/src/main/java/malpull/endpoints/Koodous.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * Copyright (C) 2020 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,9 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package endpoints; +package malpull.endpoints; -import exceptions.SampleNotFoundException; +import malpull.exceptions.SampleNotFoundException; import okhttp3.Request; import org.json.JSONArray; import org.json.JSONObject; @@ -24,7 +24,7 @@ /** * This class is used to get a sample from the Koodous database via its API. * - * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] */ public class Koodous extends GenericEndpoint implements IEndpoint { diff --git a/src/main/java/endpoints/MalShare.java b/src/main/java/malpull/endpoints/MalShare.java similarity index 92% rename from src/main/java/endpoints/MalShare.java rename to src/main/java/malpull/endpoints/MalShare.java index 5cbc48f..978a58e 100644 --- a/src/main/java/endpoints/MalShare.java +++ b/src/main/java/malpull/endpoints/MalShare.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * Copyright (C) 2020 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,15 +14,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package endpoints; +package malpull.endpoints; -import exceptions.SampleNotFoundException; +import malpull.exceptions.SampleNotFoundException; import okhttp3.Request; /** * This class is used to get a sample from the MalShare database via its API. * - * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] */ public class MalShare extends GenericEndpoint implements IEndpoint { diff --git a/src/main/java/endpoints/MalwareBazaar.java b/src/main/java/malpull/endpoints/MalwareBazaar.java similarity index 57% rename from src/main/java/endpoints/MalwareBazaar.java rename to src/main/java/malpull/endpoints/MalwareBazaar.java index 9911b33..15eadea 100644 --- a/src/main/java/endpoints/MalwareBazaar.java +++ b/src/main/java/malpull/endpoints/MalwareBazaar.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * Copyright (C) 2020 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,9 +14,18 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package endpoints; +package malpull.endpoints; -import exceptions.SampleNotFoundException; +import malpull.exceptions.SampleNotFoundException; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; +import net.lingala.zip4j.ZipFile; +import net.lingala.zip4j.exception.ZipException; +import net.lingala.zip4j.io.inputstream.ZipInputStream; +import net.lingala.zip4j.model.FileHeader; import okhttp3.MultipartBody; import okhttp3.RequestBody; import org.json.JSONObject; @@ -25,7 +34,7 @@ * This class is used to get a sample from the MalwareBazaar database via its * API. * - * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] */ public class MalwareBazaar extends GenericEndpoint implements IEndpoint { @@ -48,14 +57,19 @@ public MalwareBazaar() { */ @Override public byte[] getSample(String hash) throws SampleNotFoundException { - //Get the SHA-256 hash via the search function of the API, as only SHA-256 hashes can be used when downloading a sample - String sha256Hash = getSha256Hash(hash); - //If it cannot be found, there is no such sample - if (sha256Hash.isEmpty()) { - throw new SampleNotFoundException("Sample " + hash + " not found on MalwareBazaar!"); + try { + //Get the SHA-256 hash via the search function of the API, as only SHA-256 hashes can be used when downloading a sample + String sha256Hash = getSha256Hash(hash); + //If it cannot be found, there is no such sample + if (sha256Hash.isEmpty()) { + throw new SampleNotFoundException("Sample " + hash + " not found on MalwareBazaar!"); + } + //If the sample exists, download it + return download(sha256Hash); + } catch (IOException e) { + throw new SampleNotFoundException("Something went wrong when handling the file in the temporary files folder"); } - //If the sample exists, download it - return download(sha256Hash); + } /** @@ -97,10 +111,12 @@ private String getSha256Hash(String hash) throws SampleNotFoundException { * * @param hash the SHA-256 hash of the sample to download * @return the API's response, which is the raw file - * @throws HttpConnectionFailed if no connection can be made from the - * current machine, or to the given host + * @throws malpull.exceptions.SampleNotFoundException if the sample cannot be foun + * @throws java.io.IOException if the creation or deletion of the file in + * the temp folder fails for any reason */ - private byte[] download(String hash) throws SampleNotFoundException { + public byte[] download(String hash) throws SampleNotFoundException, IOException { + String tempPath = System.getProperty("java.io.tmpdir") + System.getProperty("file.separator") + hash; //Create the request body for the HTTP POST request with the form data RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) @@ -108,7 +124,34 @@ private byte[] download(String hash) throws SampleNotFoundException { .addFormDataPart("sha256_hash", hash) .build(); //Return the API's response - return downloader.post(apiBase, requestBody); + byte[] zip = downloader.post(apiBase, requestBody); + + File localFile = new File(tempPath); + localFile.getParentFile().mkdirs(); + Files.write(localFile.toPath(), zip); //overwrites if it exists, not thread safe when downloading the same data, unless a unique path is given + + String password = "infected"; + + try { + ZipFile zipFile = new ZipFile(localFile); + if (zipFile.isEncrypted()) { + zipFile.setPassword(password.toCharArray()); + } + + List headers = zipFile.getFileHeaders(); + ZipInputStream inputStream = zipFile.getInputStream(headers.get(0)); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + + int offset = -1; + byte[] buff = new byte[1024]; + while ((offset = inputStream.read(buff)) != -1) { + outputStream.write(buff, 0, offset); + } + localFile.delete(); + return outputStream.toByteArray(); + } catch (ZipException e) { + throw new IOException("Error whilst handling the ZIP archive:\n" + e.getMessage()); + } } } diff --git a/src/main/java/endpoints/Triage.java b/src/main/java/malpull/endpoints/Triage.java similarity index 93% rename from src/main/java/endpoints/Triage.java rename to src/main/java/malpull/endpoints/Triage.java index a01ab1f..3ff5842 100644 --- a/src/main/java/endpoints/Triage.java +++ b/src/main/java/malpull/endpoints/Triage.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * Copyright (C) 2021 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,9 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package endpoints; +package malpull.endpoints; -import exceptions.SampleNotFoundException; +import malpull.exceptions.SampleNotFoundException; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; @@ -26,7 +26,7 @@ /** * The class that is used to get a sample from Triage * - * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] */ public class Triage extends GenericEndpoint implements IEndpoint { diff --git a/src/main/java/endpoints/VirusTotal.java b/src/main/java/malpull/endpoints/VirusTotal.java similarity index 89% rename from src/main/java/endpoints/VirusTotal.java rename to src/main/java/malpull/endpoints/VirusTotal.java index 7f9f35e..5e19aa6 100644 --- a/src/main/java/endpoints/VirusTotal.java +++ b/src/main/java/malpull/endpoints/VirusTotal.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * Copyright (C) 2020 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,15 +14,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package endpoints; +package malpull.endpoints; -import exceptions.SampleNotFoundException; +import malpull.exceptions.SampleNotFoundException; import okhttp3.Request; /** * The class to get a sample from VirusTotal. * - * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] */ public class VirusTotal extends GenericEndpoint implements IEndpoint { diff --git a/src/main/java/malpull/exceptions/NoArgumentsSetException.java b/src/main/java/malpull/exceptions/NoArgumentsSetException.java new file mode 100644 index 0000000..a678301 --- /dev/null +++ b/src/main/java/malpull/exceptions/NoArgumentsSetException.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2021 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package malpull.exceptions; + +/** + * This exception is thrown when the arguments object is not set prior to the + * call a function that requires it. + * + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] + */ +public class NoArgumentsSetException extends Exception { + + public NoArgumentsSetException(String message) { + super(message); + } +} diff --git a/src/main/java/malpull/exceptions/NoHashesFoundException.java b/src/main/java/malpull/exceptions/NoHashesFoundException.java new file mode 100644 index 0000000..9086229 --- /dev/null +++ b/src/main/java/malpull/exceptions/NoHashesFoundException.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package malpull.exceptions; + +/** + * This exception is thrown if no hashes are provided + * + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] + */ +public class NoHashesFoundException extends Exception { + + public NoHashesFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/malpull/exceptions/NoServicesSetException.java b/src/main/java/malpull/exceptions/NoServicesSetException.java new file mode 100644 index 0000000..d117e6a --- /dev/null +++ b/src/main/java/malpull/exceptions/NoServicesSetException.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2021 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package malpull.exceptions; + +/** + * This exception is thrown if no services are set to use within MalPull + * + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] + */ +public class NoServicesSetException extends Exception { + + public NoServicesSetException(String message) { + super(message); + } +} diff --git a/src/main/java/exceptions/SampleNotFoundException.java b/src/main/java/malpull/exceptions/SampleNotFoundException.java similarity index 83% rename from src/main/java/exceptions/SampleNotFoundException.java rename to src/main/java/malpull/exceptions/SampleNotFoundException.java index 07c00fe..bf467d1 100644 --- a/src/main/java/exceptions/SampleNotFoundException.java +++ b/src/main/java/malpull/exceptions/SampleNotFoundException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * Copyright (C) 2020 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,13 +14,13 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package exceptions; +package malpull.exceptions; /** * This exception is used when the sample cannot be found in the malware * service's database * - * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] */ public class SampleNotFoundException extends Exception { diff --git a/src/main/java/malpull/Arguments.java b/src/main/java/malpull/model/Arguments.java similarity index 61% rename from src/main/java/malpull/Arguments.java rename to src/main/java/malpull/model/Arguments.java index f5008a3..05990d6 100644 --- a/src/main/java/malpull/Arguments.java +++ b/src/main/java/malpull/model/Arguments.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * Copyright (C) 2020 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,15 +14,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package malpull; +package malpull.model; import java.util.Set; +import malpull.exceptions.NoHashesFoundException; +import malpull.exceptions.NoServicesSetException; /** - * The argument class, which contains all relevant information from the parsed - * arguments + * The argument class, which contains all relevant information that MalPull + * requires * - * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] */ public class Arguments { @@ -30,32 +32,33 @@ public class Arguments { * The set that contains all loaded hashes */ private Set hashes; - + /** * The folder to write all samples to */ private String outputPath; - + /** * The amount of threads to use, minimally one */ private int threadCount; - + /** * The API key for Koodous */ private String koodousKey; - + /** - * The API key for Malware Bazaar is not required, meaning any value will enable downloading from this service + * The API key for Malware Bazaar is not required, meaning any value will + * enable downloading from this service */ private String malwareBazaarKey; - + /** * The API key for MalShare */ private String malShareKey; - + /** * The API key for VirusTotal */ @@ -68,16 +71,27 @@ public class Arguments { /** * Creates an object that contains all parsed arguments - * @param hashes all loaded hashes + * + * @param hashes all loaded hashes, cannot be null or empty * @param outputPath the folder to write the downloads to - * @param threadCount the amount of threads to use - * @param koodousKey the API key for Koodous - * @param malwareBazaarKey the API key for Malware Bazaar - * @param malShareKey the API key for MalShare - * @param virusTotalKey the API key for VirusTotal - * @param triageKey the API key for Triage - */ - public Arguments(Set hashes, String outputPath, int threadCount, String koodousKey, String malwareBazaarKey, String malShareKey, String virusTotalKey, String triageKey) { + * @param threadCount the amount of threads to use, a value of zero or lower + * will set the count to 1 + * @param koodousKey the API key for Koodous, null if the service is not to + * be used + * @param malwareBazaarKey the API key for Malware Bazaar, null if the + * service is not to be used + * @param malShareKey the API key for MalShare, null if the service is not + * to be used + * @param virusTotalKey the API key for VirusTotal, null if the service is + * not to be used + * @param triageKey the API key for Triage, null if the service is not to be + * used + * @throws NoServicesSetException if all of the API key strings are null at + * the same time, meaning no services will be reached + * @throws NoHashesFoundException if the given set of hashes is null or + * empty + */ + public Arguments(Set hashes, String outputPath, int threadCount, String koodousKey, String malwareBazaarKey, String malShareKey, String virusTotalKey, String triageKey) throws NoServicesSetException, NoHashesFoundException { this.hashes = hashes; this.outputPath = outputPath; this.threadCount = threadCount; @@ -86,10 +100,27 @@ public Arguments(Set hashes, String outputPath, int threadCount, String this.malShareKey = malShareKey; this.virusTotalKey = virusTotalKey; this.triageKey = triageKey; + + if (koodousKey == null + && malwareBazaarKey == null + && malShareKey == null + && virusTotalKey == null + && triageKey == null) { + throw new NoServicesSetException("No services have been set in the arguments object, as all API keys are null!"); + } + + if (hashes == null || hashes.isEmpty()) { + throw new NoHashesFoundException("No hashes are provided when creating the arguments object, given that the list is either null or empty!"); + } + + if (this.threadCount <= 0) { + this.threadCount = 1; + } } /** * Gets all loaded hashes without duplicates + * * @return all loaded hashes */ public Set getHashes() { @@ -98,6 +129,7 @@ public Set getHashes() { /** * Get the output folder where the downloads should be written to + * * @return the path to the output folder */ public String getOutputPath() { @@ -106,6 +138,7 @@ public String getOutputPath() { /** * Get the given thread count to use when downloading samples + * * @return the thread count */ public int getThreadCount() { @@ -114,6 +147,7 @@ public int getThreadCount() { /** * Get the API key of Koodous, can be null if the API key is not used + * * @return the API key */ public String getKoodousKey() { @@ -121,7 +155,10 @@ public String getKoodousKey() { } /** - * The API key of Malware Bazaar does not exist, so this value is either null or not null. Exclusion from the keys file means the service wont be used + * The API key of Malware Bazaar does not exist, so this value is either + * null or not null. Exclusion from the keys file means the service wont be + * used + * * @return a value to see if this endpoint is to be used */ public String getMalwareBazaarKey() { @@ -130,6 +167,7 @@ public String getMalwareBazaarKey() { /** * Gets the API key of MalShare, can be null if the API key is not used + * * @return the API key */ public String getMalShareKey() { @@ -138,6 +176,7 @@ public String getMalShareKey() { /** * The API key of VirusTotal, can be null if the API key is not used + * * @return the API key */ public String getVirusTotalKey() { @@ -146,6 +185,7 @@ public String getVirusTotalKey() { /** * The API key of Triage, can be null if the API key is not used + * * @return the API key */ public String getTriageKey() { diff --git a/src/main/java/malpull/model/MalPullResult.java b/src/main/java/malpull/model/MalPullResult.java new file mode 100644 index 0000000..a6a2be5 --- /dev/null +++ b/src/main/java/malpull/model/MalPullResult.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2021 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package malpull.model; + +import java.util.List; +import java.util.Map; + +/** + * A class to contain all download related results, which is returned once all + * downloads have been completed + * + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] + */ +public class MalPullResult { + + private Map downloadedSamples; + private List missingHashes; + private String time; + + public MalPullResult(Map downloadedSamples, List missingHashes, String time) { + this.downloadedSamples = downloadedSamples; + this.missingHashes = missingHashes; + this.time = time; + } + + public Map getDownloadedSamples() { + return downloadedSamples; + } + + public List getMissingHashes() { + return missingHashes; + } + + public String getTime() { + return time; + } +} diff --git a/src/main/java/malpull/Downloader.java b/src/main/java/malpull/network/MalPullConnector.java similarity index 87% rename from src/main/java/malpull/Downloader.java rename to src/main/java/malpull/network/MalPullConnector.java index 0d30bac..7fd00a6 100644 --- a/src/main/java/malpull/Downloader.java +++ b/src/main/java/malpull/network/MalPullConnector.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * Copyright (C) 2020 Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,9 +14,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package malpull; +package malpull.network; -import exceptions.SampleNotFoundException; +import malpull.exceptions.SampleNotFoundException; import java.io.IOException; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -30,9 +30,9 @@ * that contact the API endpoints can contain the logic for the API, and this * code can be reused within all services. * - * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * @author Max 'Libra' Kersten [@Libranalysis, https://maxkersten.nl] */ -public class Downloader { +public class MalPullConnector { /** * The HTTP client that sends out the request @@ -40,10 +40,10 @@ public class Downloader { protected final OkHttpClient httpClient; /** - * Creates the Downloader object, via which GET and POST requests can be + * Creates the connector object, via which GET and POST requests can be * sent to a given address */ - public Downloader() { + public MalPullConnector() { httpClient = new OkHttpClient(); } @@ -73,7 +73,7 @@ public byte[] post(String url, RequestBody requestBody) throws SampleNotFoundExc //Return response body return response.body().bytes(); } catch (IOException e) { - throw new SampleNotFoundException("IOException in Dowlnoader.post for " + request.url()); + throw new SampleNotFoundException("IOException in Downloader.post for " + request.url() + ". Error:\n" + e.getMessage()); } } @@ -96,7 +96,7 @@ public byte[] get(Request request) throws SampleNotFoundException { //Return response body return response.body().bytes(); } catch (IOException e) { - throw new SampleNotFoundException("IOException in Dowlnoader.get for " + request.url()); + throw new SampleNotFoundException("IOException in Dowlnoader.get for " + request.url() + ". Error:\n" + e.getMessage()); } } } diff --git a/target/MalPull-1.2.1-stable.jar b/target/MalPull-1.2.1-stable.jar deleted file mode 100644 index 63458e0..0000000 Binary files a/target/MalPull-1.2.1-stable.jar and /dev/null differ diff --git a/target/MalPull-1.2.1-stable-jar-with-dependencies.jar b/target/MalPull-1.3-stable-jar-with-dependencies.jar similarity index 87% rename from target/MalPull-1.2.1-stable-jar-with-dependencies.jar rename to target/MalPull-1.3-stable-jar-with-dependencies.jar index 5e18b99..e8f9bd6 100644 Binary files a/target/MalPull-1.2.1-stable-jar-with-dependencies.jar and b/target/MalPull-1.3-stable-jar-with-dependencies.jar differ diff --git a/target/MalPull-1.3-stable-javadoc.jar b/target/MalPull-1.3-stable-javadoc.jar new file mode 100644 index 0000000..f5c94b3 Binary files /dev/null and b/target/MalPull-1.3-stable-javadoc.jar differ diff --git a/target/MalPull-1.3-stable-sources.jar b/target/MalPull-1.3-stable-sources.jar new file mode 100644 index 0000000..257dce1 Binary files /dev/null and b/target/MalPull-1.3-stable-sources.jar differ diff --git a/target/MalPull-1.3-stable.jar b/target/MalPull-1.3-stable.jar new file mode 100644 index 0000000..9b93462 Binary files /dev/null and b/target/MalPull-1.3-stable.jar differ diff --git a/target/apidocs.zip b/target/apidocs.zip new file mode 100644 index 0000000..d55532e Binary files /dev/null and b/target/apidocs.zip differ