mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-27 11:12:15 -05:00
Fix Bluetooth share without breaking others
This commit is contained in:
parent
291f95db5a
commit
b06e7cd737
@ -40,6 +40,8 @@ import org.sufficientlysecure.keychain.util.PRNGFixes;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
import org.sufficientlysecure.keychain.util.TlsHelper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.security.Security;
|
||||
import java.util.HashMap;
|
||||
|
||||
@ -88,6 +90,17 @@ public class KeychainApplication extends Application {
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up leftover Bluetooth Share files
|
||||
for (File toDelete : this.getExternalCacheDir().listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, String filename) {
|
||||
if (filename.matches("^key-[0-9a-fA-F]{8}\\.pgp\\.asc$")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
})) { toDelete.delete(); }
|
||||
|
||||
brandGlowEffect(getApplicationContext(),
|
||||
getApplicationContext().getResources().getColor(R.color.primary));
|
||||
|
||||
|
@ -26,6 +26,7 @@ import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.FileObserver;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.CursorLoader;
|
||||
@ -54,6 +55,9 @@ import org.sufficientlysecure.keychain.ui.util.QrCodeUtils;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
import org.sufficientlysecure.keychain.util.NfcHelper;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
@ -175,11 +179,11 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
||||
boolean toClipboard) {
|
||||
try {
|
||||
String content;
|
||||
byte[] fingerprintData = (byte[]) providerHelper.getGenericData(
|
||||
KeyRings.buildUnifiedKeyRingUri(dataUri),
|
||||
Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
|
||||
if (fingerprintOnly) {
|
||||
byte[] data = (byte[]) providerHelper.getGenericData(
|
||||
KeyRings.buildUnifiedKeyRingUri(dataUri),
|
||||
Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
|
||||
String fingerprint = KeyFormattingUtils.convertFingerprintToHex(data);
|
||||
String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintData);
|
||||
if (!toClipboard) {
|
||||
content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
|
||||
} else {
|
||||
@ -213,13 +217,62 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
||||
Intent sendIntent = new Intent(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, content);
|
||||
sendIntent.setType("text/plain");
|
||||
|
||||
String title;
|
||||
if (fingerprintOnly) {
|
||||
title = getResources().getString(R.string.title_share_fingerprint_with);
|
||||
} else {
|
||||
title = getResources().getString(R.string.title_share_key);
|
||||
}
|
||||
startActivity(Intent.createChooser(sendIntent, title));
|
||||
Intent shareChooser = Intent.createChooser(sendIntent, title);
|
||||
|
||||
// Bluetooth Share will convert text/plain sent via EXTRA_TEXT to HTML
|
||||
// Add replacement extra to send a text/plain file instead.
|
||||
try {
|
||||
final File contentFile = new File(getActivity().getExternalCacheDir(),
|
||||
"key-" + KeyFormattingUtils.getShortKeyIdAsHexFromFingerprint(fingerprintData, false) +
|
||||
".pgp.asc");
|
||||
FileWriter contentFileWriter = new FileWriter(contentFile, false);
|
||||
BufferedWriter contentWriter = new BufferedWriter(contentFileWriter);
|
||||
contentWriter.write(content);
|
||||
contentWriter.close();
|
||||
Uri contentUri = Uri.fromFile(contentFile);
|
||||
|
||||
final Runnable deleteContentFile = new Runnable() {
|
||||
public void run() {
|
||||
contentFile.delete();
|
||||
}
|
||||
};
|
||||
|
||||
// delete the file after Bluetooth Share closes the file
|
||||
FileObserver tempFileObserver = new FileObserver(contentFile.getAbsolutePath(),
|
||||
FileObserver.CLOSE_NOWRITE) {
|
||||
@Override
|
||||
public void onEvent(int event, String path) {
|
||||
// Hopefully it will only be opened and then closed by the share process once
|
||||
getContainer().post(deleteContentFile);
|
||||
}
|
||||
};
|
||||
tempFileObserver.startWatching();
|
||||
|
||||
// If it's not complete in 1m, the file was not used; delete it
|
||||
getContainer().postDelayed(deleteContentFile, 1 * 60 * 1000);
|
||||
|
||||
// create replacement extras inside try{}:
|
||||
// if file creation fails, just don't add the replacements
|
||||
Bundle replacements = new Bundle();
|
||||
shareChooser.putExtra(Intent.EXTRA_REPLACEMENT_EXTRAS, replacements);
|
||||
|
||||
Bundle bluetoothExtra = new Bundle(sendIntent.getExtras());
|
||||
replacements.putBundle("com.android.bluetooth", bluetoothExtra);
|
||||
|
||||
bluetoothExtra.putParcelable(Intent.EXTRA_STREAM, contentUri);
|
||||
} catch (IOException e) {
|
||||
Log.e(Constants.TAG, "error creating temporary Bluetooth key share file!", e);
|
||||
Notify.create(getActivity(), R.string.error_bluetooth_file, Notify.Style.ERROR).show();
|
||||
}
|
||||
|
||||
startActivity(shareChooser);
|
||||
}
|
||||
} catch (PgpGeneralException | IOException e) {
|
||||
Log.e(Constants.TAG, "error processing key!", e);
|
||||
@ -379,4 +432,4 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -227,6 +227,14 @@ public class KeyFormattingUtils {
|
||||
return buf.getLong();
|
||||
}
|
||||
|
||||
public static int getShortKeyIdFromFingerprint(byte[] fingerprint) {
|
||||
ByteBuffer buf = ByteBuffer.wrap(fingerprint);
|
||||
// skip first 16 bytes of the fingerprint
|
||||
buf.position(16);
|
||||
// the last four bytes are the short key id (big endian, which is default order in ByteBuffer)
|
||||
return buf.getInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert key id from long to 64 bit hex string
|
||||
* <p/>
|
||||
@ -238,16 +246,24 @@ public class KeyFormattingUtils {
|
||||
* @return
|
||||
*/
|
||||
public static String convertKeyIdToHex(long keyId) {
|
||||
return convertKeyIdToHex(keyId, true);
|
||||
}
|
||||
|
||||
public static String convertKeyIdToHex(long keyId, boolean header) {
|
||||
long upper = keyId >> 32;
|
||||
if (upper == 0) {
|
||||
// this is a short key id
|
||||
return convertKeyIdToHexShort(keyId);
|
||||
return convertKeyIdToHexShort(keyId, header);
|
||||
}
|
||||
return "0x" + convertKeyIdToHex32bit(keyId >> 32) + convertKeyIdToHex32bit(keyId);
|
||||
return header?"0x":"" + convertKeyIdToHex32bit(keyId >> 32) + convertKeyIdToHex32bit(keyId);
|
||||
}
|
||||
|
||||
public static String convertKeyIdToHexShort(long keyId) {
|
||||
return "0x" + convertKeyIdToHex32bit(keyId);
|
||||
return convertKeyIdToHexShort(keyId, true);
|
||||
}
|
||||
|
||||
public static String convertKeyIdToHexShort(long keyId, boolean header) {
|
||||
return header?"0x":"" + convertKeyIdToHex32bit(keyId);
|
||||
}
|
||||
|
||||
private static String convertKeyIdToHex32bit(long keyId) {
|
||||
@ -258,6 +274,14 @@ public class KeyFormattingUtils {
|
||||
return hexString;
|
||||
}
|
||||
|
||||
public static String getKeyIdAsHexFromFingerprint(byte[] fingerprint, boolean header) {
|
||||
return convertKeyIdToHex(getKeyIdFromFingerprint(fingerprint), header);
|
||||
}
|
||||
|
||||
public static String getShortKeyIdAsHexFromFingerprint(byte[] fingerprint, boolean header) {
|
||||
return convertKeyIdToHex(getShortKeyIdFromFingerprint(fingerprint), header);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a human-readable version of a key ID, which is usually 64 bits: lower-case, no
|
||||
* leading 0x, space-separated quartets (for keys whose length in hex is divisible by 4)
|
||||
|
@ -1289,5 +1289,6 @@
|
||||
<string name="snack_yubi_other">Different key stored on YubiKey!</string>
|
||||
<string name="error_nfc">"NFC Error: %s"</string>
|
||||
<string name="error_pin_nodefault">Default PIN was rejected!</string>
|
||||
<string name="error_bluetooth_file">Error creating temporary file. Bluetooth sharing will fail.</string>
|
||||
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user