Merge branch 'master' of github.com:TheLastProject/loyalty-card-locker

This commit is contained in:
Sylvia van Os
2021-10-16 17:21:18 +02:00
9 changed files with 106 additions and 30 deletions

View File

@@ -12,13 +12,14 @@ import android.text.InputType;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -47,6 +48,7 @@ public class ImportExportActivity extends CatimaAppCompatActivity
private String importAlertTitle;
private String importAlertMessage;
private DataFormat importDataFormat;
private String exportPassword;
@Override
protected void onCreate(Bundle savedInstanceState)
@@ -88,7 +90,28 @@ public class ImportExportActivity extends CatimaAppCompatActivity
@Override
public void onClick(View v)
{
chooseFileWithIntent(intentCreateDocumentAction, CHOOSE_EXPORT_LOCATION);
AlertDialog.Builder builder = new AlertDialog.Builder(ImportExportActivity.this);
builder.setTitle(R.string.exportPassword);
FrameLayout container = new FrameLayout(ImportExportActivity.this);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.leftMargin = 50;
params.rightMargin = 50;
final EditText input = new EditText(ImportExportActivity.this);
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
input.setLayoutParams(params);
input.setHint(R.string.exportPasswordHint);
container.addView(input);
builder.setView(container);
builder.setPositiveButton(R.string.ok, (dialogInterface, i) -> {
exportPassword = input.getText().toString();
chooseFileWithIntent(intentCreateDocumentAction, CHOOSE_EXPORT_LOCATION);
});
builder.setNegativeButton(R.string.cancel, (dialogInterface, i) -> dialogInterface.cancel());
builder.show();
}
});
@@ -211,7 +234,7 @@ public class ImportExportActivity extends CatimaAppCompatActivity
importExporter.execute();
}
private void startExport(final OutputStream target, final Uri targetUri, final boolean closeWhenDone)
private void startExport(final OutputStream target, final Uri targetUri,char[] password, final boolean closeWhenDone)
{
ImportExportTask.TaskCompleteListener listener = new ImportExportTask.TaskCompleteListener()
{
@@ -229,7 +252,7 @@ public class ImportExportActivity extends CatimaAppCompatActivity
};
importExporter = new ImportExportTask(ImportExportActivity.this,
DataFormat.Catima, target, listener);
DataFormat.Catima, target,password, listener);
importExporter.execute();
}
@@ -407,6 +430,7 @@ public class ImportExportActivity extends CatimaAppCompatActivity
{
if (requestCode == CHOOSE_EXPORT_LOCATION)
{
OutputStream writer;
if (uri.getScheme() != null)
{
@@ -416,9 +440,8 @@ public class ImportExportActivity extends CatimaAppCompatActivity
{
writer = new FileOutputStream(new File(uri.toString()));
}
Log.e(TAG, "Starting file export with: " + uri.toString());
startExport(writer, uri, true);
startExport(writer, uri,exportPassword.toCharArray(),true);
}
else
{

View File

@@ -35,7 +35,7 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
/**
* Constructor which will setup a task for exporting to the given file
*/
ImportExportTask(Activity activity, DataFormat format, OutputStream output,
ImportExportTask(Activity activity, DataFormat format, OutputStream output,char[] password,
TaskCompleteListener listener)
{
super();
@@ -43,6 +43,7 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
this.doImport = false;
this.format = format;
this.outputStream = output;
this.password = password;
this.listener = listener;
}
@@ -70,14 +71,14 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
return importResult;
}
private ImportExportResult performExport(Context context, OutputStream stream, DBHelper db)
private ImportExportResult performExport(Context context, OutputStream stream, DBHelper db,char[] password)
{
ImportExportResult result = ImportExportResult.GenericFailure;
try
{
OutputStreamWriter writer = new OutputStreamWriter(stream, StandardCharsets.UTF_8);
result = MultiFormatExporter.exportData(context, db, stream, format);
result = MultiFormatExporter.exportData(context, db, stream, format,password);
writer.close();
}
catch (IOException e)
@@ -118,7 +119,7 @@ class ImportExportTask extends AsyncTask<Void, Void, ImportExportResult>
}
else
{
result = performExport(activity.getApplicationContext(), outputStream, db);
result = performExport(activity.getApplicationContext(), outputStream, db,password);
}
return result;

View File

@@ -6,6 +6,7 @@ import android.graphics.Bitmap;
import net.lingala.zip4j.io.outputstream.ZipOutputStream;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.EncryptionMethod;
import net.lingala.zip4j.util.InternalZipConstants;
import org.apache.commons.csv.CSVFormat;
@@ -30,14 +31,21 @@ import protect.card_locker.Utils;
*/
public class CatimaExporter implements Exporter
{
public void exportData(Context context, DBHelper db, OutputStream output) throws IOException, InterruptedException
public void exportData(Context context, DBHelper db, OutputStream output,char[] password) throws IOException, InterruptedException
{
// Necessary vars
int readLen;
byte[] readBuffer = new byte[InternalZipConstants.BUFF_SIZE];
// Create zip output stream
ZipOutputStream zipOutputStream = new ZipOutputStream(output);
ZipOutputStream zipOutputStream;
if(password!=null && password.length>0){
zipOutputStream = new ZipOutputStream(output,password);
}
else{
zipOutputStream = new ZipOutputStream(output);
}
// Generate CSV
ByteArrayOutputStream catimaOutputStream = new ByteArrayOutputStream();
@@ -45,8 +53,7 @@ public class CatimaExporter implements Exporter
writeCSV(db, catimaOutputStreamWriter);
// Add CSV to zip file
ZipParameters csvZipParameters = new ZipParameters();
csvZipParameters.setFileNameInZip("catima.csv");
ZipParameters csvZipParameters = createZipParameters("catima.csv",password);
zipOutputStream.putNextEntry(csvZipParameters);
InputStream csvInputStream = new ByteArrayInputStream(catimaOutputStream.toByteArray());
while ((readLen = csvInputStream.read(readBuffer)) != -1) {
@@ -71,8 +78,7 @@ public class CatimaExporter implements Exporter
// If it exists, add to the .zip file
Bitmap image = Utils.retrieveCardImage(context, card.id, front);
if (image != null) {
ZipParameters imageZipParameters = new ZipParameters();
imageZipParameters.setFileNameInZip(Utils.getCardImageFileName(card.id, front));
ZipParameters imageZipParameters = createZipParameters(Utils.getCardImageFileName(card.id, front),password);
zipOutputStream.putNextEntry(imageZipParameters);
InputStream imageInputStream = new ByteArrayInputStream(Utils.bitmapToByteArray(image));
while ((readLen = imageInputStream.read(readBuffer)) != -1) {
@@ -86,6 +92,16 @@ public class CatimaExporter implements Exporter
zipOutputStream.close();
}
private ZipParameters createZipParameters(String fileName, char[] password){
ZipParameters zipParameters = new ZipParameters();
zipParameters.setFileNameInZip(fileName);
if(password!=null && password.length>0){
zipParameters.setEncryptFiles(true);
zipParameters.setEncryptionMethod(EncryptionMethod.AES);
}
return zipParameters;
}
private void writeCSV(DBHelper db, OutputStreamWriter output) throws IOException, InterruptedException {
CSVPrinter printer = new CSVPrinter(output, CSVFormat.RFC4180);

View File

@@ -48,7 +48,7 @@ public class CatimaImporter implements Importer
bufferedInputStream.mark(100);
// First, check if this is a zip file
ZipInputStream zipInputStream = new ZipInputStream(bufferedInputStream);
ZipInputStream zipInputStream = new ZipInputStream(bufferedInputStream,password);
boolean isZipFile = false;

View File

@@ -17,5 +17,5 @@ public interface Exporter
* Export the database to the output stream in a given format.
* @throws IOException
*/
void exportData(Context context, DBHelper db, OutputStream output) throws IOException, InterruptedException;
void exportData(Context context, DBHelper db, OutputStream output,char[] password) throws IOException, InterruptedException;
}

View File

@@ -22,7 +22,7 @@ public class MultiFormatExporter
* another ImportExportResult otherwise. If not Success, partial data may have been
* written to the output stream, and it should be discarded.
*/
public static ImportExportResult exportData(Context context, DBHelper db, OutputStream output, DataFormat format)
public static ImportExportResult exportData(Context context, DBHelper db, OutputStream output, DataFormat format,char[] password)
{
Exporter exporter = null;
@@ -40,7 +40,7 @@ public class MultiFormatExporter
{
try
{
exporter.exportData(context, db, output);
exporter.exportData(context, db, output,password);
return ImportExportResult.Success;
}
catch(IOException e)

View File

@@ -196,6 +196,8 @@
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="passwordRequired">Please enter the password</string>
<string name="exportPassword">Set a password to protect your export (optional)</string>
<string name="exportPasswordHint">Enter password</string>
<string name="failedGeneratingShareURL">Could not generate sharable URL. Please report this.</string>
<string name="turn_flashlight_on">Turn flashlight on</string>
<string name="turn_flashlight_off">Turn flashlight off</string>
@@ -243,4 +245,4 @@
<string name="rate_this_app">Rate this app</string>
<string name="on_google_play">on Google Play</string>
<string name="report_error">Report Error</string>
</resources>
</resources>

View File

@@ -334,7 +334,7 @@ public class ImportExportTest
OutputStreamWriter outStream = new OutputStreamWriter(outData);
// Export data to CSV format
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima);
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima,null);
assertEquals(ImportExportResult.Success, result);
outStream.close();
@@ -354,6 +354,39 @@ public class ImportExportTest
TestHelpers.getEmptyDb(activity);
}
public void multipleCardsExportImportPasswordProtected() throws IOException
{
final int NUM_CARDS = 10;
List<char[]> passwords = Arrays.asList(null, "123456789".toCharArray());
for(char[] password : passwords){
addLoyaltyCards(NUM_CARDS);
ByteArrayOutputStream outData = new ByteArrayOutputStream();
OutputStreamWriter outStream = new OutputStreamWriter(outData);
// Export data to CSV format
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima,password);
assertEquals(ImportExportResult.Success, result);
outStream.close();
TestHelpers.getEmptyDb(activity);
ByteArrayInputStream inData = new ByteArrayInputStream(outData.toByteArray());
// Import the CSV data
result = MultiFormatImporter.importData(activity.getApplicationContext(), db, inData, DataFormat.Catima, password);
assertEquals(ImportExportResult.Success, result);
assertEquals(NUM_CARDS, db.getLoyaltyCardCount());
checkLoyaltyCards();
// Clear the database for the next format under test
TestHelpers.getEmptyDb(activity);
}
}
@Test
public void multipleCardsExportImportSomeStarred() throws IOException
{
@@ -365,7 +398,7 @@ public class ImportExportTest
OutputStreamWriter outStream = new OutputStreamWriter(outData);
// Export data to CSV format
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima);
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima,null);
assertEquals(ImportExportResult.Success, result);
outStream.close();
@@ -438,7 +471,7 @@ public class ImportExportTest
OutputStreamWriter outStream = new OutputStreamWriter(outData);
// Export data to CSV format
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima);
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima,null);
assertEquals(ImportExportResult.Success, result);
outStream.close();
@@ -482,7 +515,7 @@ public class ImportExportTest
OutputStreamWriter outStream = new OutputStreamWriter(outData);
// Export into CSV data
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima);
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima,null);
assertEquals(ImportExportResult.Success, result);
outStream.close();
@@ -513,7 +546,7 @@ public class ImportExportTest
OutputStreamWriter outStream = new OutputStreamWriter(outData);
// Export data to CSV format
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima);
ImportExportResult result = MultiFormatExporter.exportData(activity.getApplicationContext(), db, outData, DataFormat.Catima,null);
assertEquals(ImportExportResult.Success, result);
TestHelpers.getEmptyDb(activity);
@@ -560,8 +593,9 @@ public class ImportExportTest
TestTaskCompleteListener listener = new TestTaskCompleteListener();
// Export to the file
final String password = "123456789";
FileOutputStream fileOutputStream = new FileOutputStream(exportFile);
ImportExportTask task = new ImportExportTask(activity, DataFormat.Catima, fileOutputStream, listener);
ImportExportTask task = new ImportExportTask(activity, DataFormat.Catima, fileOutputStream,password.toCharArray(), listener);
task.execute();
// Actually run the task to completion
@@ -579,7 +613,7 @@ public class ImportExportTest
FileInputStream fileStream = new FileInputStream(exportFile);
task = new ImportExportTask(activity, DataFormat.Catima, fileStream, null, listener);
task = new ImportExportTask(activity, DataFormat.Catima, fileStream, password.toCharArray(), listener);
task.execute();
// Actually run the task to completion
@@ -901,7 +935,7 @@ public class ImportExportTest
// Export everything
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
MultiFormatExporter.exportData(activity.getApplicationContext(), db, outputStream, DataFormat.Catima);
MultiFormatExporter.exportData(activity.getApplicationContext(), db, outputStream, DataFormat.Catima,null);
// Wipe database
TestHelpers.getEmptyDb(activity);

View File

@@ -1 +1 @@
Catima — Den Open Source kortlommen
Catima — for kundekort, billetter og kuponger 🎴