aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport
diff options
context:
space:
mode:
authorAdithya Abraham Philip <adithyaphilip@gmail.com>2015-11-25 01:35:41 +0530
committerAdithya Abraham Philip <adithyaphilip@gmail.com>2015-12-06 00:46:52 +0530
commitf29280bbb268d112426c6662e1227118819fb904 (patch)
tree117ca2b3282fca1e10340e95f4bb07026eac7507 /OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport
parenta0b46b0d3b7dd201568d1f236cb25b0a794fc2c2 (diff)
downloadopen-keychain-f29280bbb268d112426c6662e1227118819fb904.tar.gz
open-keychain-f29280bbb268d112426c6662e1227118819fb904.tar.bz2
open-keychain-f29280bbb268d112426c6662e1227118819fb904.zip
added Facebook links support, reworked Preferences
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/FacebookKeyserver.java197
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java25
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ParcelableKeyRing.java27
7 files changed, 252 insertions, 18 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 869d107ab..df45de11f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java
@@ -48,6 +48,9 @@ public class CloudSearch {
if (cloudPrefs.searchKeybase) {
servers.add(new KeybaseKeyserver(proxy));
}
+ if (cloudPrefs.searchFacebook) {
+ servers.add(new FacebookKeyserver(proxy));
+ }
final ImportKeysList results = new ImportKeysList(servers.size());
ArrayList<Thread> searchThreads = new ArrayList<>();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/FacebookKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/FacebookKeyserver.java
new file mode 100644
index 000000000..d87a82a24
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/FacebookKeyserver.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.keyimport;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+
+import com.squareup.okhttp.OkHttpClient;
+import com.squareup.okhttp.Request;
+import com.squareup.okhttp.Response;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.pgp.PgpHelper;
+import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
+import org.sufficientlysecure.keychain.pgp.UncachedPublicKey;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
+import org.sufficientlysecure.keychain.util.Log;
+
+import java.io.IOException;
+import java.net.Proxy;
+
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+
+public class FacebookKeyserver extends Keyserver {
+
+ private static final String FB_KEY_URL_FORMAT
+ = "https://www.facebook.com/%s/publickey/download";
+ private static final String FB_HOST = "facebook.com";
+ private static final String FB_HOST_WWW = "www." + FB_HOST;
+
+ public static final String FB_URL = "https://" + FB_HOST_WWW;
+
+ public static final String ORIGIN = FB_URL;
+
+ private final Proxy mProxy;
+
+ public FacebookKeyserver(Proxy proxy) {
+ mProxy = proxy;
+ }
+
+ @Override
+ public List<ImportKeysListEntry> search(String fbUsername)
+ throws QueryFailedException, QueryNeedsRepairException {
+ List<ImportKeysListEntry> entry = new ArrayList<>(1);
+
+ String data = get(fbUsername);
+ // if we're here that means key retrieval succeeded,
+ // would have thrown an exception otherwise
+ try {
+ UncachedKeyRing keyRing = UncachedKeyRing.decodeFromData(data.getBytes());
+ try {
+ entry.add(getEntry(keyRing, fbUsername));
+ } catch (UnsupportedOperationException e) {
+ Log.e(Constants.TAG, "Parsing retrieved Facebook key failed!");
+ }
+ } catch (PgpGeneralException | IOException e) {
+ Log.e(Constants.TAG, "Failed parsing key from Facebook during search", e);
+ throw new QueryFailedException("No valid key found on Facebook");
+ }
+ return entry;
+ }
+
+ @Override
+ public String get(String fbUsername) throws QueryFailedException {
+ Log.d(Constants.TAG, "FacebookKeyserver get: " + fbUsername + " using Proxy: " + mProxy);
+
+ String data = query(fbUsername);
+
+ if (data == null) {
+ throw new QueryFailedException("data is null");
+ }
+
+ Matcher matcher = PgpHelper.PGP_PUBLIC_KEY.matcher(data);
+ if (matcher.find()) {
+ return matcher.group(1);
+ }
+ throw new QueryFailedException("data is null");
+ }
+
+ private String query(String fbUsername) throws QueryFailedException {
+ try {
+ String request = String.format(FB_KEY_URL_FORMAT, fbUsername);
+ Log.d(Constants.TAG, "fetching from Facebook with: " + request + " proxy: " + mProxy);
+
+ OkHttpClient client = new OkHttpClient();
+ client.setProxy(mProxy);
+
+ URL url = new URL(request);
+
+ Response response = client.newCall(new Request.Builder().url(url).build()).execute();
+
+ // contains body both in case of success or failure
+ String responseBody = response.body().string();
+
+ if (response.isSuccessful()) {
+ return responseBody;
+ } else {
+ // probably a 404 indicating that the key does not exist
+ throw new QueryFailedException("key for " + fbUsername + " not found on Facebook");
+ }
+
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "IOException at Facebook key download", e);
+ throw new QueryFailedException("Cannot connect to Facebook. "
+ + "Check your Internet connection!"
+ + (mProxy == Proxy.NO_PROXY ? "" : " Using proxy " + mProxy));
+ }
+ }
+
+ @Override
+ public void add(String armoredKey) throws AddKeyException {
+ // Implementing will require usage of FB API
+ throw new UnsupportedOperationException("Uploading keys not supported yet");
+ }
+
+ /**
+ * Facebook returns the entire key even during our searching phase.
+ *
+ * @throws UnsupportedOperationException if the key could not be parsed
+ */
+ @NonNull
+ public static ImportKeysListEntry getEntry(UncachedKeyRing ring, String fbUsername)
+ throws UnsupportedOperationException {
+ ImportKeysListEntry entry = new ImportKeysListEntry();
+ entry.setSecretKey(false); // keys imported from Facebook must be public
+ entry.addOrigin(ORIGIN);
+
+ // so we can query for the Facebook username directly, and to identify the source to
+ // download the key from
+ entry.setFbUsername(fbUsername);
+
+ UncachedPublicKey key = ring.getPublicKey();
+
+ entry.setPrimaryUserId(key.getPrimaryUserIdWithFallback());
+ entry.setUserIds(key.getUnorderedUserIds());
+ entry.updateMergedUserIds();
+
+ entry.setPrimaryUserId(key.getPrimaryUserIdWithFallback());
+
+ entry.setKeyId(key.getKeyId());
+ entry.setKeyIdHex(KeyFormattingUtils.convertKeyIdToHex(key.getKeyId()));
+
+ entry.setFingerprintHex(KeyFormattingUtils.convertFingerprintToHex(key.getFingerprint()));
+
+
+ try {
+ if (key.isEC()) { // unsupported key format (ECDH or ECDSA)
+ Log.e(Constants.TAG, "ECDH/ECDSA key - not supported.");
+ throw new UnsupportedOperationException(
+ "ECDH/ECDSA keys not supported yet");
+ }
+ entry.setBitStrength(key.getBitStrength());
+ final int algorithm = key.getAlgorithm();
+ entry.setAlgorithm(KeyFormattingUtils.getAlgorithmInfo(algorithm, key.getBitStrength(),
+ key.getCurveOid()));
+ } catch (NumberFormatException | NullPointerException e) {
+ Log.e(Constants.TAG, "Conversion for bit size, algorithm, or creation date failed.", e);
+ // can't use this key
+ throw new UnsupportedOperationException(
+ "Conversion for bit size, algorithm, or creation date failed.");
+ }
+
+ return entry;
+ }
+
+ public static String getUsernameFromUri(Uri uri) {
+ // path pattern is /username/publickey/download
+ return uri.getPathSegments().get(0);
+ }
+
+ public static boolean isFacebookHost(Uri uri) {
+ String host = uri.getHost();
+ return host.equalsIgnoreCase(FB_HOST) || host.equalsIgnoreCase(FB_HOST_WWW);
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java
index 03439228b..75a219191 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysList.java
@@ -77,9 +77,15 @@ public class ImportKeysList extends ArrayList<ImportKeysListEntry> {
for (String origin : incoming.getOrigins()) {
existing.addOrigin(origin);
- // to work properly, Keybase-sourced entries need to pass along the extra
- if (KeybaseKeyserver.ORIGIN.equals(origin)) {
- existing.setExtraData(incoming.getExtraData());
+ // to work properly, Keybase-sourced/Facebook-sourced entries need to pass along the
+ // identifying name/id
+ if (incoming.getKeybaseName() != null) {
+ existing.setKeybaseName(incoming.getKeybaseName());
+ // one of the origins is not a HKP keyserver
+ incomingFromHkpServer = false;
+ }
+ if (incoming.getFbUsername() != null) {
+ existing.setFbUsername(incoming.getFbUsername());
// one of the origins is not a HKP keyserver
incomingFromHkpServer = false;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java
index bb86d272f..b3cf70c9f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java
@@ -49,7 +49,8 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
private String mAlgorithm;
private boolean mSecretKey;
private String mPrimaryUserId;
- private String mExtraData;
+ private String mKeybaseName;
+ private String mFbUsername;
private String mQuery;
private ArrayList<String> mOrigins;
private Integer mHashCode = null;
@@ -81,7 +82,8 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
dest.writeString(mAlgorithm);
dest.writeByte((byte) (mSecretKey ? 1 : 0));
dest.writeByte((byte) (mSelected ? 1 : 0));
- dest.writeString(mExtraData);
+ dest.writeString(mKeybaseName);
+ dest.writeString(mFbUsername);
dest.writeStringList(mOrigins);
}
@@ -102,7 +104,8 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
vr.mAlgorithm = source.readString();
vr.mSecretKey = source.readByte() == 1;
vr.mSelected = source.readByte() == 1;
- vr.mExtraData = source.readString();
+ vr.mKeybaseName = source.readString();
+ vr.mFbUsername = source.readString();
vr.mOrigins = new ArrayList<>();
source.readStringList(vr.mOrigins);
@@ -229,12 +232,20 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
mPrimaryUserId = uid;
}
- public String getExtraData() {
- return mExtraData;
+ public String getKeybaseName() {
+ return mKeybaseName;
}
- public void setExtraData(String extraData) {
- mExtraData = extraData;
+ public String getFbUsername() {
+ return mFbUsername;
+ }
+
+ public void setKeybaseName(String keybaseName) {
+ mKeybaseName = keybaseName;
+ }
+
+ public void setFbUsername(String fbUsername) {
+ mFbUsername = fbUsername;
}
public String getQuery() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
index e4cd6738b..9243926df 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
@@ -81,8 +81,9 @@ public class KeybaseKeyserver extends Keyserver {
entry.setFingerprintHex(fingerprint);
entry.setKeyIdHex("0x" + match.getKeyID());
- // store extra info, so we can query for the keybase id directly
- entry.setExtraData(username);
+ // so we can query for the keybase id directly, and to identify the location from which the
+ // key is to be retrieved
+ entry.setKeybaseName(username);
final int bitStrength = match.getBitStrength();
entry.setBitStrength(bitStrength);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
index 00e8d6ac5..53e71f7a1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
@@ -21,7 +21,6 @@ package org.sufficientlysecure.keychain.keyimport;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.Proxy;
import java.util.List;
public abstract class Keyserver {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ParcelableKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ParcelableKeyRing.java
index 6f6c816ea..a94ce0dce 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ParcelableKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ParcelableKeyRing.java
@@ -32,24 +32,39 @@ public class ParcelableKeyRing implements Parcelable {
public final String mExpectedFingerprint;
public final String mKeyIdHex;
public final String mKeybaseName;
+ public final String mFbUsername;
public ParcelableKeyRing(byte[] bytes) {
+ this(null, bytes, false);
+ }
+
+ /**
+ * @param disAmbiguator useless parameter intended to distinguish this overloaded constructor
+ * for when null is passed as first two arguments
+ */
+ public ParcelableKeyRing(String expectedFingerprint, byte[] bytes, boolean disAmbiguator) {
mBytes = bytes;
- mExpectedFingerprint = null;
+ mExpectedFingerprint = expectedFingerprint;
mKeyIdHex = null;
mKeybaseName = null;
+ mFbUsername = null;
}
- public ParcelableKeyRing(String expectedFingerprint, byte[] bytes) {
- mBytes = bytes;
+
+ public ParcelableKeyRing(String expectedFingerprint, String keyIdHex) {
+ mBytes = null;
mExpectedFingerprint = expectedFingerprint;
- mKeyIdHex = null;
+ mKeyIdHex = keyIdHex;
mKeybaseName = null;
+ mFbUsername = null;
}
- public ParcelableKeyRing(String expectedFingerprint, String keyIdHex, String keybaseName) {
+
+ public ParcelableKeyRing(String expectedFingerprint, String keyIdHex, String keybaseName,
+ String fbUsername) {
mBytes = null;
mExpectedFingerprint = expectedFingerprint;
mKeyIdHex = keyIdHex;
mKeybaseName = keybaseName;
+ mFbUsername = fbUsername;
}
private ParcelableKeyRing(Parcel source) {
@@ -58,6 +73,7 @@ public class ParcelableKeyRing implements Parcelable {
mExpectedFingerprint = source.readString();
mKeyIdHex = source.readString();
mKeybaseName = source.readString();
+ mFbUsername = source.readString();
}
public void writeToParcel(Parcel dest, int flags) {
@@ -65,6 +81,7 @@ public class ParcelableKeyRing implements Parcelable {
dest.writeString(mExpectedFingerprint);
dest.writeString(mKeyIdHex);
dest.writeString(mKeybaseName);
+ dest.writeString(mFbUsername);
}
public static final Creator<ParcelableKeyRing> CREATOR = new Creator<ParcelableKeyRing>() {