ditch keybase
This commit is contained in:
parent
5e0a17b966
commit
d3e48db520
4
.gitmodules
vendored
4
.gitmodules
vendored
|
@ -2,10 +2,6 @@
|
|||
path = extern/openpgp-api-lib
|
||||
url = https://github.com/open-keychain/openpgp-api.git
|
||||
ignore = dirty
|
||||
[submodule "extern/KeybaseLib"]
|
||||
path = extern/KeybaseLib
|
||||
url = https://github.com/open-keychain/KeybaseLib.git
|
||||
ignore = dirty
|
||||
[submodule "extern/minidns"]
|
||||
path = extern/minidns
|
||||
url = https://github.com/open-keychain/minidns.git
|
||||
|
|
|
@ -61,7 +61,6 @@ dependencies {
|
|||
implementation project(':extern:bouncycastle:pg')
|
||||
implementation project(':extern:bouncycastle:prov')
|
||||
implementation project(':extern:minidns')
|
||||
implementation project(':KeybaseLib')
|
||||
implementation project(':extern:MaterialChipsInput')
|
||||
|
||||
implementation "android.arch.work:work-runtime:1.0.0-alpha02"
|
||||
|
|
|
@ -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-----
|
|
@ -132,7 +132,6 @@ public final class Constants {
|
|||
public static final String FIRST_TIME_APP = "firstTimeApp";
|
||||
public static final String CACHED_CONSOLIDATE = "cachedConsolidate";
|
||||
public static final String SEARCH_KEYSERVER = "search_keyserver_pref";
|
||||
public static final String SEARCH_KEYBASE = "search_keybase_pref";
|
||||
public static final String SEARCH_WEB_KEY_DIRECTORY = "search_wkd_pref";
|
||||
public static final String USE_NUMKEYPAD_FOR_SECURITY_TOKEN_PIN = "useNumKeypadForYubikeyPin";
|
||||
public static final String ENCRYPT_FILENAMES = "encryptFilenames";
|
||||
|
@ -154,7 +153,6 @@ public final class Constants {
|
|||
public static final String ENABLE_WIFI_SYNC_ONLY = "enableWifiSyncOnly";
|
||||
public static final String SYNC_WORK_UUID = "syncWorkUuid";
|
||||
// other settings
|
||||
public static final String EXPERIMENTAL_ENABLE_KEYBASE = "experimentalEnableKeybase";
|
||||
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_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!!
|
||||
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,
|
||||
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,
|
||||
USE_NUMKEYPAD_FOR_SECURITY_TOKEN_PIN, ENCRYPT_FILENAMES);
|
||||
}
|
||||
|
|
|
@ -102,7 +102,6 @@ public class KeychainApplication extends Application {
|
|||
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("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");
|
||||
|
||||
KeyserverSyncManager.updateKeyserverSyncScheduleAsync(this, false);
|
||||
|
|
|
@ -45,9 +45,6 @@ public class CloudSearch {
|
|||
if (cloudPrefs.isKeyserverEnabled()) {
|
||||
servers.add(HkpKeyserverClient.fromHkpKeyserverAddress(cloudPrefs.getKeyserver()));
|
||||
}
|
||||
if (cloudPrefs.isKeybaseEnabled()) {
|
||||
servers.add(KeybaseKeyserverClient.getInstance());
|
||||
}
|
||||
if (cloudPrefs.isFacebookEnabled()) {
|
||||
servers.add(FacebookKeyserverClient.getInstance());
|
||||
}
|
||||
|
|
|
@ -77,14 +77,8 @@ public class ImportKeysList extends ArrayList<ImportKeysListEntry> {
|
|||
|
||||
if (incoming.getKeyserver() != null) {
|
||||
existing.setKeyserver(incoming.getKeyserver());
|
||||
// Mail addresses returned by HKP servers are preferred over keybase.io IDs
|
||||
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;
|
||||
} else if (incoming.getFbUsername() != null) {
|
||||
existing.setFbUsername(incoming.getFbUsername());
|
||||
|
|
|
@ -17,6 +17,18 @@
|
|||
|
||||
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.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
@ -27,18 +39,6 @@ import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
|||
import org.sufficientlysecure.keychain.pgp.UncachedPublicKey;
|
||||
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 {
|
||||
private static final long serialVersionUID = -7797972103284992662L;
|
||||
|
||||
|
@ -64,7 +64,6 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
|
|||
|
||||
private UserId mPrimaryUserId;
|
||||
private HkpKeyserverAddress mKeyserver;
|
||||
private String mKeybaseName;
|
||||
private String mFbUsername;
|
||||
|
||||
private String mQuery;
|
||||
|
@ -197,14 +196,6 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
|
|||
mKeyserver = keyserver;
|
||||
}
|
||||
|
||||
public String getKeybaseName() {
|
||||
return mKeybaseName;
|
||||
}
|
||||
|
||||
public void setKeybaseName(String keybaseName) {
|
||||
mKeybaseName = keybaseName;
|
||||
}
|
||||
|
||||
public String getFbUsername() {
|
||||
return mFbUsername;
|
||||
}
|
||||
|
@ -257,20 +248,11 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
|
|||
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
|
||||
*/
|
||||
public ImportKeysListEntry() {
|
||||
// keys from keyserver are always public keys; from keybase too
|
||||
// keys from keyserver are always public keys
|
||||
mSecretKey = false;
|
||||
|
||||
mUserIds = new ArrayList<>();
|
||||
|
@ -339,20 +321,8 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
|
|||
private void sortMergedUserIds() {
|
||||
mSortedUserIds = new ArrayList<>(mMergedUserIds.entrySet());
|
||||
|
||||
Collections.sort(mSortedUserIds, new Comparator<Map.Entry<String, HashSet<String>>>() {
|
||||
@Override
|
||||
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());
|
||||
}
|
||||
});
|
||||
Collections.sort(mSortedUserIds,
|
||||
(entry1, entry2) -> entry1.getKey().compareTo(entry2.getKey()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -377,7 +347,6 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
|
|||
dest.writeString(mAlgorithm);
|
||||
dest.writeByte((byte) (mSecretKey ? 1 : 0));
|
||||
dest.writeParcelable(mKeyserver, flags);
|
||||
dest.writeString(mKeybaseName);
|
||||
dest.writeString(mFbUsername);
|
||||
}
|
||||
|
||||
|
@ -400,7 +369,6 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
|
|||
vr.mAlgorithm = source.readString();
|
||||
vr.mSecretKey = source.readByte() == 1;
|
||||
vr.mKeyserver = source.readParcelable(HkpKeyserverAddress.class.getClassLoader());
|
||||
vr.mKeybaseName = source.readString();
|
||||
vr.mFbUsername = source.readString();
|
||||
|
||||
return vr;
|
||||
|
|
|
@ -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 doesn’t 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();
|
||||
}
|
||||
}
|
|
@ -26,7 +26,7 @@ import com.google.auto.value.AutoValue;
|
|||
|
||||
/**
|
||||
* 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
|
||||
public abstract class ParcelableKeyRing implements Parcelable {
|
||||
|
@ -41,16 +41,14 @@ public abstract class ParcelableKeyRing implements Parcelable {
|
|||
@Nullable
|
||||
public abstract String getKeyIdHex();
|
||||
@Nullable
|
||||
public abstract String getKeybaseName();
|
||||
@Nullable
|
||||
public abstract String getFbUsername();
|
||||
|
||||
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(
|
||||
byte[] expectedFingerprint, String keyIdHex, String keybaseName, String fbUsername) {
|
||||
return new AutoValue_ParcelableKeyRing(null, expectedFingerprint, keyIdHex, keybaseName, fbUsername);
|
||||
byte[] expectedFingerprint, String keyIdHex, String fbUsername) {
|
||||
return new AutoValue_ParcelableKeyRing(null, expectedFingerprint, keyIdHex, fbUsername);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,8 +51,7 @@ public class ImportKeysListCloudLoader
|
|||
*
|
||||
* @param loaderState state containing the string to search on servers for (if it is a
|
||||
* fingerprint, will enforce fingerprint check) and the keyserver to
|
||||
* search on (whether to search on the keyserver, and whether to search
|
||||
* keybase.io)
|
||||
* search on (whether to search on the keyserver)
|
||||
* @param parcelableProxy explicit proxy to use. If null, will retrieve from preferences
|
||||
*/
|
||||
public ImportKeysListCloudLoader(Context context, CloudLoaderState loaderState,
|
||||
|
@ -84,7 +83,7 @@ public class ImportKeysListCloudLoader
|
|||
for (ImportKeysListEntry e : mEntryList) {
|
||||
if (e.getParcelableKeyRing() == null) {
|
||||
e.setParcelableKeyRing(ParcelableKeyRing.createFromReference(e.getFingerprint(), e.getKeyIdHex(),
|
||||
e.getKeybaseName(), e.getFbUsername()));
|
||||
e.getFbUsername()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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/";
|
||||
}
|
||||
|
||||
}
|
|
@ -41,7 +41,6 @@ import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
|
|||
import org.sufficientlysecure.keychain.keyimport.FacebookKeyserverClient;
|
||||
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
|
||||
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverClient;
|
||||
import org.sufficientlysecure.keychain.keyimport.KeybaseKeyserverClient;
|
||||
import org.sufficientlysecure.keychain.keyimport.KeyserverClient;
|
||||
import org.sufficientlysecure.keychain.keyimport.KeyserverClient.QueryNotFoundException;
|
||||
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
||||
|
@ -76,8 +75,7 @@ import timber.log.Timber;
|
|||
* all steps for this import.
|
||||
* For the import operation, the only valid source is an Iterator of
|
||||
* ParcelableKeyRing, each of which must contain either a single
|
||||
* keyring encoded as bytes, or a unique reference to a keyring
|
||||
* on keyservers and/or keybase.io.
|
||||
* keyring encoded as bytes, or a unique reference to a keyring on keyservers.
|
||||
* It is important to note that public keys should generally be imported before
|
||||
* secret keys, because some implementations (notably Symantec PGP Desktop) do
|
||||
* 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 FacebookKeyserverClient facebookServer;
|
||||
private KeybaseKeyserverClient keybaseServer;
|
||||
|
||||
public ImportOperation(Context context, KeyWritableRepository databaseInteractor, Progressable 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;
|
||||
if (hasFacebookName) {
|
||||
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)
|
||||
throws PgpGeneralException, IOException {
|
||||
if (facebookServer == null) {
|
||||
|
|
|
@ -72,7 +72,7 @@ public class KeySyncOperation extends BaseReadWriteOperation<KeySyncParcel> {
|
|||
ArrayList<ParcelableKeyRing> result = new ArrayList<>(staleKeyFingerprints.size());
|
||||
for (byte[] fingerprint : staleKeyFingerprints) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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];
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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_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_KEYBASE (LogLevel.INFO, R.string.msg_import_fetch_keybase),
|
||||
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_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_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
|
||||
MSG_DATA (LogLevel.START, R.string.msg_data),
|
||||
MSG_DATA_OPENPGP (LogLevel.DEBUG, R.string.msg_data_openpgp),
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
};
|
||||
}
|
|
@ -41,7 +41,6 @@ import org.sufficientlysecure.keychain.operations.ImportOperation;
|
|||
import org.sufficientlysecure.keychain.operations.InputDataOperation;
|
||||
import org.sufficientlysecure.keychain.operations.KeySyncOperation;
|
||||
import org.sufficientlysecure.keychain.operations.KeySyncParcel;
|
||||
import org.sufficientlysecure.keychain.operations.KeybaseVerificationOperation;
|
||||
import org.sufficientlysecure.keychain.operations.PromoteKeyOperation;
|
||||
import org.sufficientlysecure.keychain.operations.RevokeOperation;
|
||||
import org.sufficientlysecure.keychain.operations.SignEncryptOperation;
|
||||
|
@ -114,8 +113,6 @@ public class KeychainServiceTask {
|
|||
} else if (inputParcel instanceof UploadKeyringParcel) {
|
||||
op = new UploadOperation(context, keyRepository, asyncProgressable,
|
||||
operationCancelledBoolean);
|
||||
} else if (inputParcel instanceof KeybaseVerificationParcel) {
|
||||
op = new KeybaseVerificationOperation(context, keyRepository, asyncProgressable);
|
||||
} else if (inputParcel instanceof InputDataParcel) {
|
||||
op = new InputDataOperation(context, keyRepository, asyncProgressable);
|
||||
} else if (inputParcel instanceof BenchmarkInputParcel) {
|
||||
|
|
|
@ -138,7 +138,7 @@ public abstract class DecryptFragment extends Fragment {
|
|||
|
||||
{
|
||||
ParcelableKeyRing keyEntry = ParcelableKeyRing.createFromReference(null,
|
||||
KeyFormattingUtils.convertKeyIdToHex(unknownKeyId), null, null);
|
||||
KeyFormattingUtils.convertKeyIdToHex(unknownKeyId), null);
|
||||
ArrayList<ParcelableKeyRing> selectedEntries = new ArrayList<>();
|
||||
selectedEntries.add(keyEntry);
|
||||
|
||||
|
|
|
@ -769,7 +769,7 @@ public class DecryptListFragment
|
|||
|
||||
{
|
||||
ParcelableKeyRing keyEntry = ParcelableKeyRing.createFromReference(null,
|
||||
KeyFormattingUtils.convertKeyIdToHex(unknownKeyId), null, null);
|
||||
KeyFormattingUtils.convertKeyIdToHex(unknownKeyId), null);
|
||||
ArrayList<ParcelableKeyRing> selectedEntries = new ArrayList<>();
|
||||
selectedEntries.add(keyEntry);
|
||||
|
||||
|
|
|
@ -223,7 +223,7 @@ public class ImportKeysProxyActivity extends FragmentActivity
|
|||
}
|
||||
|
||||
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<>();
|
||||
selectedEntries.add(keyEntry);
|
||||
|
||||
|
|
|
@ -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();
|
||||