diff options
Diffstat (limited to 'OpenKeychain/src/main/java')
10 files changed, 469 insertions, 52 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java index f911318a0..3ac3a9dee 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java @@ -17,6 +17,8 @@ package org.sufficientlysecure.keychain; +import android.accounts.Account; +import android.accounts.AccountManager; import android.app.Application; import android.content.Context; import android.graphics.PorterDuff; @@ -76,6 +78,17 @@ public class KeychainApplication extends Application { brandGlowEffect(getApplicationContext(), getApplicationContext().getResources().getColor(R.color.emphasis)); + + setupAccountAsNeeded(); + } + + private void setupAccountAsNeeded() { + AccountManager manager = AccountManager.get(this); + Account[] accounts = manager.getAccountsByType(getPackageName()); + if (accounts == null || accounts.length == 0) { + Account dummy = new Account(getString(R.string.app_name), getPackageName()); + manager.addAccountExplicitly(dummy, null, null); + } } static void brandGlowEffect(Context context, int brandColor) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java index a92ea5408..583543c4a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java @@ -19,7 +19,10 @@ package org.sufficientlysecure.keychain.helper; import android.accounts.Account; import android.accounts.AccountManager; +import android.content.ContentResolver; import android.content.Context; +import android.database.Cursor; +import android.provider.ContactsContract; import android.util.Patterns; import java.util.ArrayList; @@ -39,4 +42,22 @@ public class ContactHelper { } return new ArrayList<String>(emailSet); } + + public static List<String> getContactMails(Context context) { + ContentResolver resolver = context.getContentResolver(); + Cursor mailCursor = resolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, + new String[]{ContactsContract.CommonDataKinds.Email.DATA}, + null, null, null); + if (mailCursor == null) return null; + + Set<String> mails = new HashSet<String>(); + while (mailCursor.moveToNext()) { + String email = mailCursor.getString(0); + if (email != null) { + mails.add(email); + } + } + mailCursor.close(); + return new ArrayList<String>(mails); + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/EmailKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/EmailKeyHelper.java new file mode 100644 index 000000000..80f52f914 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/EmailKeyHelper.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.helper; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Messenger; +import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; +import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; +import org.sufficientlysecure.keychain.keyimport.Keyserver; +import org.sufficientlysecure.keychain.service.KeychainIntentService; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class EmailKeyHelper { + + public static void importContacts(Context context, Messenger messenger) { + importAll(context, messenger, ContactHelper.getContactMails(context)); + } + + public static void importAll(Context context, Messenger messenger, List<String> mails) { + Set<ImportKeysListEntry> keys = new HashSet<ImportKeysListEntry>(); + for (String mail : mails) { + keys.addAll(getEmailKeys(context, mail)); + } + importKeys(context, messenger, new ArrayList<ImportKeysListEntry>(keys)); + } + + public static List<ImportKeysListEntry> getEmailKeys(Context context, String mail) { + Set<ImportKeysListEntry> keys = new HashSet<ImportKeysListEntry>(); + + // Try _hkp._tcp SRV record first + String[] mailparts = mail.split("@"); + if (mailparts.length == 2) { + HkpKeyserver hkp = HkpKeyserver.resolve(mailparts[1]); + if (hkp != null) { + keys.addAll(getEmailKeys(mail, hkp)); + } + } + + // Most users don't have the SRV record, so ask a default server as well + String[] servers = Preferences.getPreferences(context).getKeyServers(); + if (servers != null && servers.length != 0) { + HkpKeyserver hkp = new HkpKeyserver(servers[0]); + keys.addAll(getEmailKeys(mail, hkp)); + } + return new ArrayList<ImportKeysListEntry>(keys); + } + + private static void importKeys(Context context, Messenger messenger, List<ImportKeysListEntry> keys) { + Intent importIntent = new Intent(context, KeychainIntentService.class); + importIntent.setAction(KeychainIntentService.ACTION_DOWNLOAD_AND_IMPORT_KEYS); + Bundle importData = new Bundle(); + importData.putParcelableArrayList(KeychainIntentService.DOWNLOAD_KEY_LIST, + new ArrayList<ImportKeysListEntry>(keys)); + importIntent.putExtra(KeychainIntentService.EXTRA_DATA, importData); + importIntent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + context.startService(importIntent); + } + + public static List<ImportKeysListEntry> getEmailKeys(String mail, Keyserver keyServer) { + Set<ImportKeysListEntry> keys = new HashSet<ImportKeysListEntry>(); + try { + for (ImportKeysListEntry key : keyServer.search(mail)) { + if (key.isRevoked() || key.isExpired()) continue; + for (String userId : key.getUserIds()) { + if (userId.toLowerCase().contains(mail.toLowerCase())) { + keys.add(key); + } + } + } + } catch (Keyserver.QueryFailedException ignored) { + } catch (Keyserver.QueryNeedsRepairException ignored) { + } + return new ArrayList<ImportKeysListEntry>(keys); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java index 5969455bd..2ec9e1c07 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java @@ -33,6 +33,10 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.util.Log; +import org.xbill.DNS.Lookup; +import org.xbill.DNS.Record; +import org.xbill.DNS.SRVRecord; +import org.xbill.DNS.Type; import java.io.IOException; import java.io.InputStream; @@ -45,6 +49,8 @@ import java.net.URLDecoder; import java.net.URLEncoder; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; import java.util.GregorianCalendar; import java.util.List; import java.util.Locale; @@ -75,6 +81,7 @@ public class HkpKeyserver extends Keyserver { private String mHost; private short mPort; + private boolean mSecure; /** * pub:%keyid%:%algo%:%keylen%:%creationdate%:%expirationdate%:%flags% @@ -109,7 +116,7 @@ public class HkpKeyserver extends Keyserver { */ public static final Pattern PUB_KEY_LINE = Pattern .compile("pub:([0-9a-fA-F]+):([0-9]+):([0-9]+):([0-9]+):([0-9]*):([rde]*)[ \n\r]*" // pub line - + "(uid:(.*):([0-9]+):([0-9]*):([rde]*))+", // one or more uid lines + + "((uid:([^:]*):([0-9]+):([0-9]*):([rde]*)[ \n\r]*)+)", // one or more uid lines Pattern.CASE_INSENSITIVE); /** @@ -137,10 +144,11 @@ public class HkpKeyserver extends Keyserver { * </ul> */ public static final Pattern UID_LINE = Pattern - .compile("uid:(.*):([0-9]+):([0-9]*):([rde]*)", + .compile("uid:([^:]*):([0-9]+):([0-9]*):([rde]*)", Pattern.CASE_INSENSITIVE); private static final short PORT_DEFAULT = 11371; + private static final short PORT_DEFAULT_HKPS = 443; /** * @param hostAndPort may be just @@ -151,31 +159,68 @@ public class HkpKeyserver extends Keyserver { public HkpKeyserver(String hostAndPort) { String host = hostAndPort; short port = PORT_DEFAULT; - final int colonPosition = hostAndPort.lastIndexOf(':'); - if (colonPosition > 0) { - host = hostAndPort.substring(0, colonPosition); - final String portStr = hostAndPort.substring(colonPosition + 1); - port = Short.decode(portStr); + boolean secure = false; + String[] parts = hostAndPort.split(":"); + if (parts.length > 1) { + if (!parts[0].contains(".")) { // This is not a domain or ip, so it must be a protocol name + if (parts[0].equalsIgnoreCase("hkps") || parts[0].equalsIgnoreCase("https")) { + secure = true; + port = PORT_DEFAULT_HKPS; + } else if (!parts[0].equalsIgnoreCase("hkp") && !parts[0].equalsIgnoreCase("http")) { + throw new IllegalArgumentException("Protocol " + parts[0] + " is unknown"); + } + host = parts[1]; + if (host.startsWith("//")) { // People tend to type https:// and hkps://, so we'll support that as well + host = host.substring(2); + } + if (parts.length > 2) { + port = Short.decode(parts[2]); + } + } else { + host = parts[0]; + port = Short.decode(parts[1]); + } } mHost = host; mPort = port; + mSecure = secure; } public HkpKeyserver(String host, short port) { + this(host, port, false); + } + + public HkpKeyserver(String host, short port, boolean secure) { mHost = host; mPort = port; + mSecure = secure; + } + + private String getUrlPrefix() { + return mSecure ? "https://" : "http://"; } private String query(String request) throws QueryFailedException, HttpError { - InetAddress ips[]; - try { - ips = InetAddress.getAllByName(mHost); - } catch (UnknownHostException e) { - throw new QueryFailedException(e.toString()); + List<String> urls = new ArrayList<String>(); + if (mSecure) { + urls.add(getUrlPrefix() + mHost + ":" + mPort + request); + } else { + InetAddress ips[]; + try { + ips = InetAddress.getAllByName(mHost); + } catch (UnknownHostException e) { + throw new QueryFailedException(e.toString()); + } + for (InetAddress ip : ips) { + // Note: This is actually not HTTP 1.1 compliant, as we hide the real "Host" value, + // but Android's HTTPUrlConnection does not support any other way to set + // Socket's remote IP address... + urls.add(getUrlPrefix() + ip.getHostAddress() + ":" + mPort + request); + } } - for (int i = 0; i < ips.length; ++i) { + + for (String url : urls) { try { - String url = "http://" + ips[i].getHostAddress() + ":" + mPort + request; Log.d(Constants.TAG, "hkp keyserver query: " + url); URL realUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection(); @@ -238,6 +283,7 @@ public class HkpKeyserver extends Keyserver { while (matcher.find()) { final ImportKeysListEntry entry = new ImportKeysListEntry(); entry.setQuery(query); + entry.setOrigin(getUrlPrefix() + mHost + ":" + mPort); entry.setBitStrength(Integer.parseInt(matcher.group(3))); @@ -262,6 +308,7 @@ public class HkpKeyserver extends Keyserver { entry.setDate(tmpGreg.getTime()); entry.setRevoked(matcher.group(6).contains("r")); + entry.setExpired(matcher.group(6).contains("e")); ArrayList<String> userIds = new ArrayList<String>(); final String uidLines = matcher.group(7); @@ -290,7 +337,7 @@ public class HkpKeyserver extends Keyserver { public String get(String keyIdHex) throws QueryFailedException { HttpClient client = new DefaultHttpClient(); try { - String query = "http://" + mHost + ":" + mPort + + String query = getUrlPrefix() + mHost + ":" + mPort + "/pks/lookup?op=get&options=mr&search=" + keyIdHex; Log.d(Constants.TAG, "hkp keyserver get: " + query); HttpGet get = new HttpGet(query); @@ -319,7 +366,7 @@ public class HkpKeyserver extends Keyserver { public void add(String armoredKey) throws AddKeyException { HttpClient client = new DefaultHttpClient(); try { - String query = "http://" + mHost + ":" + mPort + "/pks/add"; + String query = getUrlPrefix() + mHost + ":" + mPort + "/pks/add"; HttpPost post = new HttpPost(query); Log.d(Constants.TAG, "hkp keyserver add: " + query); List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2); @@ -336,4 +383,36 @@ public class HkpKeyserver extends Keyserver { client.getConnectionManager().shutdown(); } } + + @Override + public String toString() { + return mHost + ":" + mPort; + } + + /** + * Tries to find a server responsible for a given domain + * + * @return A responsible Keyserver or null if not found. + */ + public static HkpKeyserver resolve(String domain) { + try { + Record[] records = new Lookup("_hkp._tcp." + domain, Type.SRV).run(); + if (records.length > 0) { + Arrays.sort(records, new Comparator<Record>() { + @Override + public int compare(Record lhs, Record rhs) { + if (!(lhs instanceof SRVRecord)) return 1; + if (!(rhs instanceof SRVRecord)) return -1; + return ((SRVRecord) lhs).getPriority() - ((SRVRecord) rhs).getPriority(); + } + }); + Record record = records[0]; // This is our best choice + if (record instanceof SRVRecord) { + return new HkpKeyserver(((SRVRecord) record).getTarget().toString(), (short) ((SRVRecord) record).getPort()); + } + } + } catch (Exception ignored) { + } + return null; + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java index c43f72235..b1df7886d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java @@ -36,6 +36,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { public long keyId; public String keyIdHex; public boolean revoked; + public boolean expired; public Date date; // TODO: not displayed public String fingerprintHex; public int bitStrength; @@ -44,6 +45,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { public String mPrimaryUserId; private String mExtraData; private String mQuery; + private String mOrigin; private boolean mSelected; @@ -57,6 +59,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { dest.writeStringList(userIds); dest.writeLong(keyId); dest.writeByte((byte) (revoked ? 1 : 0)); + dest.writeByte((byte) (expired ? 1 : 0)); dest.writeSerializable(date); dest.writeString(fingerprintHex); dest.writeString(keyIdHex); @@ -65,6 +68,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { dest.writeByte((byte) (secretKey ? 1 : 0)); dest.writeByte((byte) (mSelected ? 1 : 0)); dest.writeString(mExtraData); + dest.writeString(mOrigin); } public static final Creator<ImportKeysListEntry> CREATOR = new Creator<ImportKeysListEntry>() { @@ -75,6 +79,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { source.readStringList(vr.userIds); vr.keyId = source.readLong(); vr.revoked = source.readByte() == 1; + vr.expired = source.readByte() == 1; vr.date = (Date) source.readSerializable(); vr.fingerprintHex = source.readString(); vr.keyIdHex = source.readString(); @@ -83,6 +88,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { vr.secretKey = source.readByte() == 1; vr.mSelected = source.readByte() == 1; vr.mExtraData = source.readString(); + vr.mOrigin = source.readString(); return vr; } @@ -104,6 +110,14 @@ public class ImportKeysListEntry implements Serializable, Parcelable { this.mSelected = selected; } + public boolean isExpired() { + return expired; + } + + public void setExpired(boolean expired) { + this.expired = expired; + } + public long getKeyId() { return keyId; } @@ -196,6 +210,14 @@ public class ImportKeysListEntry implements Serializable, Parcelable { mQuery = query; } + public String getOrigin() { + return mOrigin; + } + + public void setOrigin(String origin) { + mOrigin = origin; + } + /** * Constructor for later querying from keyserver */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java index f9b6abf18..8054edd3e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java @@ -31,6 +31,7 @@ import java.net.URLEncoder; import java.util.ArrayList; public class KeybaseKeyserver extends Keyserver { + public static final String ORIGIN = "keybase:keybase.io"; private String mQuery; @Override @@ -87,6 +88,7 @@ public class KeybaseKeyserver extends Keyserver { final ImportKeysListEntry entry = new ImportKeysListEntry(); entry.setQuery(mQuery); + entry.setOrigin(ORIGIN); String keybaseId = JWalk.getString(match, "components", "username", "val"); String fullName = JWalk.getString(match, "components", "full_name", "val"); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java index 868f543f0..842e7d922 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java @@ -48,12 +48,12 @@ public abstract class Keyserver { private static final long serialVersionUID = -507574859137295530L; } - abstract List<ImportKeysListEntry> search(String query) throws QueryFailedException, + public abstract List<ImportKeysListEntry> search(String query) throws QueryFailedException, QueryNeedsRepairException; - abstract String get(String keyIdHex) throws QueryFailedException; + public abstract String get(String keyIdHex) throws QueryFailedException; - abstract void add(String armoredKey) throws AddKeyException; + public abstract void add(String armoredKey) throws AddKeyException; public static String readAll(InputStream in, String encoding) throws IOException { ByteArrayOutputStream raw = new ByteArrayOutputStream(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java new file mode 100644 index 000000000..4d0397196 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.accounts.Account; +import android.app.Service; +import android.content.AbstractThreadedSyncAdapter; +import android.content.ContentProviderClient; +import android.content.Intent; +import android.content.SyncResult; +import android.os.*; +import org.sufficientlysecure.keychain.helper.EmailKeyHelper; +import org.sufficientlysecure.keychain.util.Log; + +public class ContactSyncAdapterService extends Service { + + private class ContactSyncAdapter extends AbstractThreadedSyncAdapter { + + public ContactSyncAdapter() { + super(ContactSyncAdapterService.this, true); + } + + @Override + public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, + final SyncResult syncResult) { + EmailKeyHelper.importContacts(getContext(), new Messenger(new Handler(Looper.getMainLooper(), + new Handler.Callback() { + @Override + public boolean handleMessage(Message msg) { + Bundle data = msg.getData(); + switch (msg.arg1) { + case KeychainIntentServiceHandler.MESSAGE_OKAY: + return true; + case KeychainIntentServiceHandler.MESSAGE_UPDATE_PROGRESS: + if (data.containsKey(KeychainIntentServiceHandler.DATA_PROGRESS) && + data.containsKey(KeychainIntentServiceHandler.DATA_PROGRESS_MAX)) { + Log.d("Keychain/ContactSync/DownloadKeys", "Progress: " + + data.getInt(KeychainIntentServiceHandler.DATA_PROGRESS) + "/" + + data.getInt(KeychainIntentServiceHandler.DATA_PROGRESS_MAX)); + return false; + } + default: + Log.d("Keychain/ContactSync/DownloadKeys", "Syncing... " + msg.toString()); + return false; + } + } + }))); + } + } + + @Override + public IBinder onBind(Intent intent) { + return new ContactSyncAdapter().getSyncAdapterBinder(); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/DummyAccountService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/DummyAccountService.java new file mode 100644 index 000000000..d3b29d5cf --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/DummyAccountService.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> + * + * 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.accounts.AbstractAccountAuthenticator; +import android.accounts.Account; +import android.accounts.AccountAuthenticatorResponse; +import android.accounts.NetworkErrorException; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.widget.Toast; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.util.Log; + +/** + * This service actually does nothing, it's sole task is to show a Toast if the use tries to create an account. + */ +public class DummyAccountService extends Service { + + private class Toaster { + private static final String TOAST_MESSAGE = "toast_message"; + private Context context; + private Handler handler = new Handler(new Handler.Callback() { + @Override + public boolean handleMessage(Message msg) { + Toast.makeText(context, msg.getData().getString(TOAST_MESSAGE), Toast.LENGTH_LONG).show(); + return true; + } + }); + + private Toaster(Context context) { + this.context = context; + } + + public void toast(int resourceId) { + toast(context.getString(resourceId)); + } + + public void toast(String message) { + Message msg = new Message(); + Bundle bundle = new Bundle(); + bundle.putString(TOAST_MESSAGE, message); + msg.setData(bundle); + handler.sendMessage(msg); + } + } + + private class Authenticator extends AbstractAccountAuthenticator { + + public Authenticator() { + super(DummyAccountService.this); + } + + @Override + public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { + Log.d("DummyAccountService", "editProperties"); + return null; + } + + @Override + public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, + String[] requiredFeatures, Bundle options) throws NetworkErrorException { + response.onResult(new Bundle()); + toaster.toast(R.string.info_no_manual_account_creation); + Log.d("DummyAccountService", "addAccount"); + return null; + } + + @Override + public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) + throws NetworkErrorException { + Log.d("DummyAccountService", "confirmCredentials"); + return null; + } + + @Override + public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, + Bundle options) throws NetworkErrorException { + Log.d("DummyAccountService", "getAuthToken"); + return null; + } + + @Override + public String getAuthTokenLabel(String authTokenType) { + Log.d("DummyAccountService", "getAuthTokenLabel"); + return null; + } + + @Override + public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, + Bundle options) throws NetworkErrorException { + Log.d("DummyAccountService", "updateCredentials"); + return null; + } + + @Override + public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) + throws NetworkErrorException { + Log.d("DummyAccountService", "hasFeatures"); + return null; + } + } + + private Toaster toaster; + + @Override + public IBinder onBind(Intent intent) { + toaster = new Toaster(this); + return new Authenticator().getIBinder(); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 38f40db29..ce706c84f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -32,6 +32,7 @@ import org.sufficientlysecure.keychain.helper.FileHelper; import org.sufficientlysecure.keychain.helper.OtherHelper; import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; +import org.sufficientlysecure.keychain.keyimport.Keyserver; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedSecretKey; import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing; @@ -734,49 +735,30 @@ public class KeychainIntentService extends IntentService } catch (Exception e) { sendErrorToHandler(e); } - } else if (ACTION_IMPORT_KEYBASE_KEYS.equals(action)) { - ArrayList<ImportKeysListEntry> entries = data.getParcelableArrayList(DOWNLOAD_KEY_LIST); - - try { - KeybaseKeyserver server = new KeybaseKeyserver(); - ArrayList<ParcelableKeyRing> keyRings = new ArrayList<ParcelableKeyRing>(entries.size()); - for (ImportKeysListEntry entry : entries) { - // the keybase handle is in userId(1) - String keybaseId = entry.getExtraData(); - byte[] downloadedKeyBytes = server.get(keybaseId).getBytes(); - - // save key bytes in entry object for doing the - // actual import afterwards - keyRings.add(new ParcelableKeyRing(downloadedKeyBytes)); - } - - Intent importIntent = new Intent(this, KeychainIntentService.class); - importIntent.setAction(ACTION_IMPORT_KEYRING); - Bundle importData = new Bundle(); - importData.putParcelableArrayList(IMPORT_KEY_LIST, keyRings); - importIntent.putExtra(EXTRA_DATA, importData); - importIntent.putExtra(EXTRA_MESSENGER, mMessenger); - - // now import it with this service - onHandleIntent(importIntent); - - // result is handled in ACTION_IMPORT_KEYRING - } catch (Exception e) { - sendErrorToHandler(e); - } - } else if (ACTION_DOWNLOAD_AND_IMPORT_KEYS.equals(action)) { + } else if (ACTION_DOWNLOAD_AND_IMPORT_KEYS.equals(action) || ACTION_IMPORT_KEYBASE_KEYS.equals(action)) { try { ArrayList<ImportKeysListEntry> entries = data.getParcelableArrayList(DOWNLOAD_KEY_LIST); // this downloads the keys and places them into the ImportKeysListEntry entries String keyServer = data.getString(DOWNLOAD_KEY_SERVER); - HkpKeyserver server = new HkpKeyserver(keyServer); ArrayList<ParcelableKeyRing> keyRings = new ArrayList<ParcelableKeyRing>(entries.size()); for (ImportKeysListEntry entry : entries) { + + Keyserver server; + if (entry.getOrigin() == null) { + server = new HkpKeyserver(keyServer); + } else if (KeybaseKeyserver.ORIGIN.equals(entry.getOrigin())) { + server = new KeybaseKeyserver(); + } else { + server = new HkpKeyserver(entry.getOrigin()); + } + // if available use complete fingerprint for get request byte[] downloadedKeyBytes; - if (entry.getFingerprintHex() != null) { + if (KeybaseKeyserver.ORIGIN.equals(entry.getOrigin())) { + downloadedKeyBytes = server.get(entry.getExtraData()).getBytes(); + } else if (entry.getFingerprintHex() != null) { downloadedKeyBytes = server.get("0x" + entry.getFingerprintHex()).getBytes(); } else { downloadedKeyBytes = server.get(entry.getKeyIdHex()).getBytes(); |