mirror of
https://github.com/moparisthebest/open-keychain
synced 2025-02-24 23:41:45 -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.Preferences;
|
||||||
import org.sufficientlysecure.keychain.util.TlsHelper;
|
import org.sufficientlysecure.keychain.util.TlsHelper;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FilenameFilter;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.util.HashMap;
|
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(),
|
brandGlowEffect(getApplicationContext(),
|
||||||
getApplicationContext().getResources().getColor(R.color.primary));
|
getApplicationContext().getResources().getColor(R.color.primary));
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ import android.net.Uri;
|
|||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.FileObserver;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.CursorLoader;
|
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.Log;
|
||||||
import org.sufficientlysecure.keychain.util.NfcHelper;
|
import org.sufficientlysecure.keychain.util.NfcHelper;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
|
||||||
@ -175,11 +179,11 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
|||||||
boolean toClipboard) {
|
boolean toClipboard) {
|
||||||
try {
|
try {
|
||||||
String content;
|
String content;
|
||||||
|
byte[] fingerprintData = (byte[]) providerHelper.getGenericData(
|
||||||
|
KeyRings.buildUnifiedKeyRingUri(dataUri),
|
||||||
|
Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
|
||||||
if (fingerprintOnly) {
|
if (fingerprintOnly) {
|
||||||
byte[] data = (byte[]) providerHelper.getGenericData(
|
String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintData);
|
||||||
KeyRings.buildUnifiedKeyRingUri(dataUri),
|
|
||||||
Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
|
|
||||||
String fingerprint = KeyFormattingUtils.convertFingerprintToHex(data);
|
|
||||||
if (!toClipboard) {
|
if (!toClipboard) {
|
||||||
content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
|
content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
|
||||||
} else {
|
} else {
|
||||||
@ -213,13 +217,62 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
|||||||
Intent sendIntent = new Intent(Intent.ACTION_SEND);
|
Intent sendIntent = new Intent(Intent.ACTION_SEND);
|
||||||
sendIntent.putExtra(Intent.EXTRA_TEXT, content);
|
sendIntent.putExtra(Intent.EXTRA_TEXT, content);
|
||||||
sendIntent.setType("text/plain");
|
sendIntent.setType("text/plain");
|
||||||
|
|
||||||
String title;
|
String title;
|
||||||
if (fingerprintOnly) {
|
if (fingerprintOnly) {
|
||||||
title = getResources().getString(R.string.title_share_fingerprint_with);
|
title = getResources().getString(R.string.title_share_fingerprint_with);
|
||||||
} else {
|
} else {
|
||||||
title = getResources().getString(R.string.title_share_key);
|
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) {
|
} catch (PgpGeneralException | IOException e) {
|
||||||
Log.e(Constants.TAG, "error processing key!", 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();
|
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
|
* Convert key id from long to 64 bit hex string
|
||||||
* <p/>
|
* <p/>
|
||||||
@ -238,16 +246,24 @@ public class KeyFormattingUtils {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static String convertKeyIdToHex(long keyId) {
|
public static String convertKeyIdToHex(long keyId) {
|
||||||
|
return convertKeyIdToHex(keyId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String convertKeyIdToHex(long keyId, boolean header) {
|
||||||
long upper = keyId >> 32;
|
long upper = keyId >> 32;
|
||||||
if (upper == 0) {
|
if (upper == 0) {
|
||||||
// this is a short key id
|
// 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) {
|
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) {
|
private static String convertKeyIdToHex32bit(long keyId) {
|
||||||
@ -258,6 +274,14 @@ public class KeyFormattingUtils {
|
|||||||
return hexString;
|
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
|
* 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)
|
* 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="snack_yubi_other">Different key stored on YubiKey!</string>
|
||||||
<string name="error_nfc">"NFC Error: %s"</string>
|
<string name="error_nfc">"NFC Error: %s"</string>
|
||||||
<string name="error_pin_nodefault">Default PIN was rejected!</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>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user