ditch keybase

This commit is contained in:
Vincent Breitmoser 2019-11-15 11:47:46 +01:00
parent 5e0a17b966
commit d3e48db520
35 changed files with 41 additions and 1344 deletions

4
.gitmodules vendored
View file

@ -2,10 +2,6 @@
path = extern/openpgp-api-lib path = extern/openpgp-api-lib
url = https://github.com/open-keychain/openpgp-api.git url = https://github.com/open-keychain/openpgp-api.git
ignore = dirty ignore = dirty
[submodule "extern/KeybaseLib"]
path = extern/KeybaseLib
url = https://github.com/open-keychain/KeybaseLib.git
ignore = dirty
[submodule "extern/minidns"] [submodule "extern/minidns"]
path = extern/minidns path = extern/minidns
url = https://github.com/open-keychain/minidns.git url = https://github.com/open-keychain/minidns.git

View file

@ -61,7 +61,6 @@ dependencies {
implementation project(':extern:bouncycastle:pg') implementation project(':extern:bouncycastle:pg')
implementation project(':extern:bouncycastle:prov') implementation project(':extern:bouncycastle:prov')
implementation project(':extern:minidns') implementation project(':extern:minidns')
implementation project(':KeybaseLib')
implementation project(':extern:MaterialChipsInput') implementation project(':extern:MaterialChipsInput')
implementation "android.arch.work:work-runtime:1.0.0-alpha02" implementation "android.arch.work:work-runtime:1.0.0-alpha02"

View file

@ -1,38 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIGmzCCBIOgAwIBAgIJAPzhpcIBaOeNMA0GCSqGSIb3DQEBBQUAMIGPMQswCQYD
VQQGEwJVUzELMAkGA1UECBMCTlkxETAPBgNVBAcTCE5ldyBZb3JrMRQwEgYDVQQK
EwtLZXliYXNlIExMQzEXMBUGA1UECxMOQ2VydCBBdXRob3JpdHkxEzARBgNVBAMT
CmtleWJhc2UuaW8xHDAaBgkqhkiG9w0BCQEWDWNhQGtleWJhc2UuaW8wHhcNMTQw
MTAyMTY0MjMzWhcNMjMxMjMxMTY0MjMzWjCBjzELMAkGA1UEBhMCVVMxCzAJBgNV
BAgTAk5ZMREwDwYDVQQHEwhOZXcgWW9yazEUMBIGA1UEChMLS2V5YmFzZSBMTEMx
FzAVBgNVBAsTDkNlcnQgQXV0aG9yaXR5MRMwEQYDVQQDEwprZXliYXNlLmlvMRww
GgYJKoZIhvcNAQkBFg1jYUBrZXliYXNlLmlvMIICIjANBgkqhkiG9w0BAQEFAAOC
Ag8AMIICCgKCAgEA3sLA6ZG8uOvmlFvFLVIOURmcQrZyMFKbVu9/TeDiemls3w3/
JzVTduD+7KiUi9R7QcCW/V1ZpReTfunm7rfACiJ1fpIkjSQrgsvKDLghIzxIS5FM
I8utet5p6QtuJhaAwmmXn8xX05FvqWNbrcXRdpL4goFdigPsFK2xhTUiWatLMste
oShI7+zmrgkx75LeLMD0bL2uOf87JjOzbY8x2sUIZLGwPoATyG8WS38ey6KkJxRj
AhG3p+OTYEjYSrsAtQA6ImbeDpfSHKOB8HF3nVp//Eb4HEiEsWwBRbQXvAWh3DYL
GukFW0wiO0HVCoWY+bHL/Mqa0NdRGOlLsbL4Z4pLrhqKgSDU8umX9YuNRRaB0P5n
TkzyU6axHqzq990Gep/I62bjsBdYYp+DjSPK43mXRrfWJl2NTcl8xKAyfsOW+9hQ
9vwK0tpSicNxfYuUZs0BhfjSZ/Tc6Z1ERdgUYRiXTtohl+SRA2IgZMloHCllVMNj
EjXhguvHgLAOrcuyhVBupiUQGUHQvkMsr1Uz8VPNDFOJedwucRU2AaR881bknnSb
ds9+zNLsvUFV+BK7Qdnt/WkFpYL78rGwY47msi9Ooddx6fPyeg3qkJGM6cwn/boy
w9lQeleYDq8kyJdixIAxtAskNzRPJ4nDu2izTfByQoM8epwAWboc/gNFObMCAwEA
AaOB9zCB9DAdBgNVHQ4EFgQURqpATOw1gVVrzlqqFKbkfaKXvwowgcQGA1UdIwSB
vDCBuYAURqpATOw1gVVrzlqqFKbkfaKXvwqhgZWkgZIwgY8xCzAJBgNVBAYTAlVT
MQswCQYDVQQIEwJOWTERMA8GA1UEBxMITmV3IFlvcmsxFDASBgNVBAoTC0tleWJh
c2UgTExDMRcwFQYDVQQLEw5DZXJ0IEF1dGhvcml0eTETMBEGA1UEAxMKa2V5YmFz
ZS5pbzEcMBoGCSqGSIb3DQEJARYNY2FAa2V5YmFzZS5pb4IJAPzhpcIBaOeNMAwG
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggIBAA3Z5FIhulYghMuHdcHYTYWc
7xT5WD4hXQ0WALZs4p5Y+b2Af54o6v1wUE1Au97FORq5CsFXX/kGl/JzzTimeucn
YJwGuXMpilrlHCBAL5/lSQjA7qbYIolQ3SB9ON+LYuF1jKB9k8SqNp7qzucxT3tO
b8ZMDEPNsseC7NE2uwNtcW3yrTh6WZnSqg/jwswiWjHYDdG7U8FjMYlRol3wPux2
PizGbSgiR+ztI2OthxtxNWMrT9XKxNQTpcxOXnLuhiSwqH8PoY17ecP8VPpaa0K6
zym0zSkbroqydazaxcXRk3eSlc02Ktk7HzRzuqQQXhRMkxVnHbFHgGsz03L533pm
mlIEgBMggZkHwNvs1LR7f3v2McdKulDH7Mv8yyfguuQ5Jxxt7RJhUuqSudbEhoaM
6jAJwBkMFxsV2YnyFEd3eZ/qBYPf7TYHhyzmHW6WkSypGqSnXd4gYpJ8o7LxSf4F
inLjxRD+H9Xn1UVXWLM0gaBB7zZcXd2zjMpRsWgezf5IR5vyakJsc7fxzgor3Qeq
Ri6LvdEkhhFVl5rHMQBwNOPngySrq8cs/ikTLTfQVTYXXA4Ba1YyiMOlfaR1LhKw
If1AkUV0tfCTNRZ01EotKSK77+o+k214n+BAu+7mO+9B5Kb7lMFQcuWCHXKYB2Md
cT7Yh09F0QpFUd0ymEfv
-----END CERTIFICATE-----

View file

@ -132,7 +132,6 @@ public final class Constants {
public static final String FIRST_TIME_APP = "firstTimeApp"; public static final String FIRST_TIME_APP = "firstTimeApp";
public static final String CACHED_CONSOLIDATE = "cachedConsolidate"; public static final String CACHED_CONSOLIDATE = "cachedConsolidate";
public static final String SEARCH_KEYSERVER = "search_keyserver_pref"; 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 SEARCH_WEB_KEY_DIRECTORY = "search_wkd_pref";
public static final String USE_NUMKEYPAD_FOR_SECURITY_TOKEN_PIN = "useNumKeypadForYubikeyPin"; public static final String USE_NUMKEYPAD_FOR_SECURITY_TOKEN_PIN = "useNumKeypadForYubikeyPin";
public static final String ENCRYPT_FILENAMES = "encryptFilenames"; public static final String ENCRYPT_FILENAMES = "encryptFilenames";
@ -154,7 +153,6 @@ public final class Constants {
public static final String ENABLE_WIFI_SYNC_ONLY = "enableWifiSyncOnly"; public static final String ENABLE_WIFI_SYNC_ONLY = "enableWifiSyncOnly";
public static final String SYNC_WORK_UUID = "syncWorkUuid"; public static final String SYNC_WORK_UUID = "syncWorkUuid";
// other settings // other settings
public static final String EXPERIMENTAL_ENABLE_KEYBASE = "experimentalEnableKeybase";
public static final String EXPERIMENTAL_USB_ALLOW_UNTESTED = "experimentalUsbAllowUntested"; public static final String EXPERIMENTAL_USB_ALLOW_UNTESTED = "experimentalUsbAllowUntested";
public static final String EXPERIMENTAL_SMARTPGP_VERIFY_AUTHORITY = "smartpgp_authorities_pref"; public static final String EXPERIMENTAL_SMARTPGP_VERIFY_AUTHORITY = "smartpgp_authorities_pref";
public static final String EXPERIMENTAL_SMARTPGP_AUTHORITIES = "smartpgp_authorities"; public static final String EXPERIMENTAL_SMARTPGP_AUTHORITIES = "smartpgp_authorities";
@ -178,9 +176,9 @@ public final class Constants {
// we generally only track booleans. never snoop around in the user's string settings!! // we generally only track booleans. never snoop around in the user's string settings!!
public static final List<String> ANALYTICS_PREFS = Arrays.asList(USE_NORMAL_PROXY, USE_TOR_PROXY, public static final List<String> ANALYTICS_PREFS = Arrays.asList(USE_NORMAL_PROXY, USE_TOR_PROXY,
SYNC_CONTACTS, SYNC_KEYSERVER, ENABLE_WIFI_SYNC_ONLY, EXPERIMENTAL_ENABLE_KEYBASE, SYNC_CONTACTS, SYNC_KEYSERVER, ENABLE_WIFI_SYNC_ONLY,
EXPERIMENTAL_USB_ALLOW_UNTESTED, EXPERIMENTAL_USB_ALLOW_UNTESTED,
PASSPHRASE_CACHE_SUBS, SEARCH_KEYSERVER, SEARCH_KEYBASE, SEARCH_WEB_KEY_DIRECTORY, PASSPHRASE_CACHE_SUBS, SEARCH_KEYSERVER, SEARCH_WEB_KEY_DIRECTORY,
TEXT_USE_COMPRESSION, TEXT_SELF_ENCRYPT, FILE_USE_COMPRESSION, FILE_SELF_ENCRYPT, USE_ARMOR, TEXT_USE_COMPRESSION, TEXT_SELF_ENCRYPT, FILE_USE_COMPRESSION, FILE_SELF_ENCRYPT, USE_ARMOR,
USE_NUMKEYPAD_FOR_SECURITY_TOKEN_PIN, ENCRYPT_FILENAMES); USE_NUMKEYPAD_FOR_SECURITY_TOKEN_PIN, ENCRYPT_FILENAMES);
} }

View file

@ -102,7 +102,6 @@ public class KeychainApplication extends Application {
TlsCertificatePinning.addPinnedCertificate("keys.openpgp.org", getAssets(), "LetsEncryptCA.cer"); TlsCertificatePinning.addPinnedCertificate("keys.openpgp.org", getAssets(), "LetsEncryptCA.cer");
TlsCertificatePinning.addPinnedCertificate("hkps.pool.sks-keyservers.net", getAssets(), "hkps.pool.sks-keyservers.net.CA.cer"); TlsCertificatePinning.addPinnedCertificate("hkps.pool.sks-keyservers.net", getAssets(), "hkps.pool.sks-keyservers.net.CA.cer");
TlsCertificatePinning.addPinnedCertificate("pgp.mit.edu", getAssets(), "pgp.mit.edu.cer"); TlsCertificatePinning.addPinnedCertificate("pgp.mit.edu", getAssets(), "pgp.mit.edu.cer");
TlsCertificatePinning.addPinnedCertificate("api.keybase.io", getAssets(), "api.keybase.io.CA.cer");
TlsCertificatePinning.addPinnedCertificate("keyserver.ubuntu.com", getAssets(), "LetsEncryptCA.cer"); TlsCertificatePinning.addPinnedCertificate("keyserver.ubuntu.com", getAssets(), "LetsEncryptCA.cer");
KeyserverSyncManager.updateKeyserverSyncScheduleAsync(this, false); KeyserverSyncManager.updateKeyserverSyncScheduleAsync(this, false);

View file

@ -45,9 +45,6 @@ public class CloudSearch {
if (cloudPrefs.isKeyserverEnabled()) { if (cloudPrefs.isKeyserverEnabled()) {
servers.add(HkpKeyserverClient.fromHkpKeyserverAddress(cloudPrefs.getKeyserver())); servers.add(HkpKeyserverClient.fromHkpKeyserverAddress(cloudPrefs.getKeyserver()));
} }
if (cloudPrefs.isKeybaseEnabled()) {
servers.add(KeybaseKeyserverClient.getInstance());
}
if (cloudPrefs.isFacebookEnabled()) { if (cloudPrefs.isFacebookEnabled()) {
servers.add(FacebookKeyserverClient.getInstance()); servers.add(FacebookKeyserverClient.getInstance());
} }

View file

@ -77,14 +77,8 @@ public class ImportKeysList extends ArrayList<ImportKeysListEntry> {
if (incoming.getKeyserver() != null) { if (incoming.getKeyserver() != null) {
existing.setKeyserver(incoming.getKeyserver()); existing.setKeyserver(incoming.getKeyserver());
// Mail addresses returned by HKP servers are preferred over keybase.io IDs
existing.setPrimaryUserId(incoming.getPrimaryUserId()); existing.setPrimaryUserId(incoming.getPrimaryUserId());
modified = true;
} else if (incoming.getKeybaseName() != null) {
// to work properly, Keybase-sourced/Facebook-sourced entries need to pass along the
// identifying name/id
existing.setKeybaseName(incoming.getKeybaseName());
modified = true; modified = true;
} else if (incoming.getFbUsername() != null) { } else if (incoming.getFbUsername() != null) {
existing.setFbUsername(incoming.getFbUsername()); existing.setFbUsername(incoming.getFbUsername());

View file

@ -17,6 +17,18 @@
package org.sufficientlysecure.keychain.keyimport; package org.sufficientlysecure.keychain.keyimport;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import android.content.Context; import android.content.Context;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
@ -27,18 +39,6 @@ import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; import org.sufficientlysecure.keychain.pgp.UncachedPublicKey;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
public class ImportKeysListEntry implements Serializable, Parcelable { public class ImportKeysListEntry implements Serializable, Parcelable {
private static final long serialVersionUID = -7797972103284992662L; private static final long serialVersionUID = -7797972103284992662L;
@ -64,7 +64,6 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
private UserId mPrimaryUserId; private UserId mPrimaryUserId;
private HkpKeyserverAddress mKeyserver; private HkpKeyserverAddress mKeyserver;
private String mKeybaseName;
private String mFbUsername; private String mFbUsername;
private String mQuery; private String mQuery;
@ -197,14 +196,6 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
mKeyserver = keyserver; mKeyserver = keyserver;
} }
public String getKeybaseName() {
return mKeybaseName;
}
public void setKeybaseName(String keybaseName) {
mKeybaseName = keybaseName;
}
public String getFbUsername() { public String getFbUsername() {
return mFbUsername; return mFbUsername;
} }
@ -257,20 +248,11 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
return modified; return modified;
} }
public ArrayList<String> getKeybaseUserIds() {
ArrayList<String> keybaseUserIds = new ArrayList<>();
for (String s : mUserIds) {
if (s.contains(":"))
keybaseUserIds.add(s);
}
return keybaseUserIds;
}
/** /**
* Constructor for later querying from keyserver * Constructor for later querying from keyserver
*/ */
public ImportKeysListEntry() { public ImportKeysListEntry() {
// keys from keyserver are always public keys; from keybase too // keys from keyserver are always public keys
mSecretKey = false; mSecretKey = false;
mUserIds = new ArrayList<>(); mUserIds = new ArrayList<>();
@ -339,20 +321,8 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
private void sortMergedUserIds() { private void sortMergedUserIds() {
mSortedUserIds = new ArrayList<>(mMergedUserIds.entrySet()); mSortedUserIds = new ArrayList<>(mMergedUserIds.entrySet());
Collections.sort(mSortedUserIds, new Comparator<Map.Entry<String, HashSet<String>>>() { Collections.sort(mSortedUserIds,
@Override (entry1, entry2) -> entry1.getKey().compareTo(entry2.getKey()));
public int compare(Map.Entry<String, HashSet<String>> entry1,
Map.Entry<String, HashSet<String>> entry2) {
// sort keybase UserIds after non-Keybase
boolean e1IsKeybase = entry1.getKey().contains(":");
boolean e2IsKeybase = entry2.getKey().contains(":");
if (e1IsKeybase != e2IsKeybase) {
return (e1IsKeybase) ? 1 : -1;
}
return entry1.getKey().compareTo(entry2.getKey());
}
});
} }
@Override @Override
@ -377,7 +347,6 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
dest.writeString(mAlgorithm); dest.writeString(mAlgorithm);
dest.writeByte((byte) (mSecretKey ? 1 : 0)); dest.writeByte((byte) (mSecretKey ? 1 : 0));
dest.writeParcelable(mKeyserver, flags); dest.writeParcelable(mKeyserver, flags);
dest.writeString(mKeybaseName);
dest.writeString(mFbUsername); dest.writeString(mFbUsername);
} }
@ -400,7 +369,6 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
vr.mAlgorithm = source.readString(); vr.mAlgorithm = source.readString();
vr.mSecretKey = source.readByte() == 1; vr.mSecretKey = source.readByte() == 1;
vr.mKeyserver = source.readParcelable(HkpKeyserverAddress.class.getClassLoader()); vr.mKeyserver = source.readParcelable(HkpKeyserverAddress.class.getClassLoader());
vr.mKeybaseName = source.readString();
vr.mFbUsername = source.readString(); vr.mFbUsername = source.readString();
return vr; return vr;

View file

@ -1,121 +0,0 @@
/*
* Copyright (C) 2017 Schürmann & Breitmoser GbR
*
* 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 com.textuality.keybase.lib.KeybaseException;
import com.textuality.keybase.lib.KeybaseQuery;
import com.textuality.keybase.lib.Match;
import com.textuality.keybase.lib.User;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.network.OkHttpKeybaseClient;
import org.sufficientlysecure.keychain.util.ParcelableProxy;
import timber.log.Timber;
import java.util.ArrayList;
import java.util.List;
public class KeybaseKeyserverClient implements KeyserverClient {
public static KeybaseKeyserverClient getInstance() {
return new KeybaseKeyserverClient();
}
private KeybaseKeyserverClient() { }
@Override
public ArrayList<ImportKeysListEntry> search(String query, ParcelableProxy proxy) throws QueryFailedException,
QueryNeedsRepairException {
ArrayList<ImportKeysListEntry> results = new ArrayList<>();
if (query.startsWith("0x")) {
// cut off "0x" if a user is searching for a key id
query = query.substring(2);
}
if (query.isEmpty()) {
throw new QueryTooShortException();
}
try {
KeybaseQuery keybaseQuery = new KeybaseQuery(new OkHttpKeybaseClient());
keybaseQuery.setProxy(proxy.getProxy());
Iterable<Match> matches = keybaseQuery.search(query);
for (Match match : matches) {
results.add(makeEntry(match, query));
}
} catch (KeybaseException e) {
Timber.e(e, "keybase result parsing error");
throw new QueryFailedException("Unexpected structure in keybase search result: " + e.getMessage());
}
return results;
}
private ImportKeysListEntry makeEntry(Match match, String query) throws KeybaseException {
final ImportKeysListEntry entry = new ImportKeysListEntry();
entry.setQuery(query);
entry.setRevoked(false); // keybase doesnt say anything about revoked keys
String username = match.getUsername();
String fullName = match.getFullName();
String fingerprint = match.getFingerprint();
entry.setFingerprint(KeyFormattingUtils.convertFingerprintHexFingerprint(fingerprint));
entry.setKeyIdHex("0x" + match.getKeyID());
// 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);
final int algorithmId = match.getAlgorithmId();
entry.setAlgorithm(KeyFormattingUtils.getAlgorithmInfo(algorithmId, bitStrength, null));
ArrayList<String> userIds = new ArrayList<>();
String name = "<keybase.io/" + username + ">";
if (fullName != null) {
name = fullName + " " + name;
}
userIds.add(name);
List<String> proofLabels = match.getProofLabels();
for (String proofLabel : proofLabels) {
userIds.add(proofLabel);
}
entry.setUserIds(userIds);
entry.setPrimaryUserId(name);
return entry;
}
@Override
public String get(String id, ParcelableProxy proxy) throws QueryFailedException {
try {
KeybaseQuery keybaseQuery = new KeybaseQuery(new OkHttpKeybaseClient());
keybaseQuery.setProxy(proxy.getProxy());
return User.keyForUsername(keybaseQuery, id);
} catch (KeybaseException e) {
throw new QueryFailedException(e.getMessage());
}
}
@Override
public void add(String armoredKey, ParcelableProxy proxy) throws AddKeyException {
throw new AddKeyException();
}
}

View file

@ -26,7 +26,7 @@ import com.google.auto.value.AutoValue;
/** /**
* This class is a parcelable representation of either a keyring as raw data, * This class is a parcelable representation of either a keyring as raw data,
* or a (unique) reference to one as a fingerprint, keyid, or keybase name. * or a (unique) reference to one as a fingerprint, or keyid.
*/ */
@AutoValue @AutoValue
public abstract class ParcelableKeyRing implements Parcelable { public abstract class ParcelableKeyRing implements Parcelable {
@ -41,16 +41,14 @@ public abstract class ParcelableKeyRing implements Parcelable {
@Nullable @Nullable
public abstract String getKeyIdHex(); public abstract String getKeyIdHex();
@Nullable @Nullable
public abstract String getKeybaseName();
@Nullable
public abstract String getFbUsername(); public abstract String getFbUsername();
public static ParcelableKeyRing createFromEncodedBytes(byte[] bytes) { public static ParcelableKeyRing createFromEncodedBytes(byte[] bytes) {
return new AutoValue_ParcelableKeyRing(bytes, null, null, null, null); return new AutoValue_ParcelableKeyRing(bytes, null, null, null);
} }
public static ParcelableKeyRing createFromReference( public static ParcelableKeyRing createFromReference(
byte[] expectedFingerprint, String keyIdHex, String keybaseName, String fbUsername) { byte[] expectedFingerprint, String keyIdHex, String fbUsername) {
return new AutoValue_ParcelableKeyRing(null, expectedFingerprint, keyIdHex, keybaseName, fbUsername); return new AutoValue_ParcelableKeyRing(null, expectedFingerprint, keyIdHex, fbUsername);
} }
} }

View file

@ -51,8 +51,7 @@ public class ImportKeysListCloudLoader
* *
* @param loaderState state containing the string to search on servers for (if it is a * @param loaderState state containing the string to search on servers for (if it is a
* fingerprint, will enforce fingerprint check) and the keyserver to * fingerprint, will enforce fingerprint check) and the keyserver to
* search on (whether to search on the keyserver, and whether to search * search on (whether to search on the keyserver)
* keybase.io)
* @param parcelableProxy explicit proxy to use. If null, will retrieve from preferences * @param parcelableProxy explicit proxy to use. If null, will retrieve from preferences
*/ */
public ImportKeysListCloudLoader(Context context, CloudLoaderState loaderState, public ImportKeysListCloudLoader(Context context, CloudLoaderState loaderState,
@ -84,7 +83,7 @@ public class ImportKeysListCloudLoader
for (ImportKeysListEntry e : mEntryList) { for (ImportKeysListEntry e : mEntryList) {
if (e.getParcelableKeyRing() == null) { if (e.getParcelableKeyRing() == null) {
e.setParcelableKeyRing(ParcelableKeyRing.createFromReference(e.getFingerprint(), e.getKeyIdHex(), e.setParcelableKeyRing(ParcelableKeyRing.createFromReference(e.getFingerprint(), e.getKeyIdHex(),
e.getKeybaseName(), e.getFbUsername())); e.getFbUsername()));
} }
} }

View file

@ -1,55 +0,0 @@
/*
* Copyright (C) 2017 Schürmann & Breitmoser GbR
*
* 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.network;
import java.io.IOException;
import java.net.Proxy;
import java.net.URL;
import com.textuality.keybase.lib.KeybaseUrlConnectionClient;
import okhttp3.OkHttpClient;
import okhttp3.Request;
/**
* Wrapper for Keybase Lib
*/
public class OkHttpKeybaseClient implements KeybaseUrlConnectionClient {
@Override
public Response getUrlResponse(URL url, Proxy proxy, boolean isKeybase) throws IOException {
OkHttpClient client;
if (proxy != null) {
client = OkHttpClientFactory.getClientPinnedIfAvailable(url, proxy);
} else {
client = OkHttpClientFactory.getSimpleClient();
}
Request request = new Request.Builder()
.url(url).build();
okhttp3.Response okResponse = client.newCall(request).execute();
return new Response(okResponse.body().byteStream(), okResponse.code(), okResponse.message(), okResponse.headers().toMultimap());
}
@Override
public String getKeybaseBaseUrl() {
return "https://api.keybase.io/";
}
}

View file

@ -41,7 +41,6 @@ import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.keyimport.FacebookKeyserverClient; import org.sufficientlysecure.keychain.keyimport.FacebookKeyserverClient;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress; import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverClient; import org.sufficientlysecure.keychain.keyimport.HkpKeyserverClient;
import org.sufficientlysecure.keychain.keyimport.KeybaseKeyserverClient;
import org.sufficientlysecure.keychain.keyimport.KeyserverClient; import org.sufficientlysecure.keychain.keyimport.KeyserverClient;
import org.sufficientlysecure.keychain.keyimport.KeyserverClient.QueryNotFoundException; import org.sufficientlysecure.keychain.keyimport.KeyserverClient.QueryNotFoundException;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
@ -76,8 +75,7 @@ import timber.log.Timber;
* all steps for this import. * all steps for this import.
* For the import operation, the only valid source is an Iterator of * For the import operation, the only valid source is an Iterator of
* ParcelableKeyRing, each of which must contain either a single * ParcelableKeyRing, each of which must contain either a single
* keyring encoded as bytes, or a unique reference to a keyring * keyring encoded as bytes, or a unique reference to a keyring on keyservers.
* on keyservers and/or keybase.io.
* It is important to note that public keys should generally be imported before * It is important to note that public keys should generally be imported before
* secret keys, because some implementations (notably Symantec PGP Desktop) do * secret keys, because some implementations (notably Symantec PGP Desktop) do
* not include self certificates for user ids in the secret keyring. The import * not include self certificates for user ids in the secret keyring. The import
@ -93,7 +91,6 @@ public class ImportOperation extends BaseReadWriteOperation<ImportKeyringParcel>
private final KeyMetadataDao keyMetadataDao; private final KeyMetadataDao keyMetadataDao;
private FacebookKeyserverClient facebookServer; private FacebookKeyserverClient facebookServer;
private KeybaseKeyserverClient keybaseServer;
public ImportOperation(Context context, KeyWritableRepository databaseInteractor, Progressable progressable) { public ImportOperation(Context context, KeyWritableRepository databaseInteractor, Progressable progressable) {
super(context, databaseInteractor, progressable); super(context, databaseInteractor, progressable);
@ -355,14 +352,6 @@ public class ImportOperation extends BaseReadWriteOperation<ImportKeyringParcel>
} }
} }
boolean hasKeybaseName = entry.getKeybaseName() != null;
if (hasKeybaseName) {
UncachedKeyRing keybaseKey = fetchKeyFromKeybase(proxy, log, entry);
if (keybaseKey != null) {
key = mergeKeysOrUseEither(log, 3, key, keybaseKey);
}
}
boolean hasFacebookName = entry.getFbUsername() != null; boolean hasFacebookName = entry.getFbUsername() != null;
if (hasFacebookName) { if (hasFacebookName) {
UncachedKeyRing facebookKey = fetchKeyFromFacebook(proxy, log, entry); UncachedKeyRing facebookKey = fetchKeyFromFacebook(proxy, log, entry);
@ -414,32 +403,6 @@ public class ImportOperation extends BaseReadWriteOperation<ImportKeyringParcel>
} }
} }
private UncachedKeyRing fetchKeyFromKeybase(@NonNull ParcelableProxy proxy, OperationLog log, ParcelableKeyRing entry)
throws PgpGeneralException, IOException {
if (keybaseServer == null) {
keybaseServer = KeybaseKeyserverClient.getInstance();
}
try {
log.add(LogType.MSG_IMPORT_FETCH_KEYBASE, 2, entry.getKeybaseName());
byte[] data = keybaseServer.get(entry.getKeybaseName(), proxy).getBytes();
UncachedKeyRing keybaseKey = UncachedKeyRing.decodeFromData(data);
if (keybaseKey != null) {
log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER_OK, 3);
} else {
log.add(LogType.MSG_IMPORT_FETCH_ERROR_DECODE, 3);
}
return keybaseKey;
} catch (KeyserverClient.QueryFailedException e) {
// download failed, too bad. just proceed
Timber.e(e, "query failed");
log.add(LogType.MSG_IMPORT_FETCH_ERROR_KEYSERVER, 3, e.getMessage());
return null;
}
}
private UncachedKeyRing fetchKeyFromFacebook(@NonNull ParcelableProxy proxy, OperationLog log, ParcelableKeyRing entry) private UncachedKeyRing fetchKeyFromFacebook(@NonNull ParcelableProxy proxy, OperationLog log, ParcelableKeyRing entry)
throws PgpGeneralException, IOException { throws PgpGeneralException, IOException {
if (facebookServer == null) { if (facebookServer == null) {

View file

@ -72,7 +72,7 @@ public class KeySyncOperation extends BaseReadWriteOperation<KeySyncParcel> {
ArrayList<ParcelableKeyRing> result = new ArrayList<>(staleKeyFingerprints.size()); ArrayList<ParcelableKeyRing> result = new ArrayList<>(staleKeyFingerprints.size());
for (byte[] fingerprint : staleKeyFingerprints) { for (byte[] fingerprint : staleKeyFingerprints) {
Timber.d("Keyserver sync: Updating %s", KeyFormattingUtils.beautifyKeyId(fingerprint)); Timber.d("Keyserver sync: Updating %s", KeyFormattingUtils.beautifyKeyId(fingerprint));
result.add(ParcelableKeyRing.createFromReference(fingerprint, null, null, null)); result.add(ParcelableKeyRing.createFromReference(fingerprint, null, null));
} }
return result; return result;
} }

View file

@ -1,188 +0,0 @@
/*
* Copyright (C) 2017 Schürmann & Breitmoser GbR
*
* 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.operations;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.Proxy;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.support.annotation.NonNull;
import com.textuality.keybase.lib.KeybaseQuery;
import com.textuality.keybase.lib.Proof;
import com.textuality.keybase.lib.prover.Prover;
import de.measite.minidns.Client;
import de.measite.minidns.DNSMessage;
import de.measite.minidns.Question;
import de.measite.minidns.Record;
import de.measite.minidns.record.Data;
import de.measite.minidns.record.TXT;
import org.bouncycastle.openpgp.PGPUtil;
import org.json.JSONObject;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.network.OkHttpKeybaseClient;
import org.sufficientlysecure.keychain.network.orbot.OrbotHelper;
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
import org.sufficientlysecure.keychain.operations.results.KeybaseVerificationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation;
import org.sufficientlysecure.keychain.pgp.Progressable;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.service.KeybaseVerificationParcel;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Preferences;
public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificationParcel> {
public KeybaseVerificationOperation(Context context, KeyWritableRepository databaseInteractor,
Progressable progressable) {
super(context, databaseInteractor, progressable);
}
@NonNull
@Override
public KeybaseVerificationResult execute(KeybaseVerificationParcel keybaseInput,
CryptoInputParcel cryptoInput) {
Proxy proxy;
if (cryptoInput.getParcelableProxy() == null) {
// explicit proxy not set
if (!OrbotHelper.isOrbotInRequiredState(mContext)) {
return new KeybaseVerificationResult(null,
RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput);
}
proxy = Preferences.getPreferences(mContext).getParcelableProxy().getProxy();
} else {
proxy = cryptoInput.getParcelableProxy().getProxy();
}
String requiredFingerprint = keybaseInput.mRequiredFingerprint;
OperationResult.OperationLog log = new OperationResult.OperationLog();
log.add(OperationResult.LogType.MSG_KEYBASE_VERIFICATION, 0, requiredFingerprint);
try {
KeybaseQuery keybaseQuery = new KeybaseQuery(new OkHttpKeybaseClient());
keybaseQuery.setProxy(proxy);
String keybaseProof = keybaseInput.mKeybaseProof;
Proof proof = new Proof(new JSONObject(keybaseProof));
mProgressable.setProgress(R.string.keybase_message_fetching_data, 0, 100);
Prover prover = Prover.findProverFor(proof);
if (prover == null) {
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_NO_PROVER, 1,
proof.getPrettyName());
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
}
if (!prover.fetchProofData(keybaseQuery)) {
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_FETCH_PROOF, 1);
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
}
if (!prover.checkFingerprint(requiredFingerprint)) {
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_FINGERPRINT_MISMATCH, 1);
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
}
String domain = prover.dnsTxtCheckRequired();
if (domain != null) {
DNSMessage dnsQuery = new Client().query(new Question(domain, Record.TYPE.TXT));
if (dnsQuery == null) {
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_DNS_FAIL, 1);
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_SPECIFIC, 2,
getFlattenedProverLog(prover));
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
}
Record[] records = dnsQuery.getAnswers();
List<List<byte[]>> extents = new ArrayList<>();
for (Record r : records) {
Data d = r.getPayload();
if (d instanceof TXT) {
extents.add(((TXT) d).getExtents());
}
}
if (!prover.checkDnsTxt(extents)) {
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_SPECIFIC, 1,
getFlattenedProverLog(prover));
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
}
}
byte[] messageBytes = prover.getPgpMessage().getBytes();
if (prover.rawMessageCheckRequired()) {
InputStream messageByteStream = PGPUtil.getDecoderStream(new
ByteArrayInputStream
(messageBytes));
if (!prover.checkRawMessageBytes(messageByteStream)) {
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_SPECIFIC, 1,
getFlattenedProverLog(prover));
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
}
}
PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(mContext, mKeyRepository, mProgressable);
PgpDecryptVerifyInputParcel input = PgpDecryptVerifyInputParcel.builder()
.setInputBytes(messageBytes)
.build();
DecryptVerifyResult decryptVerifyResult = op.execute(input, CryptoInputParcel.createCryptoInputParcel());
if (!decryptVerifyResult.success()) {
log.add(decryptVerifyResult, 1);
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
}
long verifyingKeyId = decryptVerifyResult.getSignatureResult().getKeyId();
byte[] verifyingFingerprint = mKeyRepository.getFingerprintByKeyId(verifyingKeyId);
if (!requiredFingerprint.equals(KeyFormattingUtils.convertFingerprintToHex(verifyingFingerprint))) {
log.add(LogType.MSG_KEYBASE_ERROR_FINGERPRINT_MISMATCH, 1);
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
}
if (!prover.validate(new String(decryptVerifyResult.getOutputBytes()))) {
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_PAYLOAD_MISMATCH, 1);
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
}
return new KeybaseVerificationResult(OperationResult.RESULT_OK, log, prover);
} catch (Exception e) {
// just adds the passed parameter, in this case e.getMessage()
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_SPECIFIC, 1, e.getMessage());
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
}
}
private String getFlattenedProverLog(Prover prover) {
String log = "";
for (String line : prover.getLog()) {
log += line + "\n";
}
return log;
}
}

View file

@ -1,87 +0,0 @@
/*
* Copyright (C) 2017 Schürmann & Breitmoser GbR
*
* 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.operations.results;
import android.os.Parcel;
import android.os.Parcelable;
import com.textuality.keybase.lib.KeybaseException;
import com.textuality.keybase.lib.prover.Prover;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
public class KeybaseVerificationResult extends InputPendingResult {
public final String mProofUrl;
public final String mPresenceUrl;
public final String mPresenceLabel;
public KeybaseVerificationResult(int result, OperationLog log) {
super(result, log);
mProofUrl = null;
mPresenceLabel = null;
mPresenceUrl = null;
}
public KeybaseVerificationResult(int result, OperationLog log, Prover prover)
throws KeybaseException {
super(result, log);
mProofUrl = prover.getProofUrl();
mPresenceUrl = prover.getPresenceUrl();
mPresenceLabel = prover.getPresenceLabel();
}
public KeybaseVerificationResult(OperationLog log, RequiredInputParcel requiredInputParcel,
CryptoInputParcel cryptoInputParcel) {
super(log, requiredInputParcel, cryptoInputParcel);
mProofUrl = null;
mPresenceUrl = null;
mPresenceLabel = null;
}
protected KeybaseVerificationResult(Parcel in) {
super(in);
mProofUrl = in.readString();
mPresenceUrl = in.readString();
mPresenceLabel = in.readString();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(mProofUrl);
dest.writeString(mPresenceUrl);
dest.writeString(mPresenceLabel);
}
public static final Parcelable.Creator<KeybaseVerificationResult> CREATOR = new Parcelable.Creator<KeybaseVerificationResult>() {
@Override
public KeybaseVerificationResult createFromParcel(Parcel in) {
return new KeybaseVerificationResult(in);
}
@Override
public KeybaseVerificationResult[] newArray(int size) {
return new KeybaseVerificationResult[size];
}
};
}

View file

@ -756,7 +756,6 @@ public abstract class OperationResult implements Parcelable {
MSG_IMPORT_FETCH_ERROR_NOT_FOUND (LogLevel.ERROR, R.string.msg_import_fetch_error_not_found), MSG_IMPORT_FETCH_ERROR_NOT_FOUND (LogLevel.ERROR, R.string.msg_import_fetch_error_not_found),
MSG_IMPORT_FETCH_ERROR_KEYSERVER(LogLevel.ERROR, R.string.msg_import_fetch_error_keyserver), MSG_IMPORT_FETCH_ERROR_KEYSERVER(LogLevel.ERROR, R.string.msg_import_fetch_error_keyserver),
MSG_IMPORT_FETCH_ERROR_KEYSERVER_SECRET (LogLevel.ERROR, R.string.msg_import_fetch_error_keyserver_secret), MSG_IMPORT_FETCH_ERROR_KEYSERVER_SECRET (LogLevel.ERROR, R.string.msg_import_fetch_error_keyserver_secret),
MSG_IMPORT_FETCH_KEYBASE (LogLevel.INFO, R.string.msg_import_fetch_keybase),
MSG_IMPORT_FETCH_FACEBOOK (LogLevel.INFO, R.string.msg_import_fetch_facebook), MSG_IMPORT_FETCH_FACEBOOK (LogLevel.INFO, R.string.msg_import_fetch_facebook),
MSG_IMPORT_FETCH_KEYSERVER (LogLevel.INFO, R.string.msg_import_fetch_keyserver), MSG_IMPORT_FETCH_KEYSERVER (LogLevel.INFO, R.string.msg_import_fetch_keyserver),
MSG_IMPORT_FETCH_KEYSERVER_OK (LogLevel.DEBUG, R.string.msg_import_fetch_keyserver_ok), MSG_IMPORT_FETCH_KEYSERVER_OK (LogLevel.DEBUG, R.string.msg_import_fetch_keyserver_ok),
@ -820,18 +819,6 @@ public abstract class OperationResult implements Parcelable {
MSG_REVOKE_ERROR_KEY_FAIL (LogLevel.ERROR, R.string.msg_revoke_key_fail), MSG_REVOKE_ERROR_KEY_FAIL (LogLevel.ERROR, R.string.msg_revoke_key_fail),
MSG_REVOKE_OK (LogLevel.OK, R.string.msg_revoke_ok), MSG_REVOKE_OK (LogLevel.OK, R.string.msg_revoke_ok),
// keybase verification
MSG_KEYBASE_VERIFICATION(LogLevel.START, R.string.msg_keybase_verification),
MSG_KEYBASE_ERROR_NO_PROVER(LogLevel.ERROR, R.string.msg_keybase_error_no_prover),
MSG_KEYBASE_ERROR_FETCH_PROOF(LogLevel.ERROR, R.string.msg_keybase_error_fetching_evidence),
MSG_KEYBASE_ERROR_FINGERPRINT_MISMATCH(LogLevel.ERROR,
R.string.msg_keybase_error_key_mismatch),
MSG_KEYBASE_ERROR_DNS_FAIL(LogLevel.ERROR, R.string.msg_keybase_error_dns_fail),
MSG_KEYBASE_ERROR_SPECIFIC(LogLevel.ERROR, R.string.msg_keybase_error_specific),
MSG_KEYBASE_ERROR_PAYLOAD_MISMATCH(LogLevel.ERROR,
R.string.msg_keybase_error_msg_payload_mismatch),
// InputData Operation // InputData Operation
MSG_DATA (LogLevel.START, R.string.msg_data), MSG_DATA (LogLevel.START, R.string.msg_data),
MSG_DATA_OPENPGP (LogLevel.DEBUG, R.string.msg_data_openpgp), MSG_DATA_OPENPGP (LogLevel.DEBUG, R.string.msg_data_openpgp),

View file

@ -1,60 +0,0 @@
/*
* Copyright (C) 2017 Schürmann & Breitmoser GbR
*
* 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.service;
import android.os.Parcel;
import android.os.Parcelable;
public class KeybaseVerificationParcel implements Parcelable {
public String mKeybaseProof;
public String mRequiredFingerprint;
public KeybaseVerificationParcel(String keybaseProof, String requiredFingerprint) {
mKeybaseProof = keybaseProof;
mRequiredFingerprint = requiredFingerprint;
}
protected KeybaseVerificationParcel(Parcel in) {
mKeybaseProof = in.readString();
mRequiredFingerprint = in.readString();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mKeybaseProof);
dest.writeString(mRequiredFingerprint);
}
public static final Parcelable.Creator<KeybaseVerificationParcel> CREATOR = new Parcelable.Creator<KeybaseVerificationParcel>() {
@Override
public KeybaseVerificationParcel createFromParcel(Parcel in) {
return new KeybaseVerificationParcel(in);
}
@Override
public KeybaseVerificationParcel[] newArray(int size) {
return new KeybaseVerificationParcel[size];
}
};
}

View file

@ -41,7 +41,6 @@ import org.sufficientlysecure.keychain.operations.ImportOperation;
import org.sufficientlysecure.keychain.operations.InputDataOperation; import org.sufficientlysecure.keychain.operations.InputDataOperation;
import org.sufficientlysecure.keychain.operations.KeySyncOperation; import org.sufficientlysecure.keychain.operations.KeySyncOperation;
import org.sufficientlysecure.keychain.operations.KeySyncParcel; import org.sufficientlysecure.keychain.operations.KeySyncParcel;
import org.sufficientlysecure.keychain.operations.KeybaseVerificationOperation;
import org.sufficientlysecure.keychain.operations.PromoteKeyOperation; import org.sufficientlysecure.keychain.operations.PromoteKeyOperation;
import org.sufficientlysecure.keychain.operations.RevokeOperation; import org.sufficientlysecure.keychain.operations.RevokeOperation;
import org.sufficientlysecure.keychain.operations.SignEncryptOperation; import org.sufficientlysecure.keychain.operations.SignEncryptOperation;
@ -114,8 +113,6 @@ public class KeychainServiceTask {
} else if (inputParcel instanceof UploadKeyringParcel) { } else if (inputParcel instanceof UploadKeyringParcel) {
op = new UploadOperation(context, keyRepository, asyncProgressable, op = new UploadOperation(context, keyRepository, asyncProgressable,
operationCancelledBoolean); operationCancelledBoolean);
} else if (inputParcel instanceof KeybaseVerificationParcel) {
op = new KeybaseVerificationOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof InputDataParcel) { } else if (inputParcel instanceof InputDataParcel) {
op = new InputDataOperation(context, keyRepository, asyncProgressable); op = new InputDataOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof BenchmarkInputParcel) { } else if (inputParcel instanceof BenchmarkInputParcel) {

View file

@ -138,7 +138,7 @@ public abstract class DecryptFragment extends Fragment {
{ {
ParcelableKeyRing keyEntry = ParcelableKeyRing.createFromReference(null, ParcelableKeyRing keyEntry = ParcelableKeyRing.createFromReference(null,
KeyFormattingUtils.convertKeyIdToHex(unknownKeyId), null, null); KeyFormattingUtils.convertKeyIdToHex(unknownKeyId), null);
ArrayList<ParcelableKeyRing> selectedEntries = new ArrayList<>(); ArrayList<ParcelableKeyRing> selectedEntries = new ArrayList<>();
selectedEntries.add(keyEntry); selectedEntries.add(keyEntry);

View file

@ -769,7 +769,7 @@ public class DecryptListFragment
{ {
ParcelableKeyRing keyEntry = ParcelableKeyRing.createFromReference(null, ParcelableKeyRing keyEntry = ParcelableKeyRing.createFromReference(null,
KeyFormattingUtils.convertKeyIdToHex(unknownKeyId), null, null); KeyFormattingUtils.convertKeyIdToHex(unknownKeyId), null);
ArrayList<ParcelableKeyRing> selectedEntries = new ArrayList<>(); ArrayList<ParcelableKeyRing> selectedEntries = new ArrayList<>();
selectedEntries.add(keyEntry); selectedEntries.add(keyEntry);

View file

@ -223,7 +223,7 @@ public class ImportKeysProxyActivity extends FragmentActivity
} }
public void importKeysFromFingerprint(byte[] fingerprint) { public void importKeysFromFingerprint(byte[] fingerprint) {
ParcelableKeyRing keyEntry = ParcelableKeyRing.createFromReference(fingerprint, null, null, null); ParcelableKeyRing keyEntry = ParcelableKeyRing.createFromReference(fingerprint, null, null);
ArrayList<ParcelableKeyRing> selectedEntries = new ArrayList<>(); ArrayList<ParcelableKeyRing> selectedEntries = new ArrayList<>();
selectedEntries.add(keyEntry); selectedEntries.add(keyEntry);

View file

@ -1,465 +0,0 @@
/*
* Copyright (C) 2017 Schürmann & Breitmoser GbR
*
* 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.ui;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import android.arch.lifecycle.ViewModelProviders;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.text.style.StyleSpan;
import android.text.style.URLSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import com.textuality.keybase.lib.KeybaseException;
import com.textuality.keybase.lib.KeybaseQuery;
import com.textuality.keybase.lib.Proof;
import com.textuality.keybase.lib.User;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.model.SubKey.UnifiedKeyInfo;
import org.sufficientlysecure.keychain.network.OkHttpKeybaseClient;
import org.sufficientlysecure.keychain.network.orbot.OrbotHelper;
import org.sufficientlysecure.keychain.operations.results.KeybaseVerificationResult;
import org.sufficientlysecure.keychain.service.KeybaseVerificationParcel;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.keyview.UnifiedKeyInfoViewModel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.ParcelableProxy;
import org.sufficientlysecure.keychain.util.Preferences;
public class ViewKeyKeybaseFragment extends Fragment implements
CryptoOperationHelper.Callback<KeybaseVerificationParcel, KeybaseVerificationResult> {
private TextView mReportHeader;
private TableLayout mProofListing;
private LayoutInflater mInflater;
private View mProofVerifyHeader;
private TextView mProofVerifyDetail;
private Proof mProof;
// for CryptoOperationHelper,Callback
private String mKeybaseProof;
private String mKeybaseFingerprint;
private CryptoOperationHelper<KeybaseVerificationParcel, KeybaseVerificationResult> mKeybaseOpHelper;
/**
* Creates new instance of this fragment
*/
public static ViewKeyKeybaseFragment newInstance() {
return new ViewKeyKeybaseFragment();
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup viewGroup, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.view_key_adv_keybase_fragment, viewGroup, false);
mInflater = inflater;
mReportHeader = view.findViewById(R.id.view_key_trust_cloud_narrative);
mProofListing = view.findViewById(R.id.view_key_proof_list);
mProofVerifyHeader = view.findViewById(R.id.view_key_proof_verify_header);
mProofVerifyDetail = view.findViewById(R.id.view_key_proof_verify_detail);
mReportHeader.setVisibility(View.GONE);
mProofListing.setVisibility(View.GONE);
mProofVerifyHeader.setVisibility(View.GONE);
mProofVerifyDetail.setVisibility(View.GONE);
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
UnifiedKeyInfoViewModel viewKeyViewModel = ViewModelProviders.of(requireActivity()).get(UnifiedKeyInfoViewModel.class);
viewKeyViewModel.getUnifiedKeyInfoLiveData(requireContext()).observe(this, this::onLoadUnifiedKeyInfo);
}
private void onLoadUnifiedKeyInfo(UnifiedKeyInfo unifiedKeyInfo) {
if (unifiedKeyInfo == null) {
return;
}
String fingerprint = KeyFormattingUtils.convertFingerprintToHex(unifiedKeyInfo.fingerprint());
startSearch(fingerprint);
}
private void startSearch(final String fingerprint) {
final ParcelableProxy parcelableProxy =
Preferences.getPreferences(getActivity()).getParcelableProxy();
OrbotHelper.DialogActions dialogActions = new OrbotHelper.DialogActions() {
@Override
public void onOrbotStarted() {
new DescribeKey(parcelableProxy).execute(fingerprint);
}
@Override
public void onNeutralButton() {
new DescribeKey(ParcelableProxy.getForNoProxy())
.execute(fingerprint);
}
@Override
public void onCancel() {
}
};
if (OrbotHelper.putOrbotInRequiredState(dialogActions, getActivity())) {
new DescribeKey(parcelableProxy).execute(fingerprint);
}
}
class ResultPage {
String mHeader;
final List<CharSequence> mProofs;
ResultPage(String header, List<CharSequence> proofs) {
mHeader = header;
mProofs = proofs;
}
}
/**
* look for evidence from keybase in the background, make tabular version of result
*/
private class DescribeKey extends AsyncTask<String, Void, ResultPage> {
ParcelableProxy mParcelableProxy;
DescribeKey(ParcelableProxy parcelableProxy) {
mParcelableProxy = parcelableProxy;
}
@Override
protected ResultPage doInBackground(String... args) {
String fingerprint = args[0];
final ArrayList<CharSequence> proofList = new ArrayList<>();
final Hashtable<Integer, ArrayList<Proof>> proofs = new Hashtable<>();
try {
KeybaseQuery keybaseQuery = new KeybaseQuery(new OkHttpKeybaseClient());
keybaseQuery.setProxy(mParcelableProxy.getProxy());
User keybaseUser = User.findByFingerprint(keybaseQuery, fingerprint);
for (Proof proof : keybaseUser.getProofs()) {
Integer proofType = proof.getType();
appendIfOK(proofs, proofType, proof);
}
// a one-liner in a modern programming language
for (Integer proofType : proofs.keySet()) {
Proof[] x = {};
Proof[] proofsFor = proofs.get(proofType).toArray(x);
if (proofsFor.length > 0) {
SpannableStringBuilder ssb = new SpannableStringBuilder();
int i = 0;
while (i < proofsFor.length - 1) {
appendProofLinks(ssb, fingerprint, proofsFor[i]);
ssb.append(", ");
i++;
}
appendProofLinks(ssb, fingerprint, proofsFor[i]);
proofList.add(formatSpannableString(ssb, getProofNarrative(proofType)));
}
}
} catch (KeybaseException ignored) {
}
String prefix = "";
if (isAdded()) {
prefix = getString(R.string.key_trust_results_prefix);
}
return new ResultPage(prefix, proofList);
}
private SpannableStringBuilder formatSpannableString(SpannableStringBuilder proofLinks, String proofType) {
//Formatting SpannableStringBuilder with String.format() causes the links to stop working.
//This method is to insert the links while reserving the links
SpannableStringBuilder ssb = new SpannableStringBuilder();
ssb.append(proofType);
if (proofType.contains("%s")) {
int i = proofType.indexOf("%s");
ssb.replace(i, i + 2, proofLinks);
} else ssb.append(proofLinks);
return ssb;
}
private void appendProofLinks(SpannableStringBuilder ssb, final String fingerprint, final Proof proof) throws KeybaseException {
int startAt = ssb.length();
String handle = proof.getHandle();
ssb.append(handle);
ssb.setSpan(new URLSpan(proof.getServiceUrl()), startAt, startAt + handle.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
if (haveProofFor(proof.getType())) {
ssb.append("\u00a0[");
startAt = ssb.length();
String verify = "";
if (isAdded()) {
verify = getString(R.string.keybase_verify);
}
ssb.append(verify);
ClickableSpan clicker = new ClickableSpan() {
@Override
public void onClick(View view) {
verify(proof, fingerprint);
}
};
ssb.setSpan(clicker, startAt, startAt + verify.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.append("]");
}
}
@Override
protected void onPostExecute(ResultPage result) {
super.onPostExecute(result);
// stop if fragment is no longer added to an activity
if(!isAdded()) {
return;
}
if (result.mProofs.isEmpty()) {
result.mHeader = requireActivity().getString(R.string.key_trust_no_cloud_evidence);
}
mReportHeader.setVisibility(View.VISIBLE);
mProofListing.setVisibility(View.VISIBLE);
mReportHeader.setText(result.mHeader);
int rowNumber = 1;
for (CharSequence s : result.mProofs) {
TableRow row = (TableRow) mInflater.inflate(R.layout.view_key_adv_keybase_proof, null);
TextView number = row.findViewById(R.id.proof_number);
TextView text = row.findViewById(R.id.proof_text);
number.setText(Integer.toString(rowNumber++) + ". ");
text.setText(s);
text.setMovementMethod(LinkMovementMethod.getInstance());
mProofListing.addView(row);
}
}
}
private String getProofNarrative(int proofType) {
int stringIndex;
switch (proofType) {
case Proof.PROOF_TYPE_TWITTER:
stringIndex = R.string.keybase_narrative_twitter;
break;
case Proof.PROOF_TYPE_GITHUB:
stringIndex = R.string.keybase_narrative_github;
break;
case Proof.PROOF_TYPE_DNS:
stringIndex = R.string.keybase_narrative_dns;
break;
case Proof.PROOF_TYPE_WEB_SITE:
stringIndex = R.string.keybase_narrative_web_site;
break;
case Proof.PROOF_TYPE_HACKERNEWS:
stringIndex = R.string.keybase_narrative_hackernews;
break;
case Proof.PROOF_TYPE_COINBASE:
stringIndex = R.string.keybase_narrative_coinbase;
break;
case Proof.PROOF_TYPE_REDDIT:
stringIndex = R.string.keybase_narrative_reddit;
break;
default:
stringIndex = R.string.keybase_narrative_unknown;
}
if (isAdded()) {
return getString(stringIndex);
} else {
return "";
}
}
private void appendIfOK(Hashtable<Integer, ArrayList<Proof>> table, Integer proofType, Proof proof) {
ArrayList<Proof> list = table.get(proofType);
if (list == null) {
list = new ArrayList<>();
table.put(proofType, list);
}
list.add(proof);
}
// which proofs do we have working verifiers for?
private boolean haveProofFor(int proofType) {
switch (proofType) {
case Proof.PROOF_TYPE_TWITTER:
return true;
case Proof.PROOF_TYPE_GITHUB:
return true;
case Proof.PROOF_TYPE_DNS:
return true;
case Proof.PROOF_TYPE_WEB_SITE:
return true;
case Proof.PROOF_TYPE_HACKERNEWS:
return true;
case Proof.PROOF_TYPE_COINBASE:
return true;
case Proof.PROOF_TYPE_REDDIT:
return true;
default:
return false;
}
}
private void verify(final Proof proof, final String fingerprint) {
mProof = proof;
mKeybaseProof = proof.toString();
mKeybaseFingerprint = fingerprint;
mProofVerifyDetail.setVisibility(View.GONE);
mKeybaseOpHelper = new CryptoOperationHelper<>(1, this, this,
R.string.progress_verifying_signature);
mKeybaseOpHelper.cryptoOperation();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (mKeybaseOpHelper != null) {
mKeybaseOpHelper.handleActivityResult(requestCode, resultCode, data);
}
}
// CryptoOperationHelper.Callback methods
@Override
public KeybaseVerificationParcel createOperationInput() {
return new KeybaseVerificationParcel(mKeybaseProof, mKeybaseFingerprint);
}
@Override
public void onCryptoOperationSuccess(KeybaseVerificationResult result) {
result.createNotify(getActivity()).show();
String proofUrl = result.mProofUrl;
String presenceUrl = result.mPresenceUrl;
String presenceLabel = result.mPresenceLabel;
Proof proof = mProof; // TODO: should ideally be contained in result
String proofLabel;
switch (proof.getType()) {
case Proof.PROOF_TYPE_TWITTER:
proofLabel = getString(R.string.keybase_twitter_proof);
break;
case Proof.PROOF_TYPE_DNS:
proofLabel = getString(R.string.keybase_dns_proof);
break;
case Proof.PROOF_TYPE_WEB_SITE:
proofLabel = getString(R.string.keybase_web_site_proof);
break;
case Proof.PROOF_TYPE_GITHUB:
proofLabel = getString(R.string.keybase_github_proof);
break;
case Proof.PROOF_TYPE_REDDIT:
proofLabel = getString(R.string.keybase_reddit_proof);
break;
default:
proofLabel = getString(R.string.keybase_a_post);
break;
}
SpannableStringBuilder ssb = new SpannableStringBuilder();
ssb.append(getString(R.string.keybase_proof_succeeded));
StyleSpan bold = new StyleSpan(Typeface.BOLD);
ssb.setSpan(bold, 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.append("\n\n");
int length = ssb.length();
ssb.append(proofLabel);
if (proofUrl != null) {
URLSpan postLink = new URLSpan(proofUrl);
ssb.setSpan(postLink, length, length + proofLabel.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (Proof.PROOF_TYPE_DNS == proof.getType()) {
ssb.append(" ").append(getString(R.string.keybase_for_the_domain)).append(" ");
} else {
ssb.append(" ").append(getString(R.string.keybase_fetched_from)).append(" ");
}
length = ssb.length();
URLSpan presenceLink = new URLSpan(presenceUrl);
ssb.append(presenceLabel);
ssb.setSpan(presenceLink, length, length + presenceLabel.length(), Spanned
.SPAN_EXCLUSIVE_EXCLUSIVE);
if (Proof.PROOF_TYPE_REDDIT == proof.getType()) {
ssb.append(", ").
append(getString(R.string.keybase_reddit_attribution)).
append("").append(proof.getHandle()).append("”, ");
}
ssb.append(" ").append(getString(R.string.keybase_contained_signature));
displaySpannableResult(ssb);
}
@Override
public void onCryptoOperationCancelled() {
}
@Override
public void onCryptoOperationError(KeybaseVerificationResult result) {
result.createNotify(getActivity()).show();
SpannableStringBuilder ssb = new SpannableStringBuilder();
ssb.append(getString(R.string.keybase_proof_failure));
String msg = getString(result.getLog().getLast().mType.mMsgId);
if (msg == null) {
msg = getString(R.string.keybase_unknown_proof_failure);
}
StyleSpan bold = new StyleSpan(Typeface.BOLD);
ssb.setSpan(bold, 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.append("\n\n").append(msg);
displaySpannableResult(ssb);
}
@Override
public boolean onCryptoSetProgress(String msg, int progress, int max) {
return false;
}
private void displaySpannableResult(SpannableStringBuilder ssb) {
mProofVerifyHeader.setVisibility(View.VISIBLE);
mProofVerifyDetail.setVisibility(View.VISIBLE);
mProofVerifyDetail.setMovementMethod(LinkMovementMethod.getInstance());
mProofVerifyDetail.setText(ssb);
}
}

View file

@ -24,15 +24,16 @@ import java.util.Date;
import java.util.List; import java.util.List;
import android.content.Intent; import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.support.v4.app.FragmentActivity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.RecyclerView;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.databinding.ImportKeysListItemBinding; import org.sufficientlysecure.keychain.databinding.ImportKeysListItemBinding;
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress; import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
@ -45,7 +46,6 @@ import org.sufficientlysecure.keychain.operations.ImportOperation;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing;
import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing.VerificationStatus;
import org.sufficientlysecure.keychain.daos.KeyRepository;
import org.sufficientlysecure.keychain.service.ImportKeyringParcel; import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.keyview.ViewKeyActivity; import org.sufficientlysecure.keychain.ui.keyview.ViewKeyActivity;
@ -308,10 +308,7 @@ public class ImportKeysAdapter extends RecyclerView.Adapter<ImportKeysAdapter.Vi
throw new AssertionError("Creation date doesn't match the expected one"); throw new AssertionError("Creation date doesn't match the expected one");
} }
entry.setKeyId(keyRing.getMasterKeyId()); entry.setKeyId(keyRing.getMasterKeyId());
entry.setUserIds(keyRing.getUnorderedUserIds());
ArrayList<String> realUserIdsPlusKeybase = keyRing.getUnorderedUserIds();
realUserIdsPlusKeybase.addAll(entry.getKeybaseUserIds());
entry.setUserIds(realUserIdsPlusKeybase);
} }
private class KeyState { private class KeyState {

View file

@ -92,7 +92,6 @@ import org.sufficientlysecure.keychain.ui.MainActivity;
import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity; import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
import org.sufficientlysecure.keychain.ui.QrCodeViewActivity; import org.sufficientlysecure.keychain.ui.QrCodeViewActivity;
import org.sufficientlysecure.keychain.ui.ViewKeyAdvActivity; import org.sufficientlysecure.keychain.ui.ViewKeyAdvActivity;
import org.sufficientlysecure.keychain.ui.ViewKeyKeybaseFragment;
import org.sufficientlysecure.keychain.ui.base.BaseSecurityTokenActivity; import org.sufficientlysecure.keychain.ui.base.BaseSecurityTokenActivity;
import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;
@ -289,11 +288,6 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity {
ViewKeyFragment frag = ViewKeyFragment.newInstance(); ViewKeyFragment frag = ViewKeyFragment.newInstance();
manager.beginTransaction().replace(R.id.view_key_fragment, frag, "view_key_fragment").commit(); manager.beginTransaction().replace(R.id.view_key_fragment, frag, "view_key_fragment").commit();
if (Preferences.getPreferences(this).getExperimentalEnableKeybase()) {
final ViewKeyKeybaseFragment keybaseFrag = ViewKeyKeybaseFragment.newInstance();
manager.beginTransaction().replace(R.id.view_key_keybase_fragment, keybaseFrag).commit();
}
} }
@Override @Override
@ -890,7 +884,7 @@ public class ViewKeyActivity extends BaseSecurityTokenActivity {
HkpKeyserverAddress preferredKeyserver = Preferences.getPreferences(getApplicationContext()).getPreferredKeyserver(); HkpKeyserverAddress preferredKeyserver = Preferences.getPreferences(getApplicationContext()).getPreferredKeyserver();
ParcelableKeyRing keyEntry = ParcelableKeyRing keyEntry =
ParcelableKeyRing.createFromReference(unifiedKeyInfo.fingerprint(), null, null, null); ParcelableKeyRing.createFromReference(unifiedKeyInfo.fingerprint(), null, null);
return ImportKeyringParcel return ImportKeyringParcel
.createImportKeyringParcel(Collections.singletonList(keyEntry), preferredKeyserver); .createImportKeyringParcel(Collections.singletonList(keyEntry), preferredKeyserver);

View file

@ -65,7 +65,8 @@ public class EmailKeyHelper {
// Put them in a list and import // Put them in a list and import
ArrayList<ParcelableKeyRing> keys = new ArrayList<>(entries.size()); ArrayList<ParcelableKeyRing> keys = new ArrayList<>(entries.size());
for (ImportKeysListEntry entry : entries) { for (ImportKeysListEntry entry : entries) {
keys.add(ParcelableKeyRing.createFromReference(entry.getFingerprint(), entry.getKeyIdHex(), null, null)); keys.add(ParcelableKeyRing.createFromReference(entry.getFingerprint(), entry.getKeyIdHex(),
null));
} }
mKeyList = keys; mKeyList = keys;
mKeyserver = keyserver; mKeyserver = keyserver;

View file

@ -330,7 +330,6 @@ public class Preferences {
public CloudSearchPrefs getCloudSearchPrefs() { public CloudSearchPrefs getCloudSearchPrefs() {
return CloudSearchPrefs.create(mSharedPreferences.getBoolean(Pref.SEARCH_KEYSERVER, true), return CloudSearchPrefs.create(mSharedPreferences.getBoolean(Pref.SEARCH_KEYSERVER, true),
mSharedPreferences.getBoolean(Pref.SEARCH_KEYBASE, true),
false, false,
mSharedPreferences.getBoolean(Pref.SEARCH_WEB_KEY_DIRECTORY, true), mSharedPreferences.getBoolean(Pref.SEARCH_WEB_KEY_DIRECTORY, true),
getPreferredKeyserver()); getPreferredKeyserver());
@ -387,7 +386,6 @@ public class Preferences {
@AutoValue @AutoValue
public static abstract class CloudSearchPrefs implements Parcelable { public static abstract class CloudSearchPrefs implements Parcelable {
public abstract boolean isKeyserverEnabled(); public abstract boolean isKeyserverEnabled();
public abstract boolean isKeybaseEnabled();
public abstract boolean isFacebookEnabled(); public abstract boolean isFacebookEnabled();
public abstract boolean isWebKeyDirectoryEnabled(); public abstract boolean isWebKeyDirectoryEnabled();
@ -396,31 +394,29 @@ public class Preferences {
/** /**
* @param searchKeyserver should passed keyserver be searched * @param searchKeyserver should passed keyserver be searched
* @param searchKeybase should keybase.io be searched
* @param searchFacebook should Facebook be searched * @param searchFacebook should Facebook be searched
* @param searchWebKeyDirectory should WKD be searched * @param searchWebKeyDirectory should WKD be searched
* @param keyserver the keyserver url authority to search on * @param keyserver the keyserver url authority to search on
*/ */
public static CloudSearchPrefs create(boolean searchKeyserver, boolean searchKeybase, public static CloudSearchPrefs create(boolean searchKeyserver,
boolean searchFacebook, boolean searchWebKeyDirectory, boolean searchFacebook, boolean searchWebKeyDirectory,
@Nullable HkpKeyserverAddress keyserver) { @Nullable HkpKeyserverAddress keyserver) {
return new AutoValue_Preferences_CloudSearchPrefs(searchKeyserver, return new AutoValue_Preferences_CloudSearchPrefs(searchKeyserver,
searchKeybase,
searchFacebook, searchFacebook,
searchWebKeyDirectory, searchWebKeyDirectory,
keyserver); keyserver);
} }
public static CloudSearchPrefs createWebKeyDirectoryOnly() { public static CloudSearchPrefs createWebKeyDirectoryOnly() {
return create(false, false, false, true, null); return create(false, false, true, null);
} }
public static CloudSearchPrefs createKeyserverOnly(HkpKeyserverAddress keyserver) { public static CloudSearchPrefs createKeyserverOnly(HkpKeyserverAddress keyserver) {
return create(true, false, false, false, keyserver); return create(true, false, false, keyserver);
} }
public static CloudSearchPrefs createSocialOnly() { public static CloudSearchPrefs createSocialOnly() {
return create(false, true, true, false, null); return create(false, true, false, null);
} }
} }
@ -432,10 +428,6 @@ public class Preferences {
// experimental prefs // experimental prefs
public boolean getExperimentalEnableKeybase() {
return mSharedPreferences.getBoolean(Pref.EXPERIMENTAL_ENABLE_KEYBASE, false);
}
public boolean getExperimentalUsbAllowUntested() { public boolean getExperimentalUsbAllowUntested() {
return mSharedPreferences.getBoolean(Pref.EXPERIMENTAL_USB_ALLOW_UNTESTED, false); return mSharedPreferences.getBoolean(Pref.EXPERIMENTAL_USB_ALLOW_UNTESTED, false);
} }

View file

@ -205,11 +205,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/view_key_keybase_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- <!--
placeholder to improve the scrolling. placeholder to improve the scrolling.
Somehow the content must be large enough to enable scrolling on NestedScrollView Somehow the content must be large enough to enable scrolling on NestedScrollView

View file

@ -1,81 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp">
<android.support.v7.widget.CardView
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
card_view:cardBackgroundColor="?attr/colorCardViewBackground"
card_view:cardCornerRadius="4dp"
card_view:cardElevation="2dp"
card_view:cardUseCompatPadding="true">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
style="@style/CardViewHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/section_keybase_proofs" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp">
<TextView
android:id="@+id/view_key_trust_cloud_narrative"
style="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginBottom="14dp"
android:layout_marginLeft="8dp"
android:layout_weight="1" />
<TableLayout
android:id="@+id/view_key_proof_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/view_key_proof_verify_header"
style="@style/SectionHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_weight="1"
android:text="@string/section_proof_details" />
<TextView
android:id="@+id/view_key_proof_verify_detail"
style="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginLeft="8dp"
android:layout_marginTop="14dp"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>

View file

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<TableRow xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<TextView
android:id="@+id/proof_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="6dip"
android:text="1."
style="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/proof_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="6dip"
android:text="Posts to twitter as Timbray"
style="?android:attr/textAppearanceSmall" />
</TableRow>

View file

@ -46,12 +46,11 @@
<string name="section_user_ids">"Identities"</string> <string name="section_user_ids">"Identities"</string>
<string name="section_security_token">"Security Token"</string> <string name="section_security_token">"Security Token"</string>
<string name="section_linked_system_contact">"Linked System Contact"</string> <string name="section_linked_system_contact">"Linked System Contact"</string>
<string name="section_keybase_proofs">"Keybase.io Proofs"</string>
<string name="section_should_you_trust">"Should you trust this key?"</string> <string name="section_should_you_trust">"Should you trust this key?"</string>
<string name="section_proof_details">Proof verification</string> <string name="section_proof_details">Proof verification</string>
<string name="section_keys">"Subkeys"</string> <string name="section_keys">"Subkeys"</string>
<string name="section_cloud_search">"Key Search"</string> <string name="section_cloud_search">"Key Search"</string>
<string name="section_cloud_search_summary">"Keyserver, keybase.io"</string> <string name="section_cloud_search_summary">"Keyserver"</string>
<string name="section_passphrase_cache">"Passwords and PINs"</string> <string name="section_passphrase_cache">"Passwords and PINs"</string>
<string name="section_passphrase_cache_summary">"Handling"</string> <string name="section_passphrase_cache_summary">"Handling"</string>
<string name="section_proxy_settings">"Network Anonymity"</string> <string name="section_proxy_settings">"Network Anonymity"</string>
@ -212,8 +211,6 @@
<string name="pref_keyserver">"OpenPGP keyservers"</string> <string name="pref_keyserver">"OpenPGP keyservers"</string>
<string name="pref_keyserver_summary">"Search keys on selected OpenPGP keyservers (HKP protocol)"</string> <string name="pref_keyserver_summary">"Search keys on selected OpenPGP keyservers (HKP protocol)"</string>
<string name="pref_keybase">"keybase.io"</string>
<string name="pref_keybase_summary">"Search keys on keybase.io"</string>
<string name="pref_facebook">"Facebook"</string> <string name="pref_facebook">"Facebook"</string>
<string name="pref_facebook_summary">"Search keys on Facebook by username"</string> <string name="pref_facebook_summary">"Search keys on Facebook by username"</string>
<string name="pref_wkd">"Web Key Directory"</string> <string name="pref_wkd">"Web Key Directory"</string>
@ -232,8 +229,6 @@
<string name="label_experimental_settings_desc_title">"Warning"</string> <string name="label_experimental_settings_desc_title">"Warning"</string>
<string name="label_experimental_settings_desc_summary">"These features are not yet finished or results of user experience/security research. Thus, don't rely on their security and please don't report issues you encounter!"</string> <string name="label_experimental_settings_desc_summary">"These features are not yet finished or results of user experience/security research. Thus, don't rely on their security and please don't report issues you encounter!"</string>
<string name="label_experimental_settings_keybase_title">"Keybase.io proofs"</string>
<string name="label_experimental_settings_keybase_summary">"Contact keybase.io for key proofs and show them every time a key is displayed"</string>
<string name="label_experimental_settings_theme_summary">"(The icons and many screens are not yet adjusted accordingly for the dark theme)"</string> <string name="label_experimental_settings_theme_summary">"(The icons and many screens are not yet adjusted accordingly for the dark theme)"</string>
<string name="label_settings_analytics_title">Allow anonymous usage statistics</string> <string name="label_settings_analytics_title">Allow anonymous usage statistics</string>
@ -724,7 +719,6 @@
<string name="key_view_tab_share">"Share"</string> <string name="key_view_tab_share">"Share"</string>
<string name="key_view_tab_keys">"Subkeys"</string> <string name="key_view_tab_keys">"Subkeys"</string>
<string name="key_view_tab_certs">"Certificates"</string> <string name="key_view_tab_certs">"Certificates"</string>
<string name="key_view_tab_keybase">"Keybase.io"</string>
<string name="user_id_info_revoked_title">"Revoked"</string> <string name="user_id_info_revoked_title">"Revoked"</string>
<string name="user_id_info_revoked_text">"This identity has been revoked by the key owner. It is no longer valid."</string> <string name="user_id_info_revoked_text">"This identity has been revoked by the key owner. It is no longer valid."</string>
<string name="user_id_info_certified_title">"Confirmed"</string> <string name="user_id_info_certified_title">"Confirmed"</string>
@ -735,37 +729,6 @@
<!-- Key trust --> <!-- Key trust -->
<string name="key_trust_no_cloud_evidence">"No proof from the Internet on this keys trustworthiness."</string> <string name="key_trust_no_cloud_evidence">"No proof from the Internet on this keys trustworthiness."</string>
<string name="key_trust_start_cloud_search">"Start search"</string> <string name="key_trust_start_cloud_search">"Start search"</string>
<string name="key_trust_results_prefix">"Keybase.io offers “proofs” which assert that the owner of this key: "</string>
<!-- keybase proof stuff -->
<string name="keybase_narrative_twitter">"Posts to Twitter as %s"</string>
<string name="keybase_narrative_github">"Is known on GitHub as %s"</string>
<string name="keybase_narrative_dns">"Controls the domain name(s) %s"</string>
<string name="keybase_narrative_web_site">"Can post to the Web site(s) %s"</string>
<string name="keybase_narrative_reddit">"Posts to Reddit as %s"</string>
<string name="keybase_narrative_coinbase">"Is known on Coinbase as %s"</string>
<string name="keybase_narrative_hackernews">"Posts to Hacker News as %s"</string>
<string name="keybase_narrative_unknown">"Unknown proof type %s"</string>
<string name="keybase_proof_failure">"Unfortunately this proof cannot be verified."</string>
<string name="keybase_unknown_proof_failure">"Unrecognized problem with proof checker"</string>
<string name="keybase_problem_fetching_evidence">"Problem with proof"</string>
<string name="keybase_key_mismatch">"Key fingerprint doesnt match that in proof post"</string>
<string name="keybase_dns_query_failure">"DNS TXT Record retrieval failed"</string>
<string name="keybase_no_prover_found">"No proof checker found for"</string>
<string name="keybase_message_payload_mismatch">"Decrypted proof post does not match expected value"</string>
<string name="keybase_message_fetching_data">"Fetching proof"</string>
<string name="keybase_proof_succeeded">"This proof has been verified!"</string>
<string name="keybase_a_post">"A post"</string>
<string name="keybase_fetched_from">"fetched from"</string>
<string name="keybase_for_the_domain">"for the domain"</string>
<string name="keybase_contained_signature">"contains a message which could only have been created by the owner of this key."</string>
<string name="keybase_twitter_proof">"A tweet"</string>
<string name="keybase_dns_proof">"A DNS TXT record"</string>
<string name="keybase_web_site_proof">"A text file"</string>
<string name="keybase_github_proof">"A gist"</string>
<string name="keybase_reddit_proof">"A JSON file"</string>
<string name="keybase_reddit_attribution">"attributed by Reddit to"</string>
<string name="keybase_verify">"Verify"</string>
<!-- Edit key --> <!-- Edit key -->
<string name="edit_key_action_change_passphrase">"Change Password"</string> <string name="edit_key_action_change_passphrase">"Change Password"</string>
@ -1334,7 +1297,6 @@
<string name="msg_import_fetch_error_not_found">"Key not found!"</string> <string name="msg_import_fetch_error_not_found">"Key not found!"</string>
<string name="msg_import_fetch_error_keyserver">"Could not retrieve key from keyservers: %s"</string> <string name="msg_import_fetch_error_keyserver">"Could not retrieve key from keyservers: %s"</string>
<string name="msg_import_fetch_error_keyserver_secret">"Cannot import secret key from keyserver!"</string> <string name="msg_import_fetch_error_keyserver_secret">"Cannot import secret key from keyserver!"</string>
<string name="msg_import_fetch_keybase">"Retrieving from keybase.io: %s"</string>
<string name="msg_import_fetch_facebook">"Retrieving from Facebook: %s"</string> <string name="msg_import_fetch_facebook">"Retrieving from Facebook: %s"</string>
<string name="msg_import_fetch_keyserver">"Retrieving from keyserver: %s"</string> <string name="msg_import_fetch_keyserver">"Retrieving from keyserver: %s"</string>
<string name="msg_import_fetch_keyserver_ok">"Key retrieval successful"</string> <string name="msg_import_fetch_keyserver_ok">"Key retrieval successful"</string>
@ -1437,15 +1399,6 @@
<string name="msg_download_query_failed">"An error occurred when searching for keys."</string> <string name="msg_download_query_failed">"An error occurred when searching for keys."</string>
<!-- Messages for Keybase Verification operation -->
<string name="msg_keybase_verification">"Attempting keybase verification for %s"</string>
<string name="msg_keybase_error_no_prover">"No proof checker found for %s"</string>
<string name="msg_keybase_error_fetching_evidence">"Problem with fetching proof"</string>
<string name="msg_keybase_error_key_mismatch">"Key fingerprint doesnt match that in proof post"</string>
<string name="msg_keybase_error_dns_fail">"DNS TXT Record retrieval failed"</string>
<string name="msg_keybase_error_specific">"%s"</string>
<string name="msg_keybase_error_msg_payload_mismatch">"Decrypted proof post does not match expected value"</string>
<!-- Messages for Mime parsing operation --> <!-- Messages for Mime parsing operation -->
<string name="msg_mime_parsing_start">"Parsing the MIME structure"</string> <string name="msg_mime_parsing_start">"Parsing the MIME structure"</string>
<string name="msg_mime_parsing_error">"MIME parsing failed"</string> <string name="msg_mime_parsing_error">"MIME parsing failed"</string>

View file

@ -9,11 +9,6 @@
android:dependency="search_keyserver_pref" android:dependency="search_keyserver_pref"
android:key="keyServers" android:key="keyServers"
android:title="@string/label_keyservers" /> android:title="@string/label_keyservers" />
<SwitchPreference
android:defaultValue="true"
android:key="search_keybase_pref"
android:summary="@string/pref_keybase_summary"
android:title="@string/pref_keybase" />
<SwitchPreference <SwitchPreference
android:defaultValue="true" android:defaultValue="true"
android:key="search_wkd_pref" android:key="search_wkd_pref"

View file

@ -12,13 +12,6 @@
android:summary="@string/label_settings_analytics_summary" android:summary="@string/label_settings_analytics_summary"
android:title="@string/label_settings_analytics_title" /> android:title="@string/label_settings_analytics_title" />
<SwitchPreference
android:defaultValue="false"
android:key="experimentalEnableKeybase"
android:persistent="true"
android:summary="@string/label_experimental_settings_keybase_summary"
android:title="@string/label_experimental_settings_keybase_title" />
<ListPreference <ListPreference
android:defaultValue="light" android:defaultValue="light"
android:dialogTitle="@string/label_theme" android:dialogTitle="@string/label_theme"

1
extern/KeybaseLib vendored

@ -1 +0,0 @@
Subproject commit 476fc52a7e59a490d89b8e15f96f5c8535c20328

View file

@ -11,8 +11,5 @@ include ':extern:MaterialChipsInput:library'
//include ':extern:openpgp-api-lib:openpgp-api' //include ':extern:openpgp-api-lib:openpgp-api'
include ':openpgp-api-lib' include ':openpgp-api-lib'
project(':openpgp-api-lib').projectDir = new File('extern/openpgp-api-lib/openpgp-api') project(':openpgp-api-lib').projectDir = new File('extern/openpgp-api-lib/openpgp-api')
//include ':extern:KeybaseLib:Lib'
include ':KeybaseLib'
project(':KeybaseLib').projectDir = new File('extern/KeybaseLib/Lib')
include ':sshauthentication-api' include ':sshauthentication-api'
project(':sshauthentication-api').projectDir = new File('sshauthentication-api') project(':sshauthentication-api').projectDir = new File('sshauthentication-api')