diff options
Diffstat (limited to 'OpenKeychain/src/main/java')
3 files changed, 99 insertions, 9 deletions
| diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java index 710dbf8aa..161979ce3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java @@ -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)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java index 6bd3a9303..4141da202 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java @@ -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      } -}
\ No newline at end of file +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java index 91a7d361a..0b80b5fe9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java @@ -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) | 
