From 474c5a143f6c94a72439a013cc1266eb253e42ef Mon Sep 17 00:00:00 2001 From: SendSafely Date: Fri, 18 Jan 2019 11:31:37 -0500 Subject: [PATCH] v3.1.0 --- .../src/com/sendsafely/SendSafely.java | 16 +- .../GetDownloadUrlsFromDirectoryRequest.java | 45 ++++ .../dto/request/GetDownloadUrlsRequest.java | 38 ++++ .../dto/response/GetDownloadUrlsResponse.java | 18 ++ .../exceptions/GetDownloadUrlsException.java | 22 ++ .../DownloadAndDecryptFileHandler.java | 148 ++++++++++++- .../handlers/DownloadFileHandler.java | 38 +++- .../handlers/GetDownloadUrlsHandler.java | 115 ++++++++++ .../handlers/PackageInformationHandler.java | 2 +- .../sendsafely/upload/S3UploadManager.java | 205 ++++++++++++++++++ .../com/sendsafely/upload/UploadFactory.java | 5 + .../src/com/sendsafely/utils/SendUtil.java | 2 +- 12 files changed, 637 insertions(+), 17 deletions(-) create mode 100644 SendSafelyAPI/src/com/sendsafely/dto/request/GetDownloadUrlsFromDirectoryRequest.java create mode 100644 SendSafelyAPI/src/com/sendsafely/dto/request/GetDownloadUrlsRequest.java create mode 100644 SendSafelyAPI/src/com/sendsafely/dto/response/GetDownloadUrlsResponse.java create mode 100644 SendSafelyAPI/src/com/sendsafely/exceptions/GetDownloadUrlsException.java create mode 100644 SendSafelyAPI/src/com/sendsafely/handlers/GetDownloadUrlsHandler.java create mode 100644 SendSafelyAPI/src/com/sendsafely/upload/S3UploadManager.java diff --git a/SendSafelyAPI/src/com/sendsafely/SendSafely.java b/SendSafelyAPI/src/com/sendsafely/SendSafely.java index 9a2ac6d..5e1557f 100644 --- a/SendSafelyAPI/src/com/sendsafely/SendSafely.java +++ b/SendSafelyAPI/src/com/sendsafely/SendSafely.java @@ -147,6 +147,8 @@ public class SendSafely { protected double version = 0.3; + private boolean ec2Proxy = false; + /** * @description Constructor to create a new SendSafely object. * @param host The hostname you use to access SendSafely. Should be https://companyname.sendsafely.com or https://www.sendsafely.com @@ -216,6 +218,10 @@ public SendSafely(String host) { this(host, (ConnectionManager)null, (CredentialsManager)null); } + public void setEc2Proxy (boolean isProxy) { + this.ec2Proxy = isProxy; + } + /** * @description Add Contact Group as a recipient on a package. * @param packageId The unique package id of the package for the add the Contact Group operation. @@ -435,7 +441,7 @@ public void deletePackage(String packageId) throws DeletePackageException */ public java.io.File downloadFile(String packageId, String fileId, String keyCode) throws DownloadFileException, PasswordRequiredException { - return downloadFile(packageId, fileId, keyCode, null, (String)null); + return downloadFile(packageId, fileId, keyCode, new DefaultProgress()); } /** @@ -452,7 +458,7 @@ public java.io.File downloadFile(String packageId, String fileId, String keyCode public java.io.File downloadFile(String packageId, String fileId, String keyCode, ProgressInterface progress) throws DownloadFileException, PasswordRequiredException { DownloadAndDecryptFileHandler handler = new DownloadAndDecryptFileHandler(uploadManager); - return handler.makeRequest(packageId, null, fileId, keyCode, progress, null); + return handler.makeRequestS3(packageId, null, fileId, keyCode, progress, null, ec2Proxy); } /** @@ -485,7 +491,6 @@ public java.io.File downloadFile(String packageId, String fileId, String keyCode return handler.makeRequest(packageId, null, fileId, keyCode, progress, password); } - /** * @description Downloads a file from the server and decrypts it. * @param packageId The unique package id of the package for the file download operation. @@ -499,7 +504,8 @@ public java.io.File downloadFile(String packageId, String fileId, String keyCode */ public java.io.File downloadFile(String packageId, String fileId, String keyCode, String password) throws DownloadFileException, PasswordRequiredException { - return downloadFile(packageId, fileId, keyCode, null, password); + DownloadAndDecryptFileHandler handler = new DownloadAndDecryptFileHandler(uploadManager); + return handler.makeRequest(packageId, null, fileId, keyCode, null, password); } /** @@ -531,7 +537,7 @@ public java.io.File downloadFileFromDirectory(String packageId, String directory */ public java.io.File downloadFileFromDirectory(String packageId, String directoryId, String fileId, String keyCode, ProgressInterface progress) throws DownloadFileException, PasswordRequiredException { DownloadAndDecryptFileHandler handler = new DownloadAndDecryptFileHandler(uploadManager); - return handler.makeRequest(packageId, directoryId, fileId, keyCode, progress); + return handler.makeRequestS3(packageId, directoryId, fileId, keyCode, progress, (String)null, ec2Proxy); } /** diff --git a/SendSafelyAPI/src/com/sendsafely/dto/request/GetDownloadUrlsFromDirectoryRequest.java b/SendSafelyAPI/src/com/sendsafely/dto/request/GetDownloadUrlsFromDirectoryRequest.java new file mode 100644 index 0000000..f35fc68 --- /dev/null +++ b/SendSafelyAPI/src/com/sendsafely/dto/request/GetDownloadUrlsFromDirectoryRequest.java @@ -0,0 +1,45 @@ +package com.sendsafely.dto.request; + +import com.sendsafely.enums.GetParam; +import com.sendsafely.enums.HTTPMethod; +import com.sendsafely.json.JsonManager; + +public class GetDownloadUrlsFromDirectoryRequest extends BaseRequest { + + private HTTPMethod method = HTTPMethod.POST; + private String path = "/package/" + GetParam.PACKAGE_ID + "/directory/" + GetParam.DIRECTORY_ID + "/file/" + GetParam.FILE_ID + "/download-urls/"; + + public GetDownloadUrlsFromDirectoryRequest(JsonManager jsonManager){ + initialize(jsonManager, method, path); + } + + public void setPackageId(String packageId) { + super.setGetParam(GetParam.PACKAGE_ID, packageId); + } + + public void setFileId(String fileId) { + super.setGetParam(GetParam.FILE_ID, fileId); + } + + public void setDirectoryId(String directoryId){ + super.setGetParam(GetParam.DIRECTORY_ID, directoryId); + } + + public void setStartSegment(int start) { + super.setPostParam("startSegment", start); + } + + public void setEndSegment(int end) { + super.setPostParam("endSegment", end); + } + public void setPackageCode(String packageCode){ + super.setPostParam("packageCode", packageCode); + } + public void setChecksum(String checksum){ + super.setPostParam("checksum", checksum); + } + public void setForceProxy(boolean forceProxy){ + super.setPostParam("forceProxy", forceProxy); + } + +} \ No newline at end of file diff --git a/SendSafelyAPI/src/com/sendsafely/dto/request/GetDownloadUrlsRequest.java b/SendSafelyAPI/src/com/sendsafely/dto/request/GetDownloadUrlsRequest.java new file mode 100644 index 0000000..c0ecfd0 --- /dev/null +++ b/SendSafelyAPI/src/com/sendsafely/dto/request/GetDownloadUrlsRequest.java @@ -0,0 +1,38 @@ +package com.sendsafely.dto.request; + +import com.sendsafely.enums.GetParam; +import com.sendsafely.enums.HTTPMethod; +import com.sendsafely.json.JsonManager; + +public class GetDownloadUrlsRequest extends BaseRequest { + + private HTTPMethod method = HTTPMethod.POST; + private String path = "/package/" + GetParam.PACKAGE_ID + "/file/" + GetParam.FILE_ID + "/download-urls/"; + + public GetDownloadUrlsRequest(JsonManager jsonManager){ + initialize(jsonManager, method, path); + } + + public void setPackageId(String packageId) { + super.setGetParam(GetParam.PACKAGE_ID, packageId); + } + + public void setFileId(String fileId) { + super.setGetParam(GetParam.FILE_ID, fileId); + } + + public void setStartSegment(int start) { + super.setPostParam("startSegment", start); + } + + public void setEndSegment(int end) { + super.setPostParam("endSegment", end); + } + + public void setChecksum(String checksum){ + super.setPostParam("checksum", checksum); + } + public void setForceProxy(boolean forceProxy){ + super.setPostParam("forceProxy", forceProxy); + } +} \ No newline at end of file diff --git a/SendSafelyAPI/src/com/sendsafely/dto/response/GetDownloadUrlsResponse.java b/SendSafelyAPI/src/com/sendsafely/dto/response/GetDownloadUrlsResponse.java new file mode 100644 index 0000000..a5ec0d2 --- /dev/null +++ b/SendSafelyAPI/src/com/sendsafely/dto/response/GetDownloadUrlsResponse.java @@ -0,0 +1,18 @@ +package com.sendsafely.dto.response; + +import java.util.List; +import java.util.Map; + +public class GetDownloadUrlsResponse extends BaseResponse { + + private List> downloadUrls; + + public List> getDownloadUrls() { + return downloadUrls; + } + + public void setDownloadUrls(List> downloadUrls) { + this.downloadUrls = downloadUrls; + } + +} \ No newline at end of file diff --git a/SendSafelyAPI/src/com/sendsafely/exceptions/GetDownloadUrlsException.java b/SendSafelyAPI/src/com/sendsafely/exceptions/GetDownloadUrlsException.java new file mode 100644 index 0000000..3c37361 --- /dev/null +++ b/SendSafelyAPI/src/com/sendsafely/exceptions/GetDownloadUrlsException.java @@ -0,0 +1,22 @@ +package com.sendsafely.exceptions; + +public class GetDownloadUrlsException extends Exception { + + /** + * + */ + private static final long serialVersionUID = 1L; + + String error; + + public GetDownloadUrlsException(Exception e) { + super(e); + error = e.getMessage(); + } + + public GetDownloadUrlsException(String err){ + super(err); + error = err; + } + +} diff --git a/SendSafelyAPI/src/com/sendsafely/handlers/DownloadAndDecryptFileHandler.java b/SendSafelyAPI/src/com/sendsafely/handlers/DownloadAndDecryptFileHandler.java index 3d62d54..e54f588 100644 --- a/SendSafelyAPI/src/com/sendsafely/handlers/DownloadAndDecryptFileHandler.java +++ b/SendSafelyAPI/src/com/sendsafely/handlers/DownloadAndDecryptFileHandler.java @@ -5,25 +5,33 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; import java.util.Timer; import com.sendsafely.Directory; import com.sendsafely.File; import com.sendsafely.Package; import com.sendsafely.ProgressInterface; +import com.sendsafely.connection.ConnectionFactory; +import com.sendsafely.connection.ConnectionManager; import com.sendsafely.enums.Endpoint; import com.sendsafely.exceptions.DirectoryOperationFailedException; import com.sendsafely.exceptions.DownloadFileException; +import com.sendsafely.exceptions.GetDownloadUrlsException; +import com.sendsafely.exceptions.LimitExceededException; import com.sendsafely.exceptions.PackageInformationFailedException; import com.sendsafely.exceptions.PasswordRequiredException; import com.sendsafely.progress.DefaultProgress; +import com.sendsafely.upload.UploadFactory; import com.sendsafely.upload.UploadManager; +import com.sendsafely.utils.CryptoUtil; import com.sendsafely.utils.Progress; public class DownloadAndDecryptFileHandler extends BaseHandler { - private final int RETRY_ATTEMPTS = 10; - private final int RETRY_SLEEP_INCREMENT = 5000; + private final int RETRY_ATTEMPTS = 5; + private final int RETRY_SLEEP_INCREMENT = 3000; private Package packageInfo; private String fileId; private String directoryId; @@ -35,6 +43,7 @@ public DownloadAndDecryptFileHandler(UploadManager uploadManager) { super(uploadManager); } + @Deprecated public java.io.File makeRequest(String packageId, String fileId, String keyCode, ProgressInterface progress, String password) throws DownloadFileException, PasswordRequiredException { this.fileId = fileId; this.password = password; @@ -51,6 +60,7 @@ public java.io.File makeRequest(String packageId, String fileId, String keyCode, return downloadFile(systemFile, fileToDownload); } + @Deprecated public java.io.File makeRequest(String packageId, String directoryId, String fileId, String keyCode, ProgressInterface progress) throws DownloadFileException, PasswordRequiredException { this.fileId = fileId; this.directoryId = directoryId; @@ -68,7 +78,7 @@ public java.io.File makeRequest(String packageId, String directoryId, String fil return downloadFile(systemFile, fileToDownload); } - + @Deprecated public java.io.File makeRequest(String packageId, String directoryId, String fileId, String keyCode, ProgressInterface progress, String password) throws DownloadFileException, PasswordRequiredException { this.fileId = fileId; @@ -91,7 +101,42 @@ public java.io.File makeRequest(String packageId, String directoryId, String fil return downloadFile(systemFile, fileToDownload); } -private Directory getDirectoryInfo(String packageId, String directoryId) throws DownloadFileException { + public java.io.File makeRequestS3(String packageId, String directoryId, String fileId, String keyCode, + ProgressInterface progress, String password, boolean forceProxy) throws DownloadFileException, PasswordRequiredException { + this.fileId = fileId; + this.directoryId = directoryId; + this.password = password; + setupProgress(progress); + + if (directoryId != null) + this.directoryInfo = getDirectoryInfo(packageId, directoryId); + + // Get the file information + this.packageInfo = getPackageInfo(packageId); + this.packageInfo.setKeyCode(keyCode); + + File fileToDownload = findFile(); + java.io.File systemFile = getSystemFile(fileToDownload); + + // Download the file + java.io.File file = null; + try { + file = downloadFileFromS3(systemFile, fileToDownload, forceProxy); + } catch (GetDownloadUrlsException e) { + throw new DownloadFileException("Unable to get download URLs"); + } catch (LimitExceededException e){ + try { + file = downloadFileFromS3(systemFile, fileToDownload, true, Integer.parseInt(e.getMessage().toString())); + } catch (GetDownloadUrlsException | LimitExceededException e1) { + throw new DownloadFileException("Unable to get download URLs"); + } + }catch(Exception e){ + throw new DownloadFileException(e); + } + return file; + } + + private Directory getDirectoryInfo(String packageId, String directoryId) throws DownloadFileException { GetDirectoryHandler handler = ((GetDirectoryHandler)HandlerFactory.getInstance(uploadManager, Endpoint.GET_DIRECTORY)); try{ @@ -125,6 +170,7 @@ private Package getPackageInfo(String packageId) throws DownloadFileException } } + @Deprecated private java.io.File downloadFile(java.io.File outFile, File ssFile) throws DownloadFileException, PasswordRequiredException { Progress progress = new Progress(this.progress, ssFile.getFileId()); @@ -186,8 +232,102 @@ private java.io.File downloadFile(java.io.File outFile, File ssFile) throws Down return outFile; } + private java.io.File downloadFileFromS3(java.io.File systemFile, File fileToDownload, boolean forceProxy) throws DownloadFileException, PasswordRequiredException, GetDownloadUrlsException, LimitExceededException { + return downloadFileFromS3(systemFile, fileToDownload, forceProxy, 0); + } + private java.io.File downloadFileFromS3(java.io.File outFile, File ssFile, boolean forceProxy, int filePart) throws DownloadFileException, PasswordRequiredException, GetDownloadUrlsException, LimitExceededException { + + Progress progress = new Progress(this.progress, ssFile.getFileId()); + progress.setTotal(ssFile.getFileSize()); + progress.resetCurrent(); + + Timer timer = startTimer(progress); + + int failCounter = 0; + OutputStream output = getOutputStream(outFile); + try{ + int part; + if(filePart>0){ + part = filePart; + }else{ + part = 1; + } + + GetDownloadUrlsHandler urlHandler = new GetDownloadUrlsHandler(uploadManager,ssFile.getParts()); + String checksum = calculateChecksum(packageInfo.getPackageCode(), packageInfo.getKeyCode()); + urlHandler.fetchDownloadUrls(packageInfo.getPackageId(), ssFile.getFileId(), this.directoryId, part, forceProxy, checksum);//do we need password here? + + while (!urlHandler.getCurrentDownloadUrls().isEmpty()) { + + String downloadUrl = urlHandler.getCurrentDownloadUrls().get(0).get("url"); + //This is the fail/retry loop (on any exception) + for (failCounter = 0; failCounter <= RETRY_ATTEMPTS; failCounter++) + { + try + { + InputStream stream; + if(forceProxy){ + DownloadFileHandler proxyHandler = new DownloadFileHandler(uploadManager); + stream = proxyHandler.makeRequest(downloadUrl, packageInfo, part, password); + + }else{ + URL u = new URL(downloadUrl); + ConnectionManager connection = ConnectionFactory.getDefaultManager(u.getHost()); + DownloadFileHandler s3Handler = new DownloadFileHandler(UploadFactory.getManagerS3(connection)); + stream = s3Handler.makeRequest(downloadUrl); + } + decrypt(stream, output, progress); + break; + } + catch(DownloadFileException e) + { + if(failCounter == RETRY_ATTEMPTS && !forceProxy){ + //limit exceeded, caller should catch this exception and try again. + throw new LimitExceededException(Integer.toString(part)); + } + if(failCounter == RETRY_ATTEMPTS) + { + outFile.delete(); + throw new DownloadFileException(e); + } + + //Download failed...retrying in sleepInterval milliseconds (increases on each failure) + int sleepInterval = failCounter * RETRY_SLEEP_INCREMENT; + + try + { + Thread.sleep(sleepInterval); + } + catch (InterruptedException e1) + { + throw new DownloadFileException(e); + } + } catch (MalformedURLException e) { + throw new DownloadFileException(e); + } + } + urlHandler.removeUrl(); + part++; + urlHandler.fetchDownloadUrls(packageInfo.getPackageId(), ssFile.getFileId(), this.directoryId, part, forceProxy, checksum); + } + }catch(LimitExceededException e){ + throw new LimitExceededException(e.getMessage()); + } + finally + { + closeStream(output); + progress.finished(); + stopTimer(timer); + } + return outFile; + } + private String calculateChecksum(String packageCode, String keycode) + { + return CryptoUtil.createChecksum(keycode, packageCode); + } + private void stopTimer(Timer timer) { timer.cancel(); diff --git a/SendSafelyAPI/src/com/sendsafely/handlers/DownloadFileHandler.java b/SendSafelyAPI/src/com/sendsafely/handlers/DownloadFileHandler.java index 344d558..0463f7c 100644 --- a/SendSafelyAPI/src/com/sendsafely/handlers/DownloadFileHandler.java +++ b/SendSafelyAPI/src/com/sendsafely/handlers/DownloadFileHandler.java @@ -8,6 +8,7 @@ import com.sendsafely.dto.request.DownloadFileRequest; import com.sendsafely.dto.response.DownloadFileResponse; import com.sendsafely.enums.APIResponse; +import com.sendsafely.enums.HTTPMethod; import com.sendsafely.exceptions.DownloadFileException; import com.sendsafely.exceptions.PasswordRequiredException; import com.sendsafely.exceptions.SendFailedException; @@ -23,15 +24,31 @@ public class DownloadFileHandler extends BaseHandler private String checksum; private String password; private int part; + private String path; public DownloadFileHandler(UploadManager uploadManager) { super(uploadManager); } - - public InputStream makeRequest(Package packageInfo, String fileId, int part) throws DownloadFileException, PasswordRequiredException { - return makeRequest(packageInfo, fileId, part, null); + + public InputStream makeRequest(String url) throws DownloadFileException { + DownloadFileResponse response = downloadFile(new DownloadFileRequest(uploadManager.getJsonManager(), HTTPMethod.GET, url)); + if(response.getResponse() == APIResponse.SUCCESS) { + return response.getFileStream(); + } else { + throw new DownloadFileException("Server returned error message: " + response.getResponse() + " " + response.getMessage()); + } + } + + public InputStream makeRequest(String path, Package packageInfo, int part, String password) throws DownloadFileException, PasswordRequiredException { + this.path = path; + this.packageInfo = packageInfo; + this.part = part; + this.password = password; + + return downloadFile(); } + @Deprecated public InputStream makeRequest(Package packageInfo, String fileId, int part, String password) throws DownloadFileException, PasswordRequiredException { this.fileId = fileId; this.packageInfo = packageInfo; @@ -41,6 +58,7 @@ public InputStream makeRequest(Package packageInfo, String fileId, int part, Str return downloadFile(); } + @Deprecated public InputStream makeRequest(Package packageInfo, String directoryId, String fileId, int part, String password) throws DownloadFileException, PasswordRequiredException { this.fileId = fileId; this.directoryId = directoryId; @@ -67,6 +85,7 @@ private InputStream downloadFile() throws DownloadFileException, PasswordRequire } } + @Deprecated private InputStream downloadFile(String directoryId) throws DownloadFileException, PasswordRequiredException { this.checksum = calculateChecksum(packageInfo.getPackageCode(), packageInfo.getKeyCode()); DownloadFileFromDirectoryRequest request = createRequest(directoryId, part); @@ -83,8 +102,13 @@ private InputStream downloadFile(String directoryId) throws DownloadFileExceptio private DownloadFileRequest createRequest(int part) { DownloadFileRequest request = new DownloadFileRequest(uploadManager.getJsonManager()); - request.setPackageId(packageInfo.getPackageId()); - request.setFileId(fileId); + if (path != null) { + request = new DownloadFileRequest(uploadManager.getJsonManager(),HTTPMethod.POST, path); + } else { + request.setPackageId(packageInfo.getPackageId()); + request.setFileId(fileId); + } + request.setChecksum(checksum); request.setPart(part); request.setApi(DOWNLOAD_API); @@ -96,6 +120,7 @@ private DownloadFileRequest createRequest(int part) return request; } + @Deprecated private DownloadFileFromDirectoryRequest createRequest(String directoryId, int part) { DownloadFileFromDirectoryRequest request = new DownloadFileFromDirectoryRequest(uploadManager.getJsonManager()); @@ -124,6 +149,7 @@ private DownloadFileResponse downloadFile(DownloadFileRequest request) throws Do } } + @Deprecated private DownloadFileResponse downloadFile(DownloadFileFromDirectoryRequest request) throws DownloadFileException { try { @@ -138,5 +164,5 @@ private DownloadFileResponse downloadFile(DownloadFileFromDirectoryRequest reque private String calculateChecksum(String packageCode, String keycode) { return CryptoUtil.createChecksum(keycode, packageCode); - } + } } diff --git a/SendSafelyAPI/src/com/sendsafely/handlers/GetDownloadUrlsHandler.java b/SendSafelyAPI/src/com/sendsafely/handlers/GetDownloadUrlsHandler.java new file mode 100644 index 0000000..db1c3b6 --- /dev/null +++ b/SendSafelyAPI/src/com/sendsafely/handlers/GetDownloadUrlsHandler.java @@ -0,0 +1,115 @@ +package com.sendsafely.handlers; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.sendsafely.dto.request.BaseRequest; +import com.sendsafely.dto.request.GetDownloadUrlsFromDirectoryRequest; +import com.sendsafely.dto.request.GetDownloadUrlsRequest; +import com.sendsafely.dto.response.GetDownloadUrlsResponse; +import com.sendsafely.enums.APIResponse; +import com.sendsafely.exceptions.GetDownloadUrlsException; +import com.sendsafely.exceptions.SendFailedException; +import com.sendsafely.upload.UploadManager; + +public class GetDownloadUrlsHandler extends BaseHandler { + + private BaseRequest request; + private int totalFileParts; + private int totalDownloadUrlsFetched = 0; + private List> downloadUrls; + private static int MAX_URL_BATCH_SIZE = 25; + private static int URL_REFRESH_LIMIT = 10; + + public GetDownloadUrlsHandler(UploadManager uploadManager, int totalFileParts) { + super(uploadManager); + this.totalFileParts = totalFileParts; + this.downloadUrls = new ArrayList>(); + } + + public void fetchDownloadUrls(String packageId, String fileId, String directoryId, int filePart, boolean forceProxy, String checksum) throws GetDownloadUrlsException { + + int urlBatchSize = 0; + + if (filePart == 1) { + urlBatchSize = (this.totalFileParts < MAX_URL_BATCH_SIZE) ? this.totalFileParts : MAX_URL_BATCH_SIZE; + if(directoryId!=null){ + createRequest(packageId,fileId,directoryId,filePart,urlBatchSize, forceProxy, checksum); + }else{ + createRequest(packageId,fileId,filePart,urlBatchSize, forceProxy, checksum); + } + makeRequest(); + } else if (filePart == (totalDownloadUrlsFetched - URL_REFRESH_LIMIT)) { + //Refresh limit hit. Do we need more URLs? + int urlsRemaining = this.totalFileParts - this.totalDownloadUrlsFetched; + if (urlsRemaining > 0) { + urlBatchSize = (urlsRemaining < MAX_URL_BATCH_SIZE) ? urlsRemaining : MAX_URL_BATCH_SIZE; + if(directoryId!=null){ + createRequest(packageId,fileId,directoryId,totalDownloadUrlsFetched+1,totalDownloadUrlsFetched+urlBatchSize, forceProxy, checksum); + }else{ + createRequest(packageId,fileId,totalDownloadUrlsFetched+1,totalDownloadUrlsFetched+urlBatchSize, forceProxy, checksum); + } + makeRequest(); + } + } else { + //No new URLs need to be fetched + } + } + + private void makeRequest() throws GetDownloadUrlsException { + + GetDownloadUrlsResponse response = send(); + if(response.getResponse() == APIResponse.SUCCESS) + { + this.totalDownloadUrlsFetched+=response.getDownloadUrls().size(); + this.downloadUrls.addAll(response.getDownloadUrls()); + } + else + { + throw new GetDownloadUrlsException(response.getMessage()); + } + + } + + private void createRequest (String packageId, String fileId, int startSegment, int endSegment, boolean forceProxy, String checksum) { + + this.request = new GetDownloadUrlsRequest(this.uploadManager.getJsonManager()); + ((GetDownloadUrlsRequest) request).setPackageId(packageId); + ((GetDownloadUrlsRequest) request).setFileId(fileId); + ((GetDownloadUrlsRequest) request).setStartSegment(startSegment); + ((GetDownloadUrlsRequest) request).setEndSegment(endSegment); + ((GetDownloadUrlsRequest) request).setChecksum(checksum); + ((GetDownloadUrlsRequest) request).setForceProxy(forceProxy); + } + private void createRequest (String packageId, String fileId, String directoryId, int startSegment, int endSegment, boolean forceProxy, String checksum) { + + this.request = new GetDownloadUrlsFromDirectoryRequest(this.uploadManager.getJsonManager()); + ((GetDownloadUrlsFromDirectoryRequest) request).setPackageId(packageId); + ((GetDownloadUrlsFromDirectoryRequest) request).setFileId(fileId); + ((GetDownloadUrlsFromDirectoryRequest) request).setStartSegment(startSegment); + ((GetDownloadUrlsFromDirectoryRequest) request).setEndSegment(endSegment); + ((GetDownloadUrlsFromDirectoryRequest) request).setChecksum(checksum); + ((GetDownloadUrlsFromDirectoryRequest) request).setDirectoryId(directoryId); + ((GetDownloadUrlsFromDirectoryRequest) request).setForceProxy(forceProxy); + } + + public void removeUrl() { + this.downloadUrls.remove(0); + } + + public List> getCurrentDownloadUrls () { + return this.downloadUrls; + } + + protected GetDownloadUrlsResponse send() throws GetDownloadUrlsException{ + try { + return send(request, new GetDownloadUrlsResponse()); + } catch (SendFailedException e) { + throw new GetDownloadUrlsException(e); + } catch (IOException e) { + throw new GetDownloadUrlsException(e); + } + } +} diff --git a/SendSafelyAPI/src/com/sendsafely/handlers/PackageInformationHandler.java b/SendSafelyAPI/src/com/sendsafely/handlers/PackageInformationHandler.java index 262ebc2..e720e5a 100644 --- a/SendSafelyAPI/src/com/sendsafely/handlers/PackageInformationHandler.java +++ b/SendSafelyAPI/src/com/sendsafely/handlers/PackageInformationHandler.java @@ -205,4 +205,4 @@ private URL createUrl(String link) throws PackageInformationFailedException { } } -} +} \ No newline at end of file diff --git a/SendSafelyAPI/src/com/sendsafely/upload/S3UploadManager.java b/SendSafelyAPI/src/com/sendsafely/upload/S3UploadManager.java new file mode 100644 index 0000000..f6b3ffb --- /dev/null +++ b/SendSafelyAPI/src/com/sendsafely/upload/S3UploadManager.java @@ -0,0 +1,205 @@ +package com.sendsafely.upload; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.net.MalformedURLException; +import java.net.URL; + +import com.sendsafely.connection.ConnectionManager; +import com.sendsafely.credentials.CredentialsManager; +import com.sendsafely.enums.HTTPMethod; +import com.sendsafely.exceptions.CredentialsException; +import com.sendsafely.exceptions.SendFailedException; +import com.sendsafely.file.FileManager; +import com.sendsafely.json.JsonManager; +import com.sendsafely.utils.Progress; + +public class S3UploadManager implements UploadManager { + + private final String CONTENT_TYPE = "application/octet-stream"; + private final String FILE_UPLOAD_CONTENT_TYPE = "multipart/form-data;"; + private final String CRLF = "\r\n"; + private final int BUFFER_SIZE = 1024; + + private CredentialsManager credentialsManager; + private ConnectionManager conn; + private JsonManager jsonManager; + private InputStream content; + private String responseVal = ""; + + private String server; + private String date; + private int responseCode; + private String responseMessage; + private String responseContentType; + private String etc; + + public S3UploadManager(ConnectionManager connManager, JsonManager jsonManager) + { + this.conn = connManager; + this.jsonManager = jsonManager; + } + + @Override + public void send(String path, HTTPMethod method, String data) throws SendFailedException, IOException + { + URL url = new URL(path); + conn.open(url); + this.date = conn.getHeader("Date"); + this.server = conn.getHeader("Server"); + this.responseCode = conn.getResponseCode(); + this.responseMessage = conn.getResponseMessage(); + this.responseContentType = conn.getContentType(); + this.content = conn.getResponse(); + } + + @Override + public String sendFile(String path, FileManager file, String filename, String data, Progress progress) throws SendFailedException, IOException + { + URL url = createUrl(path); + + String boundary = Long.toHexString(System.currentTimeMillis()); + + conn.open(url); + + addCredentials(data); + + // Set api key header. + String contentType = FILE_UPLOAD_CONTENT_TYPE + " boundary=" + boundary; + populateHeaders("POST", contentType); + + OutputStream output = conn.getOutputStream(); + + PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, "UTF-8"), true); // true, autoflush + + setParam("requestData", data, boundary, writer); + + sendBinaryFile(filename, file.getInputStream(), output, writer, boundary, progress); + + // End of multipart/form-data. + writer.append("--" + boundary + "--").append(CRLF); + writer.flush(); + + this.content = conn.getResponse(); + String responseVal = getResponse(); + return responseVal; + } + + + + @Override + public String getResponse() throws IOException + { + // Wait for response + BufferedReader in = new BufferedReader(new InputStreamReader(this.content)); + String responseVal = ""; + String line = null; + while((line = in.readLine()) != null) + { + responseVal += line; + } + + return responseVal; + } + + @Override + public JsonManager getJsonManager() { + return this.jsonManager; + } + + @Override + public String getContentType() { + return conn.getHeader("Content-Type"); + } + + @Override + public InputStream getStream() { + return this.content; + } + + + @Override + public String getServer() { + return server; + } + @Override + public String getDate() { + return date; + } + @Override + public int getResponseCode() { + return responseCode; + } + @Override + public String getResponseMessage() { + return responseMessage; + } + + public String getApiHost() { + return conn.getHost(); + } + + private URL createUrl(String path) throws SendFailedException + { + try { + return new URL(conn.getHost() + credentialsManager.getAPIPath() + path); + } catch (MalformedURLException e) { + throw new SendFailedException(e); + } + } + + private void sendBinaryFile(String filename, InputStream input, OutputStream output, PrintWriter writer, String boundary, Progress progress) throws IOException { + + writer.append("--" + boundary).append(CRLF); + writer.append("Content-Disposition: form-data; name=\"textFile\"; filename=\"" + filename + "\"").append(CRLF); + writer.append("Content-Type: text/plain; charset=UTF-8").append(CRLF); + writer.append(CRLF).flush(); + + try + { + byte[] tmp = new byte[BUFFER_SIZE]; + int l; + + while ((l = input.read(tmp, 0, BUFFER_SIZE)) != -1) + { + output.write(tmp, 0, l); + progress.updateCurrent(l); + output.flush(); + } + } + finally + { + if(input != null) + input.close(); + } + writer.append(CRLF).flush(); + } + + private void setParam(String key, String value, String boundary, PrintWriter writer) { + writer.append("--" + boundary).append(CRLF); + writer.append("content-disposition: form-data; name=\"" + key + "\"").append(CRLF); + writer.append("content-type: text/plain; charset=UTF-8").append(CRLF); + writer.append(CRLF); + writer.append(value).append(CRLF).flush(); + } + + private void addCredentials(String data) throws SendFailedException { + try { + credentialsManager.addCredentials(conn, data); + } catch (CredentialsException e) { + throw new SendFailedException(e); + } + } + + private void populateHeaders(String method, String contentType) throws SendFailedException + { + conn.addHeader("Content-Type", contentType); + conn.setRequestMethod(method); + } + +} diff --git a/SendSafelyAPI/src/com/sendsafely/upload/UploadFactory.java b/SendSafelyAPI/src/com/sendsafely/upload/UploadFactory.java index aaa3463..33acb46 100644 --- a/SendSafelyAPI/src/com/sendsafely/upload/UploadFactory.java +++ b/SendSafelyAPI/src/com/sendsafely/upload/UploadFactory.java @@ -16,5 +16,10 @@ public static UploadManager getManager(ConnectionManager connection, Credentials { return new DefaultUploadManager(connection, manager, jsonManager); } + + public static UploadManager getManagerS3(ConnectionManager connection) + { + return new S3UploadManager(connection, JsonFactory.getDefaultManager()); + } } diff --git a/SendSafelyAPI/src/com/sendsafely/utils/SendUtil.java b/SendSafelyAPI/src/com/sendsafely/utils/SendUtil.java index 2f0e98b..23ebe47 100644 --- a/SendSafelyAPI/src/com/sendsafely/utils/SendUtil.java +++ b/SendSafelyAPI/src/com/sendsafely/utils/SendUtil.java @@ -49,7 +49,7 @@ protected T send(String path, HTTPMethod method, String data, T clazz) throw protected T handleResponse(T clazz) throws IOException, SendFailedException { - if(connection.getContentType() != null && connection.getContentType().equals("application/octet-stream")) { + if(connection.getContentType() != null && (connection.getContentType().equals("application/octet-stream")|| connection.getContentType().equals("binary/octet-stream"))) { return handleFileDownload(clazz); } else { String response = connection.getResponse();