mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-27 19:22:14 -05:00
Merge pull request #627 from thi/improve-keybase.io-support
Improve keybase.io support
This commit is contained in:
commit
bbf19248ef
@ -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 {
|
||||
|
@ -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<ImportKeysListEntry> CREATOR = new Creator<ImportKeysListEntry>() {
|
||||
@ -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);
|
||||
|
@ -41,6 +41,11 @@ public class KeybaseKeyServer extends KeyServer {
|
||||
InsufficientQuery {
|
||||
ArrayList<ImportKeysListEntry> results = new ArrayList<ImportKeysListEntry>();
|
||||
|
||||
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) {
|
||||
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<String> userIds = new ArrayList<String>();
|
||||
String name = "keybase.io/" + keybaseID + " <" + keybaseID + "@keybase.io>";
|
||||
String name = fullName + " <keybase.io/" + keybaseId + ">";
|
||||
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;
|
||||
|
@ -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 {
|
||||
|
@ -146,14 +146,19 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user