diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyServer.java index 85ce6bfcc..8d1e1f460 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyServer.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyServer.java @@ -247,7 +247,7 @@ public class HkpKeyServer extends KeyServer { // see http://bit.ly/1d4bxbk and http://bit.ly/1gD1wwr String fingerprintOrKeyId = matcher.group(1); if (fingerprintOrKeyId.length() > 16) { - entry.setFingerPrintHex(fingerprintOrKeyId.toLowerCase(Locale.US)); + entry.setFingerprintHex(fingerprintOrKeyId.toLowerCase(Locale.US)); entry.setKeyIdHex("0x" + fingerprintOrKeyId.substring(fingerprintOrKeyId.length() - 16, fingerprintOrKeyId.length())); } else { 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 1199290e0..4a8d58e56 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java @@ -45,11 +45,12 @@ public class ImportKeysListEntry implements Serializable, Parcelable { public String keyIdHex; public boolean revoked; public Date date; // TODO: not displayed - public String fingerPrintHex; + public String fingerprintHex; public int bitStrength; public String algorithm; public boolean secretKey; public String mPrimaryUserId; + private String mExtraData; private boolean mSelected; @@ -66,7 +67,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { dest.writeLong(keyId); dest.writeByte((byte) (revoked ? 1 : 0)); dest.writeSerializable(date); - dest.writeString(fingerPrintHex); + dest.writeString(fingerprintHex); dest.writeString(keyIdHex); dest.writeInt(bitStrength); dest.writeString(algorithm); @@ -74,6 +75,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { dest.writeByte((byte) (mSelected ? 1 : 0)); dest.writeInt(mBytes.length); dest.writeByteArray(mBytes); + dest.writeString(mExtraData); } public static final Creator CREATOR = new Creator() { @@ -85,7 +87,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { vr.keyId = source.readLong(); vr.revoked = source.readByte() == 1; vr.date = (Date) source.readSerializable(); - vr.fingerPrintHex = source.readString(); + vr.fingerprintHex = source.readString(); vr.keyIdHex = source.readString(); vr.bitStrength = source.readInt(); vr.algorithm = source.readString(); @@ -93,6 +95,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { vr.mSelected = source.readByte() == 1; vr.mBytes = new byte[source.readInt()]; source.readByteArray(vr.mBytes); + vr.mExtraData = source.readString(); return vr; } @@ -150,12 +153,12 @@ public class ImportKeysListEntry implements Serializable, Parcelable { this.date = date; } - public String getFingerPrintHex() { - return fingerPrintHex; + public String getFingerprintHex() { + return fingerprintHex; } - public void setFingerPrintHex(String fingerPrintHex) { - this.fingerPrintHex = fingerPrintHex; + public void setFingerprintHex(String fingerprintHex) { + this.fingerprintHex = fingerprintHex; } public int getBitStrength() { @@ -198,6 +201,14 @@ public class ImportKeysListEntry implements Serializable, Parcelable { mPrimaryUserId = uid; } + public String getExtraData() { + return mExtraData; + } + + public void setExtraData(String extraData) { + mExtraData = extraData; + } + /** * Constructor for later querying from keyserver */ @@ -260,7 +271,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { this.keyIdHex = PgpKeyHelper.convertKeyIdToHex(keyId); this.revoked = key.isRevoked(); - this.fingerPrintHex = PgpKeyHelper.convertFingerprintToHex(key.getFingerprint()); + this.fingerprintHex = PgpKeyHelper.convertFingerprintToHex(key.getFingerprint()); this.bitStrength = key.getBitStrength(); final int algorithm = key.getAlgorithm(); this.algorithm = PgpKeyHelper.getAlgorithmInfo(context, algorithm); 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 7ffe123c0..953cf3cbb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyServer.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyServer.java @@ -41,6 +41,11 @@ public class KeybaseKeyServer extends KeyServer { InsufficientQuery { ArrayList results = new ArrayList(); + if (query.startsWith("0x")) { + // cut off "0x" if a user is searching for a key id + query = query.substring(2); + } + JSONObject fromQuery = getFromKeybase("_/api/1.0/user/autocomplete.json?q=", query); try { @@ -50,23 +55,32 @@ public class KeybaseKeyServer extends KeyServer { // only list them if they have a key if (JWalk.optObject(match, "components", "key_fingerprint") != null) { - results.add(makeEntry(match)); + String keybaseId = JWalk.getString(match, "components", "username", "val"); + String fingerprint = JWalk.getString(match, "components", "key_fingerprint", "val"); + fingerprint = fingerprint.replace(" ", "").toUpperCase(); + + if (keybaseId.equals(query) || fingerprint.startsWith(query.toUpperCase())) { + results.add(makeEntry(match)); + } else { + results.add(makeEntry(match)); + } } } } catch (Exception e) { + Log.e(Constants.TAG, "keybase result parsing error", e); throw new QueryException("Unexpected structure in keybase search result: " + e.getMessage()); } return results; } - private JSONObject getUser(String keybaseID) throws QueryException { + private JSONObject getUser(String keybaseId) throws QueryException { try { - return getFromKeybase("_/api/1.0/user/lookup.json?username=", keybaseID); + return getFromKeybase("_/api/1.0/user/lookup.json?username=", keybaseId); } catch (Exception e) { String detail = ""; - if (keybaseID != null) { - detail = ". Query was for user '" + keybaseID + "'"; + if (keybaseId != null) { + detail = ". Query was for user '" + keybaseId + "'"; } throw new QueryException(e.getMessage() + detail); } @@ -74,35 +88,50 @@ public class KeybaseKeyServer extends KeyServer { private ImportKeysListEntry makeEntry(JSONObject match) throws QueryException, JSONException { - String keybaseID = JWalk.getString(match, "components", "username", "val"); - String key_fingerprint = JWalk.getString(match, "components", "key_fingerprint", "val"); - key_fingerprint = key_fingerprint.replace(" ", "").toUpperCase(); - match = getUser(keybaseID); - final ImportKeysListEntry entry = new ImportKeysListEntry(); + String keybaseId = JWalk.getString(match, "components", "username", "val"); + String fullName = JWalk.getString(match, "components", "full_name", "val"); + String fingerprint = JWalk.getString(match, "components", "key_fingerprint", "val"); + fingerprint = fingerprint.replace(" ", "").toUpperCase(); + + // in anticipation of a full fingerprint, only use the last 16 chars as 64-bit key id + entry.setKeyIdHex("0x" + fingerprint.substring(Math.max(0, fingerprint.length() - 16))); + // store extra info, so we can query for the keybase id directly + entry.setExtraData(keybaseId); // TODO: Fix; have suggested keybase provide this value to avoid search-time crypto calls - entry.setBitStrength(4096); - entry.setAlgorithm("RSA"); - entry.setKeyIdHex("0x" + key_fingerprint); - entry.setRevoked(false); + //entry.setBitStrength(4096); + //entry.setAlgorithm("RSA"); - // ctime - final long creationDate = JWalk.getLong(match, "them", "public_keys", "primary", "ctime"); - final GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC")); - tmpGreg.setTimeInMillis(creationDate * 1000); - entry.setDate(tmpGreg.getTime()); + entry.setFingerprintHex(fingerprint); - // key bits - // we have to fetch the user object to construct the search-result list, so we might as - // well (weakly) remember the key, in case they try to import it - mKeyCache.put(keybaseID, JWalk.getString(match,"them", "public_keys", "primary", "bundle")); + // key data + // currently there's no need to query the user right away, and it should be avoided, so the + // user doesn't experience lag and doesn't download many keys unnecessarily, but should we + // require to do it at soe point: + // (weakly) remember the key, in case the user tries to import it + //mKeyCache.put(keybaseId, JWalk.getString(match, "them", "public_keys", "primary", "bundle")); - // String displayName = JWalk.getString(match, "them", "profile", "full_name"); ArrayList userIds = new ArrayList(); - String name = "keybase.io/" + keybaseID + " <" + keybaseID + "@keybase.io>"; + String name = fullName + " "; userIds.add(name); - userIds.add(keybaseID); + try { + userIds.add("github.com/" + JWalk.getString(match, "components", "github", "val")); + } catch (JSONException e) { + // ignore + } + try { + userIds.add("twitter.com/" + JWalk.getString(match, "components", "twitter", "val")); + } catch (JSONException e) { + // ignore + } + try { + JSONArray array = JWalk.getArray(match, "components", "websites"); + JSONObject website = array.getJSONObject(0); + userIds.add(JWalk.getString(website, "val")); + } catch (JSONException e) { + // ignore + } entry.setUserIds(userIds); entry.setPrimaryUserId(name); return entry; @@ -158,4 +187,4 @@ public class KeybaseKeyServer extends KeyServer { public void add(String armoredKey) throws AddKeyException { throw new AddKeyException(); } -} \ No newline at end of file +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index f1e30c560..805bb9dad 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -749,8 +749,8 @@ public class KeychainIntentService extends IntentService KeybaseKeyServer server = new KeybaseKeyServer(); for (ImportKeysListEntry entry : entries) { // the keybase handle is in userId(1) - String keybaseID = entry.getUserIds().get(1); - byte[] downloadedKeyBytes = server.get(keybaseID).getBytes(); + String keybaseId = entry.getExtraData(); + byte[] downloadedKeyBytes = server.get(keybaseId).getBytes(); // create PGPKeyRing object based on downloaded armored key PGPKeyRing downloadedKey = null; @@ -802,8 +802,8 @@ public class KeychainIntentService extends IntentService for (ImportKeysListEntry entry : entries) { // if available use complete fingerprint for get request byte[] downloadedKeyBytes; - if (entry.getFingerPrintHex() != null) { - downloadedKeyBytes = server.get("0x" + entry.getFingerPrintHex()).getBytes(); + if (entry.getFingerprintHex() != null) { + downloadedKeyBytes = server.get("0x" + entry.getFingerprintHex()).getBytes(); } else { downloadedKeyBytes = server.get(entry.getKeyIdHex()).getBytes(); } @@ -829,10 +829,10 @@ public class KeychainIntentService extends IntentService } // verify downloaded key by comparing fingerprints - if (entry.getFingerPrintHex() != null) { + if (entry.getFingerprintHex() != null) { String downloadedKeyFp = PgpKeyHelper.convertFingerprintToHex( downloadedKey.getPublicKey().getFingerprint()); - if (downloadedKeyFp.equals(entry.getFingerPrintHex())) { + if (downloadedKeyFp.equals(entry.getFingerprintHex())) { Log.d(Constants.TAG, "fingerprint of downloaded key is the same as " + "the requested fingerprint!"); } else { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java index 9d323c822..c1fb9ae94 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java @@ -146,14 +146,19 @@ public class ImportKeysAdapter extends ArrayAdapter { holder.keyId.setText(entry.keyIdHex); - if (entry.fingerPrintHex != null) { + if (entry.fingerprintHex != null) { holder.fingerprint.setVisibility(View.VISIBLE); - holder.fingerprint.setText(PgpKeyHelper.colorizeFingerprint(entry.fingerPrintHex)); + holder.fingerprint.setText(PgpKeyHelper.colorizeFingerprint(entry.fingerprintHex)); } else { holder.fingerprint.setVisibility(View.GONE); } - holder.algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm); + if (entry.bitStrength != 0 && entry.algorithm != null) { + holder.algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm); + holder.algorithm.setVisibility(View.VISIBLE); + } else { + holder.algorithm.setVisibility(View.INVISIBLE); + } if (entry.revoked) { holder.status.setVisibility(View.VISIBLE); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java index 4175592d6..d5329e6f6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java @@ -108,7 +108,7 @@ public class ImportKeysListServerLoader * set fingerprint explicitly after query * to enforce a check when the key is imported by KeychainIntentService */ - uniqueEntry.setFingerPrintHex(fingerprint); + uniqueEntry.setFingerprintHex(fingerprint); uniqueEntry.setSelected(true); mEntryList.add(uniqueEntry); }