Handle encrypted files while importing keys
This commit is contained in:
@@ -416,11 +416,18 @@ public class ImportKeysActivity extends BaseActivity
|
|||||||
intent.putExtra(ImportKeyResult.EXTRA_RESULT, result);
|
intent.putExtra(ImportKeyResult.EXTRA_RESULT, result);
|
||||||
setResult(RESULT_OK, intent);
|
setResult(RESULT_OK, intent);
|
||||||
finish();
|
finish();
|
||||||
return;
|
} else if (result.isOkNew() || result.isOkUpdated()) {
|
||||||
}
|
// User has successfully imported a key, hide first time dialog
|
||||||
|
Preferences.getPreferences(this).setFirstTime(false);
|
||||||
|
|
||||||
result.createNotify(ImportKeysActivity.this)
|
// Close activities opened for importing keys and go to the list of keys
|
||||||
.show((ViewGroup) findViewById(R.id.import_snackbar));
|
Intent intent = new Intent(this, MainActivity.class);
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||||
|
startActivity(intent);
|
||||||
|
} else {
|
||||||
|
result.createNotify(ImportKeysActivity.this)
|
||||||
|
.show((ViewGroup) findViewById(R.id.import_snackbar));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// methods from CryptoOperationHelper.Callback
|
// methods from CryptoOperationHelper.Callback
|
||||||
|
|||||||
@@ -17,29 +17,46 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.ui;
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
||||||
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
import org.sufficientlysecure.keychain.pgp.PgpHelper;
|
||||||
|
import org.sufficientlysecure.keychain.ui.ImportKeysListFragment.BytesLoaderState;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||||
import org.sufficientlysecure.keychain.util.FileHelper;
|
import org.sufficientlysecure.keychain.util.FileHelper;
|
||||||
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
public class ImportKeysFileFragment extends Fragment {
|
public class ImportKeysFileFragment extends Fragment {
|
||||||
private ImportKeysActivity mImportActivity;
|
private ImportKeysActivity mImportActivity;
|
||||||
private View mBrowse;
|
private View mBrowse;
|
||||||
private View mClipboardButton;
|
private View mClipboardButton;
|
||||||
|
|
||||||
public static final int REQUEST_CODE_FILE = 0x00007003;
|
private Uri mCurrentUri;
|
||||||
|
|
||||||
|
private static final int REQUEST_CODE_FILE = 0x00007003;
|
||||||
|
private static final int REQUEST_PERMISSION_READ_EXTERNAL_STORAGE = 12;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new instance of this fragment
|
* Creates new instance of this fragment
|
||||||
@@ -83,10 +100,10 @@ public class ImportKeysFileFragment extends Fragment {
|
|||||||
sendText = clipboardText.toString();
|
sendText = clipboardText.toString();
|
||||||
sendText = PgpHelper.getPgpKeyContent(sendText);
|
sendText = PgpHelper.getPgpKeyContent(sendText);
|
||||||
if (sendText == null) {
|
if (sendText == null) {
|
||||||
Notify.create(mImportActivity, "Bad data!", Style.ERROR).show();
|
Notify.create(mImportActivity, R.string.error_bad_data, Style.ERROR).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mImportActivity.loadCallback(new ImportKeysListFragment.BytesLoaderState(sendText.getBytes(), null));
|
mImportActivity.loadCallback(new BytesLoaderState(sendText.getBytes(), null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -106,11 +123,12 @@ public class ImportKeysFileFragment extends Fragment {
|
|||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case REQUEST_CODE_FILE: {
|
case REQUEST_CODE_FILE: {
|
||||||
if (resultCode == Activity.RESULT_OK && data != null && data.getData() != null) {
|
if (resultCode == Activity.RESULT_OK && data != null && data.getData() != null) {
|
||||||
|
mCurrentUri = data.getData();
|
||||||
|
|
||||||
// load data
|
if (checkAndRequestReadPermission(mCurrentUri)) {
|
||||||
mImportActivity.loadCallback(new ImportKeysListFragment.BytesLoaderState(null, data.getData()));
|
startImportingKeys();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,4 +139,77 @@ public class ImportKeysFileFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startImportingKeys() {
|
||||||
|
boolean isEncrypted;
|
||||||
|
try {
|
||||||
|
isEncrypted = FileHelper.isEncryptedFile(mImportActivity, mCurrentUri);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "Error opening file", e);
|
||||||
|
|
||||||
|
Notify.create(mImportActivity, R.string.error_bad_data, Style.ERROR).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEncrypted) {
|
||||||
|
Intent intent = new Intent(mImportActivity, DecryptActivity.class);
|
||||||
|
intent.setAction(Intent.ACTION_VIEW);
|
||||||
|
intent.setData(mCurrentUri);
|
||||||
|
startActivity(intent);
|
||||||
|
} else {
|
||||||
|
mImportActivity.loadCallback(new BytesLoaderState(null, mCurrentUri));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request READ_EXTERNAL_STORAGE permission on Android >= 6.0 to read content from "file" Uris.
|
||||||
|
* <p/>
|
||||||
|
* This method returns true on Android < 6, or if permission is already granted. It
|
||||||
|
* requests the permission and returns false otherwise.
|
||||||
|
* <p/>
|
||||||
|
* see https://commonsware.com/blog/2015/10/07/runtime-permissions-files-action-send.html
|
||||||
|
*/
|
||||||
|
private boolean checkAndRequestReadPermission(final Uri uri) {
|
||||||
|
if (!ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Additional check due to https://commonsware.com/blog/2015/11/09/you-cannot-hold-nonexistent-permissions.html
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||||
|
== PackageManager.PERMISSION_GRANTED) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestPermissions(
|
||||||
|
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
|
||||||
|
REQUEST_PERMISSION_READ_EXTERNAL_STORAGE);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResult(int requestCode,
|
||||||
|
@NonNull String[] permissions,
|
||||||
|
@NonNull int[] grantResults) {
|
||||||
|
|
||||||
|
if (requestCode != REQUEST_PERMISSION_READ_EXTERNAL_STORAGE) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean permissionWasGranted = grantResults.length > 0
|
||||||
|
&& grantResults[0] == PackageManager.PERMISSION_GRANTED;
|
||||||
|
|
||||||
|
if (permissionWasGranted) {
|
||||||
|
startImportingKeys();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getActivity(), R.string.error_denied_storage_permission, Toast.LENGTH_LONG).show();
|
||||||
|
getActivity().setResult(Activity.RESULT_CANCELED);
|
||||||
|
getActivity().finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,13 @@ package org.sufficientlysecure.keychain.util;
|
|||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.BufferedReader;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
@@ -223,6 +225,31 @@ public class FileHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isEncryptedFile(Context context, Uri uri) throws IOException {
|
||||||
|
boolean isEncrypted = false;
|
||||||
|
|
||||||
|
BufferedReader br = null;
|
||||||
|
try {
|
||||||
|
InputStream is = context.getContentResolver().openInputStream(uri);
|
||||||
|
br = new BufferedReader(new InputStreamReader(is));
|
||||||
|
|
||||||
|
String header = "-----BEGIN PGP MESSAGE-----";
|
||||||
|
int length = header.length();
|
||||||
|
char[] buffer = new char[length];
|
||||||
|
if (br.read(buffer, 0, length) == length) {
|
||||||
|
isEncrypted = new String(buffer).equals(header);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (br != null)
|
||||||
|
br.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(Constants.TAG, "Error closing file", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isEncrypted;
|
||||||
|
}
|
||||||
|
|
||||||
public static String readableFileSize(long size) {
|
public static String readableFileSize(long size) {
|
||||||
if (size <= 0) return "0";
|
if (size <= 0) return "0";
|
||||||
final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
|
final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
|
||||||
|
|||||||
@@ -359,6 +359,7 @@
|
|||||||
<string name="error_file_delete_failed">"have not been deleted. Delete them manually!"</string>
|
<string name="error_file_delete_failed">"have not been deleted. Delete them manually!"</string>
|
||||||
<string name="error_file_added_already">%s has already been added.</string>
|
<string name="error_file_added_already">%s has already been added.</string>
|
||||||
<string name="error_file_not_found">"file not found"</string>
|
<string name="error_file_not_found">"file not found"</string>
|
||||||
|
<string name="error_bad_data">"Bad data!"</string>
|
||||||
<string name="error_no_secret_key_found">"no suitable secret key found"</string>
|
<string name="error_no_secret_key_found">"no suitable secret key found"</string>
|
||||||
<string name="error_external_storage_not_ready">"external storage not ready"</string>
|
<string name="error_external_storage_not_ready">"external storage not ready"</string>
|
||||||
<string name="error_key_size_minimum512bit">"key size must be at least 512bit"</string>
|
<string name="error_key_size_minimum512bit">"key size must be at least 512bit"</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user