From bc25b345fc13ba4b26dda9760f3dd62bdfcf5e5e Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Tue, 22 May 2018 10:01:47 +0200 Subject: [PATCH 1/6] Extract out contruction of Web Key Directory URLs Moves `toWebKeyDirectoryURL` to a separate class adding unit tests for URL correctness as well as support for spaces at the beginning and end of the e-mail. Spaces are frequently automatically inserted by soft keyboards. --- .../keyimport/WebKeyDirectoryClient.java | 48 +++-------------- .../keychain/util/WebKeyDirectoryUtil.java | 52 +++++++++++++++++++ .../util/WebKeyDirectoryUtilTest.java | 30 +++++++++++ 3 files changed, 88 insertions(+), 42 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtil.java create mode 100644 OpenKeychain/src/test/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtilTest.java diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/WebKeyDirectoryClient.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/WebKeyDirectoryClient.java index 06570ea21..e6df3cab9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/WebKeyDirectoryClient.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/WebKeyDirectoryClient.java @@ -19,30 +19,23 @@ package org.sufficientlysecure.keychain.keyimport; import android.support.annotation.Nullable; - +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; import org.sufficientlysecure.keychain.network.OkHttpClientFactory; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.util.ParcelableProxy; -import org.sufficientlysecure.keychain.util.ZBase32; +import org.sufficientlysecure.keychain.util.WebKeyDirectoryUtil; +import timber.log.Timber; import java.io.IOException; import java.net.HttpURLConnection; -import java.net.MalformedURLException; import java.net.Proxy; import java.net.URL; import java.net.UnknownHostException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import java.util.Collections; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import timber.log.Timber; /** @@ -59,12 +52,10 @@ public class WebKeyDirectoryClient implements KeyserverClient { private WebKeyDirectoryClient() { } - private static final Pattern EMAIL_PATTERN = Pattern.compile("^\\s*(.+)@(.+)\\s*$"); - @Override public List search(String name, ParcelableProxy proxy) throws QueryFailedException { - URL webKeyDirectoryURL = toWebKeyDirectoryURL(name); + URL webKeyDirectoryURL = WebKeyDirectoryUtil.toWebKeyDirectoryURL(name); if (webKeyDirectoryURL == null) { Timber.d("Name not supported by Web Key Directory Client: " + name); @@ -130,31 +121,4 @@ public class WebKeyDirectoryClient implements KeyserverClient { public void add(String armoredKey, ParcelableProxy proxy) { throw new UnsupportedOperationException("Uploading keys to Web Key Directory is not supported"); } - - @Nullable - private static URL toWebKeyDirectoryURL(String name) { - Matcher matcher = EMAIL_PATTERN.matcher(name); - - if (!matcher.matches()) { - return null; - } - - String localPart = matcher.group(1); - String encodedPart = ZBase32.encode(toSHA1(localPart.toLowerCase().getBytes())); - String domain = matcher.group(2); - - try { - return new URL("https://" + domain + "/.well-known/openpgpkey/hu/" + encodedPart); - } catch (MalformedURLException e) { - return null; - } - } - - private static byte[] toSHA1(byte[] input) { - try { - return MessageDigest.getInstance("SHA-1").digest(input); - } catch (NoSuchAlgorithmException e) { - throw new AssertionError("SHA-1 should always be available"); - } - } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtil.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtil.java new file mode 100644 index 000000000..716aee4a0 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtil.java @@ -0,0 +1,52 @@ +package org.sufficientlysecure.keychain.util; + +import android.support.annotation.Nullable; + +import java.net.MalformedURLException; +import java.net.URL; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class WebKeyDirectoryUtil { + + private static final Pattern EMAIL_PATTERN = Pattern.compile("^\\s*([^\\s]+)@([^\\s]+)\\s*$"); + + private WebKeyDirectoryUtil() { + } + + /** + * Tries to construct a Web Key Directory from a given name. + * Returns {@code null} if unsuccessful. + * + * @see Key Discovery + */ + @Nullable + public static URL toWebKeyDirectoryURL(String name) { + Matcher matcher = EMAIL_PATTERN.matcher(name); + + if (!matcher.matches()) { + return null; + } + + String localPart = matcher.group(1); + String encodedPart = ZBase32.encode(toSHA1(localPart.toLowerCase().getBytes())); + String domain = matcher.group(2); + + try { + return new URL("https://" + domain + "/.well-known/openpgpkey/hu/" + encodedPart); + } catch (MalformedURLException e) { + return null; + } + } + + private static byte[] toSHA1(byte[] input) { + try { + return MessageDigest.getInstance("SHA-1").digest(input); + } catch (NoSuchAlgorithmException e) { + throw new AssertionError("SHA-1 should always be available"); + } + } + +} diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtilTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtilTest.java new file mode 100644 index 000000000..fd0d40b7d --- /dev/null +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtilTest.java @@ -0,0 +1,30 @@ +package org.sufficientlysecure.keychain.util; + +import org.junit.Test; + +import java.net.URL; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNotNull; + +public class WebKeyDirectoryUtilTest { + + @Test + public void testWkd() { + URL url = WebKeyDirectoryUtil.toWebKeyDirectoryURL("test-wkd@openkeychain.org"); + assertNotNull(url); + assertEquals("openkeychain.org", url.getHost()); + assertEquals("https", url.getProtocol()); + assertEquals("/.well-known/openpgpkey/hu/4hg7tescnttreaouu4z1izeuuyibwww1", url.getPath()); + } + + @Test + public void testWkdWithSpaces() { + URL url = WebKeyDirectoryUtil.toWebKeyDirectoryURL(" test-wkd@openkeychain.org "); + assertNotNull(url); + assertEquals("openkeychain.org", url.getHost()); + assertEquals("https", url.getProtocol()); + assertEquals("/.well-known/openpgpkey/hu/4hg7tescnttreaouu4z1izeuuyibwww1", url.getPath()); + } + +} From 222231066efad1ac0c83a7e6b380489bf96e4de8 Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Tue, 22 May 2018 10:16:19 +0200 Subject: [PATCH 2/6] Show import key dialog when clicking on WKD URL This change extends WKD support for direct Web Key Directory URLs similarily to Facebook key URLs and HKP URLs. When a link with scheme `https` and path starting with `/.well-known/openpgpkey/hu/` is clicked Android will suggest importing the key with OpenKeychain. Fixes #2270. --- OpenKeychain/src/main/AndroidManifest.xml | 15 +++++++++++++++ .../keychain/ui/ImportKeysActivity.java | 11 +++++++++++ .../keychain/util/WebKeyDirectoryUtil.java | 12 ++++++++++++ .../keychain/util/WebKeyDirectoryUtilTest.java | 9 +++++++++ 4 files changed, 47 insertions(+) diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index 51ce60576..257fbcf78 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -719,6 +719,21 @@ + + + + + + + + + + + + + + + diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index 33963d7b3..f2d718b8a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -56,6 +56,8 @@ public class ImportKeysActivity extends BaseActivity implements ImportKeysListen public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER = Constants.IMPORT_KEY_FROM_KEYSERVER; public static final String ACTION_IMPORT_KEY_FROM_FACEBOOK = Constants.INTENT_PREFIX + "IMPORT_KEY_FROM_FACEBOOK"; + public static final String ACTION_IMPORT_KEY_FROM_WEB_KEY_DIRECTORY + = Constants.INTENT_PREFIX + "ACTION_IMPORT_KEY_FROM_WEB_KEY_DIRECTORY"; public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT = Constants.INTENT_PREFIX + "IMPORT_KEY_FROM_KEY_SERVER_AND_RETURN_RESULT"; public static final String ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN = Constants.INTENT_PREFIX @@ -121,6 +123,8 @@ public class ImportKeysActivity extends BaseActivity implements ImportKeysListen if (Intent.ACTION_VIEW.equals(action)) { if (FacebookKeyserverClient.isFacebookHost(dataUri)) { action = ACTION_IMPORT_KEY_FROM_FACEBOOK; + } else if ("https".equalsIgnoreCase(scheme) || dataUri.getPath().startsWith("/.well-known/openpgpkey/hu/")) { + action = ACTION_IMPORT_KEY_FROM_WEB_KEY_DIRECTORY; } else if ("http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme)) { action = ACTION_SEARCH_KEYSERVER_FROM_URL; } else if ("openpgp4fpr".equalsIgnoreCase(scheme)) { @@ -208,6 +212,13 @@ public class ImportKeysActivity extends BaseActivity implements ImportKeysListen startListFragment(null, null, fbUsername, cloudSearchPrefs); break; } + case ACTION_IMPORT_KEY_FROM_WEB_KEY_DIRECTORY: { + Preferences.CloudSearchPrefs cloudSearchPrefs = + new Preferences.CloudSearchPrefs(false, false, false, true, null); + // search immediately + startListFragment(null, null, dataUri.toString(), cloudSearchPrefs); + break; + } case ACTION_SEARCH_KEYSERVER_FROM_URL: { // get keyserver from URL HkpKeyserverAddress keyserver = HkpKeyserverAddress.createFromUri( diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtil.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtil.java index 716aee4a0..0531986ad 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtil.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtil.java @@ -24,6 +24,18 @@ public class WebKeyDirectoryUtil { */ @Nullable public static URL toWebKeyDirectoryURL(String name) { + if (name == null) { + return null; + } + + if (name.startsWith("https://") && name.contains("/.well-known/openpgpkey/hu/")) { + try { + return new URL(name); + } catch (MalformedURLException e) { + return null; + } + } + Matcher matcher = EMAIL_PATTERN.matcher(name); if (!matcher.matches()) { diff --git a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtilTest.java b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtilTest.java index fd0d40b7d..f468774ff 100644 --- a/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtilTest.java +++ b/OpenKeychain/src/test/java/org/sufficientlysecure/keychain/util/WebKeyDirectoryUtilTest.java @@ -27,4 +27,13 @@ public class WebKeyDirectoryUtilTest { assertEquals("/.well-known/openpgpkey/hu/4hg7tescnttreaouu4z1izeuuyibwww1", url.getPath()); } + @Test + public void testWkdDirectUrl() { + URL url = WebKeyDirectoryUtil.toWebKeyDirectoryURL("https://openkeychain.org/.well-known/openpgpkey/hu/4hg7tescnttreaouu4z1izeuuyibwww1"); + assertNotNull(url); + assertEquals("openkeychain.org", url.getHost()); + assertEquals("https", url.getProtocol()); + assertEquals("/.well-known/openpgpkey/hu/4hg7tescnttreaouu4z1izeuuyibwww1", url.getPath()); + } + } From f6b3887f93aa445312da9cfbfafe0edd3cf168ed Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Tue, 22 May 2018 11:06:31 +0200 Subject: [PATCH 3/6] Follow redirects when fetching keys over WKD Some hosts (like `kernel.org`) redirect all requests to a subdomain (in this case `www`). As WKD queries are always over HTTPS following redirects would be safe. --- .../keychain/keyimport/WebKeyDirectoryClient.java | 2 +- .../keychain/network/OkHttpClientFactory.java | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/WebKeyDirectoryClient.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/WebKeyDirectoryClient.java index e6df3cab9..66058aedf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/WebKeyDirectoryClient.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/WebKeyDirectoryClient.java @@ -94,7 +94,7 @@ public class WebKeyDirectoryClient implements KeyserverClient { Request request = new Request.Builder().url(url).build(); - OkHttpClient client = OkHttpClientFactory.getClientPinnedIfAvailable(url, proxy); + OkHttpClient client = OkHttpClientFactory.getClientPinnedIfAvailableWithRedirects(url, proxy); Response response = client.newCall(request).execute(); if (response.isSuccessful()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/OkHttpClientFactory.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/OkHttpClientFactory.java index 1d2bdc6f5..507a9509c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/OkHttpClientFactory.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/network/OkHttpClientFactory.java @@ -47,10 +47,18 @@ public class OkHttpClientFactory { } public static OkHttpClient getClientPinnedIfAvailable(URL url, Proxy proxy) { + // don't follow any redirects for keyservers, as discussed in the security audit + return getClientPinnedIfAvailable(url, proxy, false); + } + + public static OkHttpClient getClientPinnedIfAvailableWithRedirects(URL url, Proxy proxy) { + return getClientPinnedIfAvailable(url, proxy, true); + } + + private static OkHttpClient getClientPinnedIfAvailable(URL url, Proxy proxy, boolean followRedirects) { OkHttpClient.Builder builder = new OkHttpClient.Builder(); - // don't follow any redirects for keyservers, as discussed in the security audit - builder.followRedirects(false) + builder.followRedirects(followRedirects) .followSslRedirects(false); if (proxy != null) { From fe78850b3dcf49635bb84ad191966c13c69fd045 Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Tue, 22 May 2018 21:31:38 +0200 Subject: [PATCH 4/6] Automatically construct CloudSearchPrefs using auto-value --- .../keychain/keyimport/CloudSearch.java | 10 +-- .../keychain/ui/ImportKeysActivity.java | 7 +- .../keychain/util/Preferences.java | 89 ++++++++----------- 3 files changed, 43 insertions(+), 63 deletions(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java index de6807e4a..51c840d89 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java @@ -42,16 +42,16 @@ public class CloudSearch { // it's a Vector for sync, multiple threads might report problems final Vector problems = new Vector<>(); - if (cloudPrefs.searchKeyserver) { - servers.add(HkpKeyserverClient.fromHkpKeyserverAddress(cloudPrefs.keyserver)); + if (cloudPrefs.isKeyserverEnabled()) { + servers.add(HkpKeyserverClient.fromHkpKeyserverAddress(cloudPrefs.getKeyserver())); } - if (cloudPrefs.searchKeybase) { + if (cloudPrefs.isKeybaseEnabled()) { servers.add(KeybaseKeyserverClient.getInstance()); } - if (cloudPrefs.searchFacebook) { + if (cloudPrefs.isFacebookEnabled()) { servers.add(FacebookKeyserverClient.getInstance()); } - if (cloudPrefs.searchWebKeyDirectory) { + if (cloudPrefs.isWebKeyDirectoryEnabled()) { servers.add(WebKeyDirectoryClient.getInstance()); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index f2d718b8a..eef8589cd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -207,14 +207,14 @@ public class ImportKeysActivity extends BaseActivity implements ImportKeysListen String fbUsername = FacebookKeyserverClient.getUsernameFromUri(dataUri); Preferences.CloudSearchPrefs cloudSearchPrefs = - new Preferences.CloudSearchPrefs(false, true, true, false, null); + Preferences.CloudSearchPrefs.createSocialOnly(); // search immediately startListFragment(null, null, fbUsername, cloudSearchPrefs); break; } case ACTION_IMPORT_KEY_FROM_WEB_KEY_DIRECTORY: { Preferences.CloudSearchPrefs cloudSearchPrefs = - new Preferences.CloudSearchPrefs(false, false, false, true, null); + Preferences.CloudSearchPrefs.createWebKeyDirectoryOnly(); // search immediately startListFragment(null, null, dataUri.toString(), cloudSearchPrefs); break; @@ -223,8 +223,7 @@ public class ImportKeysActivity extends BaseActivity implements ImportKeysListen // get keyserver from URL HkpKeyserverAddress keyserver = HkpKeyserverAddress.createFromUri( dataUri.getScheme() + "://" + dataUri.getAuthority()); - Preferences.CloudSearchPrefs cloudSearchPrefs = new Preferences.CloudSearchPrefs( - true, false, false, false, keyserver); + Preferences.CloudSearchPrefs cloudSearchPrefs = Preferences.CloudSearchPrefs.createKeyserverOnly(keyserver); Timber.d("Using keyserver: " + keyserver); // process URL to get operation and query diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java index 233eddf5f..4da18b909 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java @@ -18,28 +18,27 @@ package org.sufficientlysecure.keychain.util; -import java.net.Proxy; -import java.util.ArrayList; -import java.util.ListIterator; - import android.accounts.Account; import android.annotation.SuppressLint; import android.content.ContentResolver; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; -import android.os.Parcel; import android.os.Parcelable; import android.preference.PreferenceManager; - +import android.support.annotation.Nullable; +import com.google.auto.value.AutoValue; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants.Pref; import org.sufficientlysecure.keychain.KeychainApplication; import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress; import org.sufficientlysecure.keychain.service.KeyserverSyncAdapterService; - import timber.log.Timber; +import java.net.Proxy; +import java.util.ArrayList; +import java.util.ListIterator; + /** * Singleton Implementation of a Preference Helper @@ -345,7 +344,7 @@ public class Preferences { // cloud prefs public CloudSearchPrefs getCloudSearchPrefs() { - return new CloudSearchPrefs(mSharedPreferences.getBoolean(Pref.SEARCH_KEYSERVER, true), + return CloudSearchPrefs.create(mSharedPreferences.getBoolean(Pref.SEARCH_KEYSERVER, true), mSharedPreferences.getBoolean(Pref.SEARCH_KEYBASE, true), false, true, @@ -362,62 +361,44 @@ public class Preferences { editor.commit(); } - public static class CloudSearchPrefs implements Parcelable { - public final boolean searchKeyserver; - public final boolean searchKeybase; - public final boolean searchFacebook; - public final boolean searchWebKeyDirectory; - public final HkpKeyserverAddress keyserver; + @AutoValue + public static abstract class CloudSearchPrefs implements Parcelable { + public abstract boolean isKeyserverEnabled(); + public abstract boolean isKeybaseEnabled(); + public abstract boolean isFacebookEnabled(); + public abstract boolean isWebKeyDirectoryEnabled(); + + @Nullable + public abstract HkpKeyserverAddress getKeyserver(); /** - * @param searchKeyserver should passed keyserver be searched - * @param searchKeybase should keybase.io be searched - * @param keyserver the keyserver url authority to search on + * @param searchKeyserver should passed keyserver be searched + * @param searchKeybase should keybase.io be searched + * @param searchFacebook should Facebook be searched + * @param searchWebKeyDirectory should WKD be searched + * @param keyserver the keyserver url authority to search on */ - public CloudSearchPrefs(boolean searchKeyserver, boolean searchKeybase, - boolean searchFacebook, boolean searchWebKeyDirectory, - HkpKeyserverAddress keyserver) { - this.searchKeyserver = searchKeyserver; - this.searchKeybase = searchKeybase; - this.searchFacebook = searchFacebook; - this.searchWebKeyDirectory = searchWebKeyDirectory; - this.keyserver = keyserver; + public static CloudSearchPrefs create(boolean searchKeyserver, boolean searchKeybase, + boolean searchFacebook, boolean searchWebKeyDirectory, + @Nullable HkpKeyserverAddress keyserver) { + return new AutoValue_Preferences_CloudSearchPrefs(searchKeyserver, + searchKeybase, + searchFacebook, + searchWebKeyDirectory, + keyserver); } - protected CloudSearchPrefs(Parcel in) { - searchKeyserver = in.readByte() != 0x00; - searchKeybase = in.readByte() != 0x00; - searchFacebook = in.readByte() != 0x00; - searchWebKeyDirectory = in.readByte() != 0x00; - keyserver = in.readParcelable(HkpKeyserverAddress.class.getClassLoader()); + public static CloudSearchPrefs createWebKeyDirectoryOnly() { + return create(false, false, false, true, null); } - @Override - public int describeContents() { - return 0; + public static CloudSearchPrefs createKeyserverOnly(HkpKeyserverAddress keyserver) { + return create(true, false, false, false, keyserver); } - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeByte((byte) (searchKeyserver ? 0x01 : 0x00)); - dest.writeByte((byte) (searchKeybase ? 0x01 : 0x00)); - dest.writeByte((byte) (searchFacebook ? 0x01 : 0x00)); - dest.writeByte((byte) (searchWebKeyDirectory ? 0x01 : 0x00)); - dest.writeParcelable(keyserver, flags); + public static CloudSearchPrefs createSocialOnly() { + return create(false, true, true, false, null); } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - @Override - public CloudSearchPrefs createFromParcel(Parcel in) { - return new CloudSearchPrefs(in); - } - - @Override - public CloudSearchPrefs[] newArray(int size) { - return new CloudSearchPrefs[size]; - } - }; } // sync preferences From 92e7995b83f49deb9e64b7394598cb22894cf34b Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Tue, 22 May 2018 21:46:31 +0200 Subject: [PATCH 5/6] Add preference toggle for switching on/off WKD --- .../main/java/org/sufficientlysecure/keychain/Constants.java | 1 + .../org/sufficientlysecure/keychain/util/Preferences.java | 2 +- OpenKeychain/src/main/res/values/strings.xml | 2 ++ OpenKeychain/src/main/res/xml/cloud_search_preferences.xml | 5 +++++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java index fa3ac244d..9e1e676f0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java @@ -126,6 +126,7 @@ public final class Constants { public static final String CACHED_CONSOLIDATE = "cachedConsolidate"; public static final String SEARCH_KEYSERVER = "search_keyserver_pref"; public static final String SEARCH_KEYBASE = "search_keybase_pref"; + public static final String SEARCH_WEB_KEY_DIRECTORY = "search_wkd_pref"; public static final String USE_NUMKEYPAD_FOR_SECURITY_TOKEN_PIN = "useNumKeypadForYubikeyPin"; public static final String ENCRYPT_FILENAMES = "encryptFilenames"; public static final String FILE_USE_COMPRESSION = "useFileCompression"; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java index 4da18b909..a44c101fb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java @@ -347,7 +347,7 @@ public class Preferences { return CloudSearchPrefs.create(mSharedPreferences.getBoolean(Pref.SEARCH_KEYSERVER, true), mSharedPreferences.getBoolean(Pref.SEARCH_KEYBASE, true), false, - true, + mSharedPreferences.getBoolean(Pref.SEARCH_WEB_KEY_DIRECTORY, true), getPreferredKeyserver()); } diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 0ed0fb1c2..1d14bfd09 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -211,6 +211,8 @@ "Search keys on keybase.io" "Facebook" "Search keys on Facebook by username" + "Web Key Directory" + "Search keys using Web Key Directory" "Automatic key updates" "Every three days, keys are updated from the preferred keyserver" diff --git a/OpenKeychain/src/main/res/xml/cloud_search_preferences.xml b/OpenKeychain/src/main/res/xml/cloud_search_preferences.xml index e1ab50d63..6c5540098 100644 --- a/OpenKeychain/src/main/res/xml/cloud_search_preferences.xml +++ b/OpenKeychain/src/main/res/xml/cloud_search_preferences.xml @@ -14,4 +14,9 @@ android:key="search_keybase_pref" android:summary="@string/pref_keybase_summary" android:title="@string/pref_keybase" /> + \ No newline at end of file From 7e3c985c54bb94c81491de93d7f347a1f88558ec Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Wed, 23 May 2018 15:02:10 +0200 Subject: [PATCH 6/6] Add intent filter for handling WKD link in Firefox Firefox for Android requires `mimeType` condition on the intent filter. Built-in browsers (e.g. Chrome) need an intent filter that will *not* have `mimeType` conditions. Using two common MIME types: `application/octet-stream` is mentioned in the I-D and `application/pgp-keys` is a common type for keys used in the wild. --- OpenKeychain/src/main/AndroidManifest.xml | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml index 257fbcf78..b6ab4338d 100644 --- a/OpenKeychain/src/main/AndroidManifest.xml +++ b/OpenKeychain/src/main/AndroidManifest.xml @@ -719,7 +719,7 @@ - + @@ -732,6 +732,27 @@ + + + + + + + + + + + + + + + + + + + + +