531 lines
19 KiB
Java
531 lines
19 KiB
Java
package com.eua.local.view.controller;
|
|
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.math.BigDecimal;
|
|
import java.util.Random;
|
|
import java.util.zip.ZipEntry;
|
|
import java.util.zip.ZipOutputStream;
|
|
|
|
import com.foundation.metadata.Attribute;
|
|
import com.foundation.util.IManagedList;
|
|
import com.foundation.util.ManagedList;
|
|
import com.foundation.view.ControlDecoration;
|
|
import com.foundation.view.IViewContext;
|
|
import com.foundation.view.swt.DirectoryDialog;
|
|
import com.foundation.view.swt.FileDialog;
|
|
import com.common.comparison.Comparator;
|
|
import com.common.debug.Debug;
|
|
import com.common.io.StreamSupport;
|
|
import com.common.io.SymmetricOutputStream;
|
|
import com.common.security.ISymmetricAlgorithm;
|
|
import com.common.security.Rijndael;
|
|
import com.common.security.Sha1;
|
|
import com.common.util.LiteHashSet;
|
|
import com.common.util.StringSupport;
|
|
import com.eua.controller.SettingsController;
|
|
import com.eua.local.view.EncryptView;
|
|
import com.eua.model.FileMetadata;
|
|
|
|
/**
|
|
* Copyright Declarative Engineering LLC 2009<p>
|
|
*/
|
|
public class EncryptViewController extends AbstractViewController {
|
|
private static final int METRIC_BYTES = 0;
|
|
private static final int METRIC_KILO_BYTES = 1;
|
|
private static final int METRIC_MEGA_BYTES = 2;
|
|
private static final int METRIC_GIGA_BYTES = 3;
|
|
|
|
//Note: The metrics must be in ascending sequential order starting with zero for both the options array and the names array.//
|
|
private static final Integer[] METRIC_OPTIONS = new Integer[] {new Integer(METRIC_BYTES), new Integer(METRIC_KILO_BYTES), new Integer(METRIC_MEGA_BYTES), new Integer(METRIC_GIGA_BYTES)};
|
|
private static final String[] METRIC_OPTION_NAMES = new String[] {"Bytes", "Kilobytes", "Megabytes", "Gigabytes"};
|
|
|
|
public static final Attribute FILES = registerCollection(EncryptViewController.class, "files", AO_REFERENCED | AO_LAZY);
|
|
public static final Attribute SELECTED_FILES = registerCollection(EncryptViewController.class, "selectedFiles", AO_REFERENCED | AO_LAZY);
|
|
public static final Attribute SPLIT = registerAttribute(EncryptViewController.class, "split", Boolean.FALSE);
|
|
public static final Attribute MAXIMUM_OUTPUT_SIZE = registerAttribute(EncryptViewController.class, "maximumOutputSize", new Long(1));
|
|
public static final Attribute MAXIMUM_OUTPUT_METRIC = registerAttribute(EncryptViewController.class, "maximumOutputMetric", new Integer(METRIC_MEGA_BYTES));
|
|
public static final Attribute PASSWORD = registerAttribute(EncryptViewController.class, "password");
|
|
public static final Attribute OUTPUT_DIRECTORY = registerAttribute(EncryptViewController.class, "outputDirectory", AO_LAZY);
|
|
public static final Attribute OUTPUT_NAME = registerAttribute(EncryptViewController.class, "outputName", AO_LAZY);
|
|
public static final Attribute FILE_METADATA_SET = registerAttribute(EncryptViewController.class, "fileMetadataSet", AO_REFERENCED | AO_LAZY);
|
|
public static final Attribute INPUT_DIRECTORY = registerAttribute(EncryptViewController.class, "inputDirectory", AO_REFERENCED | AO_LAZY);
|
|
/**
|
|
* EncryptViewController constructor.
|
|
* @param viewContext
|
|
*/
|
|
public EncryptViewController(IViewContext viewContext) {
|
|
super(viewContext);
|
|
}//EncryptViewController()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.common.Entity#lazyLoadAttribute(int)
|
|
*/
|
|
protected Object lazyLoadAttribute(Attribute attributeNumber) {
|
|
Object result = null;
|
|
|
|
if(attributeNumber == FILES) {
|
|
result = new ManagedList(10, 100);
|
|
}//if//
|
|
else if(attributeNumber == SELECTED_FILES) {
|
|
result = new ManagedList(10, 100);
|
|
}//else if//
|
|
else if(attributeNumber == INPUT_DIRECTORY) {
|
|
result = SettingsController.getSingleton().getInputDirectory();
|
|
|
|
if(result == null) {
|
|
File desktop = new File(System.getProperty("user.home"), "desktop");
|
|
|
|
if(desktop.exists()) {
|
|
result = desktop.getAbsolutePath();
|
|
}//if//
|
|
else {
|
|
result = System.getProperty("user.dir");
|
|
}//else//
|
|
}//if//
|
|
}//else if//
|
|
else if(attributeNumber == OUTPUT_DIRECTORY) {
|
|
result = SettingsController.getSingleton().getEncryptionOutputDirectory();
|
|
|
|
if(result == null) {
|
|
File desktop = new File(System.getProperty("user.home"), "desktop");
|
|
|
|
if(desktop.exists()) {
|
|
result = desktop.getAbsolutePath();
|
|
}//if//
|
|
else {
|
|
result = System.getProperty("user.dir");
|
|
}//else//
|
|
}//if//
|
|
}//else if//
|
|
else if(attributeNumber == OUTPUT_NAME) {
|
|
result = SettingsController.getSingleton().getEncryptedFileName();
|
|
|
|
if(result == null) {
|
|
result = "encrypted";
|
|
}//if//
|
|
}//else if//
|
|
else if(attributeNumber == FILE_METADATA_SET) {
|
|
result = new LiteHashSet(10, LiteHashSet.DEFAULT_LOAD_FACTOR, Comparator.getLogicalComparator(), LiteHashSet.STYLE_NO_DUPLICATES);
|
|
}//else if//
|
|
else {
|
|
result = super.lazyLoadAttribute(attributeNumber);
|
|
}//else//
|
|
|
|
return result;
|
|
}//lazyLoadAttribute()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.controller.ViewController#getViewClass()
|
|
*/
|
|
protected Class getViewClass() {
|
|
return EncryptView.class;
|
|
}//getViewClass()//
|
|
/* (non-Javadoc)
|
|
* @see com.foundation.controller.ViewController#validate()
|
|
*/
|
|
public boolean validate() {
|
|
boolean result = true;
|
|
|
|
getDecorationManager().clearDecorations();
|
|
|
|
if(getSplit().booleanValue() && (getMaximumOutputSize() == null || getMaximumOutputSize().longValue() <= 0)) {
|
|
getDecorationManager().addDecoration(this, MAXIMUM_OUTPUT_SIZE, new ControlDecoration(IMAGE_ERROR, "Missing output size."));
|
|
result = false;
|
|
}//if//
|
|
else if(getSplit().booleanValue() && getMaximumOutputMetric().intValue() == METRIC_BYTES && getMaximumOutputSize().longValue() < 1000) {
|
|
getDecorationManager().addDecoration(this, MAXIMUM_OUTPUT_SIZE, new ControlDecoration(IMAGE_ERROR, "Maximum output size must be greater than 1000 if measured in bytes."));
|
|
result = false;
|
|
}//else if//
|
|
|
|
if(getPassword() == null || getPassword().length() == 0) {
|
|
getDecorationManager().addDecoration(this, PASSWORD, new ControlDecoration(IMAGE_ERROR, "Password required."));
|
|
result = false;
|
|
}//if//
|
|
|
|
if(getOutputDirectory() == null || getOutputDirectory().trim().length() == 0) {
|
|
getDecorationManager().addDecoration(this, OUTPUT_DIRECTORY, new ControlDecoration(IMAGE_ERROR, "Output directory required."));
|
|
result = false;
|
|
}//if//
|
|
|
|
if(getOutputName() == null || getOutputName().trim().length() == 0) {
|
|
getDecorationManager().addDecoration(this, OUTPUT_NAME, new ControlDecoration(IMAGE_ERROR, "Output name required."));
|
|
result = false;
|
|
}//if//
|
|
|
|
getDecorationManager().applyDecorationChanges();
|
|
|
|
return result;
|
|
}//validate()//
|
|
/**
|
|
* Cancels the log-in process and closes the client.
|
|
*/
|
|
public void doCancel() {
|
|
close();
|
|
}//doCancel()//
|
|
/**
|
|
* Initiates the validation process and opens the next view upon sucsessful validation.
|
|
*/
|
|
public void doEncrypt() {
|
|
synchronize();
|
|
|
|
if(validate()) {
|
|
if(getFiles().getSize() > 0 && getPassword() != null) {
|
|
BigDecimal totalSize = new BigDecimal(0);
|
|
BigDecimal maximumOutputSize = getSplit().booleanValue() ? new BigDecimal(getMaximumOutputSize().longValue()) : null;
|
|
int currentFileIndex = 0;
|
|
FileMetadata nextFile = (FileMetadata) getFiles().getFirst();
|
|
FileInputStream fin = null;
|
|
FileOutputStream fout = null;
|
|
byte[] buffer = new byte[100000]; //100k
|
|
ISymmetricAlgorithm algorithm = new Rijndael(new Random(StringSupport.hash(getPassword())));
|
|
SymmetricOutputStream sout = null;
|
|
ZipOutputStream zout = null;
|
|
File outputFile = new File(getOutputDirectory(), getOutputName() + ".enc");
|
|
|
|
try {
|
|
fin = new FileInputStream(new File(nextFile.getPath(), nextFile.getName()));
|
|
|
|
//Calculate the maximum output size of each split segment in terms of bytes.//
|
|
if(maximumOutputSize != null) {
|
|
switch(getMaximumOutputMetric().intValue()) {
|
|
case METRIC_GIGA_BYTES: {
|
|
maximumOutputSize = maximumOutputSize.multiply(new BigDecimal(1073741824)); //1024^3
|
|
break;
|
|
}//case//
|
|
case METRIC_MEGA_BYTES: {
|
|
maximumOutputSize = maximumOutputSize.multiply(new BigDecimal(1048576)); //1024^2
|
|
break;
|
|
}//case//
|
|
case METRIC_KILO_BYTES: {
|
|
maximumOutputSize = maximumOutputSize.multiply(new BigDecimal(1024));
|
|
break;
|
|
}//case//
|
|
default: {
|
|
//Do nothing.//
|
|
break;
|
|
}//default//
|
|
}//switch//
|
|
}//if//
|
|
|
|
//Calculate the total size of all the input content.//
|
|
for(int index = 0; index < getFiles().getSize(); index++) {
|
|
FileMetadata next = (FileMetadata) getFiles().get(index);
|
|
|
|
totalSize = totalSize.add(new BigDecimal(next.getLength().longValue()));
|
|
}//for//
|
|
|
|
fout = new FileOutputStream(outputFile);
|
|
//Write the magic number which is used when reading to verify that the file is generated by this same tool.//
|
|
StreamSupport.writeInt(MAGIC_NUMBER, fout);
|
|
//Write the version number of the tool being used to generate the encrypted data.//
|
|
StreamSupport.writeInt(VERSION, fout);
|
|
//Create the symmetric encryption output stream.//
|
|
sout = new SymmetricOutputStream(fout, algorithm);
|
|
sout.encrypt(true);
|
|
//Create the zip output stream to ensure all encrypted content is first compressed.//
|
|
zout = new ZipOutputStream(sout);
|
|
zout.putNextEntry(new ZipEntry("main"));
|
|
//Write the number of input files.//
|
|
StreamSupport.writeInt(getFiles().getSize(), zout);
|
|
|
|
//Write each file name and size.//
|
|
for(int index = 0; index < getFiles().getSize(); index++) {
|
|
FileMetadata next = (FileMetadata) getFiles().get(index);
|
|
|
|
StreamSupport.writeString(next.getName(), zout);
|
|
StreamSupport.writeLong(next.getLength().longValue(), zout);
|
|
}//for//
|
|
|
|
//Write the file data as long as we have an input stream.//
|
|
while(fin != null) {
|
|
int readCount = 0;
|
|
|
|
//Read in a whole buffer of content.//
|
|
while(readCount < buffer.length && fin != null) {
|
|
readCount += StreamSupport.readBytes(fin, buffer, readCount, buffer.length - readCount);
|
|
|
|
//If we couldn't fill the buffer (due to not enough bytes in the input stream), then open a stream on the next file.//
|
|
if(readCount != buffer.length) {
|
|
fin.close();
|
|
|
|
//Increment to the next file and open an input stream.//
|
|
if(++currentFileIndex != getFiles().getSize()) {
|
|
nextFile = (FileMetadata) getFiles().get(currentFileIndex);
|
|
fin = new FileInputStream(new File(nextFile.getPath(), nextFile.getName()));
|
|
}//if//
|
|
else {
|
|
fin = null;
|
|
nextFile = null;
|
|
}//else//
|
|
}//if//
|
|
}//while//
|
|
|
|
zout.write(buffer, 0, readCount);
|
|
}//while//
|
|
|
|
zout.closeEntry();
|
|
zout.flush();
|
|
zout.finish();
|
|
sout.encrypt(false);
|
|
sout.flush();
|
|
zout.close();
|
|
sout.close();
|
|
fout.close();
|
|
|
|
//If the output should be split then split the generated file now.//
|
|
if(getSplit().booleanValue() && maximumOutputSize.compareTo(new BigDecimal(outputFile.length())) < 0) {
|
|
int outputFileIndex = 0;
|
|
BigDecimal bufferSize = new BigDecimal(buffer.length);
|
|
|
|
fin = new FileInputStream(outputFile);
|
|
fout = null;
|
|
|
|
//Keep reading and writing until the input stream is empty.//
|
|
while(fin != null) {
|
|
BigDecimal writeSize = new BigDecimal(0);
|
|
|
|
if(fout != null) {
|
|
fout.close();
|
|
}//if//
|
|
|
|
fout = new FileOutputStream(outputFile.getAbsolutePath() + "." + ++outputFileIndex);
|
|
|
|
//Keep writing to the current file until we can't write any more.//
|
|
while(fin != null && writeSize.compareTo(maximumOutputSize) < 0) {
|
|
int readCount;
|
|
BigDecimal readLength = maximumOutputSize.subtract(writeSize);
|
|
|
|
//If the read length is greater than the buffer size then use the buffer size.//
|
|
if(readLength.compareTo(bufferSize) > 0) {
|
|
readLength = bufferSize;
|
|
}//if//
|
|
|
|
readCount = StreamSupport.readBytes(fin, buffer, 0, readLength.intValue());
|
|
fout.write(buffer, 0, readCount);
|
|
writeSize = writeSize.add(new BigDecimal(readCount));
|
|
|
|
//Check to see if the input stream is empty.//
|
|
if(readCount != readLength.intValue()) {
|
|
fin.close();
|
|
fin = null;
|
|
}//if//
|
|
}//while//
|
|
}//while//
|
|
|
|
fout.close();
|
|
fout = new FileOutputStream(outputFile);
|
|
//Write the magic number which is used when reading to verify that the file is generated by this same tool.//
|
|
StreamSupport.writeInt(SEQUENCE_MAGIC_NUMBER, fout);
|
|
//Write the version number of the tool being used to generate the encrypted data.//
|
|
StreamSupport.writeInt(SEQUENCE_VERSION, fout);
|
|
//Write the number of files in the sequence.//
|
|
StreamSupport.writeInt(outputFileIndex, fout);
|
|
fout.close();
|
|
fout = null;
|
|
displayInformation("Encryption Successful", "The content was successfully encrypted and split. All results placed in \"" + outputFile.getParentFile().getCanonicalPath() + "\".");
|
|
}//if//
|
|
else {
|
|
displayInformation("Encryption Successful", "The content was successfully encrypted to \"" + outputFile.getCanonicalPath() + "\".");
|
|
}//else//
|
|
|
|
SettingsController.getSingleton().setEncryptionSettings(getOutputDirectory(), getOutputName(), getInputDirectory());
|
|
}//try//
|
|
catch(Throwable e) {
|
|
Debug.log(e);
|
|
}//catch//
|
|
finally {
|
|
if(fin != null) {
|
|
try {fin.close();}catch(Throwable e) {}
|
|
}//if//
|
|
|
|
if(fout != null) {
|
|
try {fout.close();}catch(Throwable e) {}
|
|
}//if//
|
|
}//finally//
|
|
}//if//
|
|
}//if//
|
|
}//doEncrypt()//
|
|
/**
|
|
* Changes the output directory by opening a dialog for the user to choose a location.
|
|
*/
|
|
public void doChangeOutputDirectory() {
|
|
DirectoryDialog dialog = new DirectoryDialog(getView(), 0);
|
|
String directory;
|
|
|
|
dialog.setMessage("Choose the output directory.");
|
|
|
|
if((directory = dialog.open()) != null) {
|
|
setOutputDirectory(directory);
|
|
}//if//
|
|
}//doChangeOutputDirectory()//
|
|
/**
|
|
* Adds files to the collection to be encrypted.
|
|
*/
|
|
public void doAddFiles() {
|
|
FileDialog dialog = new FileDialog(getView(), FileDialog.STYLE_MULTI);
|
|
String path;
|
|
|
|
dialog.setFilterPath(getInputDirectory());
|
|
dialog.setText("Select the files you wish to encrypt.");
|
|
|
|
if((path = dialog.open()) != null) {
|
|
String[] fileNames = dialog.getFileNames();
|
|
File pathFile = new File(path);
|
|
|
|
//Get the actual path. Doing this because the dialog's result isn't a directory path, but rather a path to the first selected file.//
|
|
path = pathFile.getParent();
|
|
setInputDirectory(path);
|
|
|
|
for(int index = 0; index < fileNames.length; index++) {
|
|
FileMetadata fileMetadata = new FileMetadata(fileNames[index], path);
|
|
|
|
if(getFileMetadataSet().add(fileMetadata) != -1) {
|
|
getFiles().add(fileMetadata);
|
|
}//if//
|
|
}//for//
|
|
}//if//
|
|
}//doAddFiles()//
|
|
/**
|
|
* Removes files from the collection to be encrypted.
|
|
*/
|
|
public void doRemoveFiles() {
|
|
if(getSelectedFiles().getSize() > 0) {
|
|
getFiles().removeAll(getSelectedFiles());
|
|
getSelectedFiles().removeAll();
|
|
}//if//
|
|
}//doRemoveFiles()//
|
|
/**
|
|
* Gets the files value.
|
|
* @return The files value.
|
|
*/
|
|
public IManagedList getFiles() {
|
|
return (IManagedList) getAttributeValue(FILES);
|
|
}//getFiles()//
|
|
/**
|
|
* Gets the selectedFiles value.
|
|
* @return The selectedFiles value.
|
|
*/
|
|
public IManagedList getSelectedFiles() {
|
|
return (IManagedList) getAttributeValue(SELECTED_FILES);
|
|
}//getSelectedFiles()//
|
|
/**
|
|
* Gets the split value.
|
|
* @return The split value.
|
|
*/
|
|
public Boolean getSplit() {
|
|
return (Boolean) getAttributeValue(SPLIT);
|
|
}//getSplit()//
|
|
/**
|
|
* Sets the split value.
|
|
* @param split The split value.
|
|
*/
|
|
public void setSplit(Boolean split) {
|
|
setAttributeValue(SPLIT, split);
|
|
}//setSplit()//
|
|
/**
|
|
* Gets the maximumOutputSize value.
|
|
* @return The maximumOutputSize value.
|
|
*/
|
|
public Long getMaximumOutputSize() {
|
|
return (Long) getAttributeValue(MAXIMUM_OUTPUT_SIZE);
|
|
}//getMaximumOutputSize()//
|
|
/**
|
|
* Sets the maximumOutputSize value.
|
|
* @param maximumOutputSize The maximumOutputSize value.
|
|
*/
|
|
public void setMaximumOutputSize(Long maximumOutputSize) {
|
|
setAttributeValue(MAXIMUM_OUTPUT_SIZE, maximumOutputSize);
|
|
}//setMaximumOutputSize()//
|
|
/**
|
|
* Gets the maximumOutputMetric value.
|
|
* @return The maximumOutputMetric value.
|
|
*/
|
|
public Integer getMaximumOutputMetric() {
|
|
return (Integer) getAttributeValue(MAXIMUM_OUTPUT_METRIC);
|
|
}//getMaximumOutputMetric()//
|
|
/**
|
|
* Sets the metric for the maximum output value.
|
|
* @param maximumOutputMetric The metric for the maximum output value.
|
|
*/
|
|
public void setMaximumOutputMetric(Integer maximumOutputMetric) {
|
|
setAttributeValue(MAXIMUM_OUTPUT_METRIC, maximumOutputMetric);
|
|
}//setMaximumOutputMetric()//
|
|
/**
|
|
* Gets the set of metrics allowed for the maximum output metric.
|
|
* @return The metrics allowed.
|
|
*/
|
|
public Integer[] getMetrics() {
|
|
return METRIC_OPTIONS;
|
|
}//getMetrics()//
|
|
/**
|
|
* Gets the metric name for the given metric identifier.
|
|
* @param metric The metric number.
|
|
* @return The name for the metric.
|
|
*/
|
|
public String getMetricName(Integer metric) {
|
|
return METRIC_OPTION_NAMES[metric.intValue()];
|
|
}//getMetricName()//
|
|
/**
|
|
* Gets the password value.
|
|
* @return The password value.
|
|
*/
|
|
public String getPassword() {
|
|
return (String) getAttributeValue(PASSWORD);
|
|
}//getPassword()//
|
|
/**
|
|
* Sets the password value.
|
|
* @param password The password value.
|
|
*/
|
|
public void setPassword(String password) {
|
|
setAttributeValue(PASSWORD, password);
|
|
}//setPassword()//
|
|
/**
|
|
* Gets the outputDirectory value.
|
|
* @return The outputDirectory value.
|
|
*/
|
|
public String getOutputDirectory() {
|
|
return (String) getAttributeValue(OUTPUT_DIRECTORY);
|
|
}//getOutputDirectory()//
|
|
/**
|
|
* Sets the outputDirectory value.
|
|
* @param outputDirectory The outputDirectory value.
|
|
*/
|
|
public void setOutputDirectory(String outputDirectory) {
|
|
setAttributeValue(OUTPUT_DIRECTORY, outputDirectory);
|
|
}//setOutputDirectory()//
|
|
/**
|
|
* Gets the outputName value.
|
|
* @return The outputName value.
|
|
*/
|
|
public String getOutputName() {
|
|
return (String) getAttributeValue(OUTPUT_NAME);
|
|
}//getOutputName()//
|
|
/**
|
|
* Sets the outputName value.
|
|
* @param outputName The outputName value.
|
|
*/
|
|
public void setOutputName(String outputName) {
|
|
setAttributeValue(OUTPUT_NAME, outputName);
|
|
}//setOutputName()//
|
|
/**
|
|
* Gets the fileMetadataSet value.
|
|
* @return The fileMetadataSet value.
|
|
*/
|
|
protected LiteHashSet getFileMetadataSet() {
|
|
return (LiteHashSet) getAttributeValue(FILE_METADATA_SET);
|
|
}//getFileMetadataSet()//
|
|
/**
|
|
* Gets the last used directory for selecting files to encrypt.
|
|
* @return The input directory path.
|
|
*/
|
|
public String getInputDirectory() {
|
|
return (String) getAttributeValue(INPUT_DIRECTORY);
|
|
}//getInputDirectory()//
|
|
/**
|
|
* Sets the last used directory for selecting files to encrypt.
|
|
* @param inputDirectory The input directory path.
|
|
*/
|
|
public void setInputDirectory(String inputDirectory) {
|
|
setAttributeValue(INPUT_DIRECTORY, inputDirectory);
|
|
}//setInputDirectory()//
|
|
}//EncryptViewController// |