--- a/mobile/android/base/android-services.mozbuild
+++ b/mobile/android/base/android-services.mozbuild
@@ -866,19 +866,17 @@ sync_java_files = [TOPSRCDIR + '/mobile/
'fxa/SyncStatusListener.java',
'sync/AlreadySyncingException.java',
'sync/BackoffHandler.java',
'sync/BadRequiredFieldJSONException.java',
'sync/CollectionKeys.java',
'sync/CommandProcessor.java',
'sync/CommandRunner.java',
'sync/config/AccountPickler.java',
- 'sync/config/activities/SelectEnginesActivity.java',
'sync/config/ClientRecordTerminator.java',
- 'sync/config/ConfigurationMigrator.java',
'sync/CredentialException.java',
'sync/crypto/CryptoException.java',
'sync/crypto/CryptoInfo.java',
'sync/crypto/HKDF.java',
'sync/crypto/HMACVerificationException.java',
'sync/crypto/KeyBundle.java',
'sync/crypto/MissingCryptoInputException.java',
'sync/crypto/NoKeyBundleException.java',
@@ -896,39 +894,16 @@ sync_java_files = [TOPSRCDIR + '/mobile/
'sync/delegates/NodeAssignmentCallback.java',
'sync/delegates/WipeServerDelegate.java',
'sync/EngineSettings.java',
'sync/ExtendedJSONObject.java',
'sync/GlobalSession.java',
'sync/HTTPFailureException.java',
'sync/InfoCollections.java',
'sync/InfoCounts.java',
- 'sync/jpake/BigIntegerHelper.java',
- 'sync/jpake/Gx3OrGx4IsZeroOrOneException.java',
- 'sync/jpake/IncorrectZkpException.java',
- 'sync/jpake/JPakeClient.java',
- 'sync/jpake/JPakeCrypto.java',
- 'sync/jpake/JPakeJson.java',
- 'sync/jpake/JPakeNoActivePairingException.java',
- 'sync/jpake/JPakeNumGenerator.java',
- 'sync/jpake/JPakeNumGeneratorRandom.java',
- 'sync/jpake/JPakeParty.java',
- 'sync/jpake/stage/CompleteStage.java',
- 'sync/jpake/stage/ComputeFinalStage.java',
- 'sync/jpake/stage/ComputeKeyVerificationStage.java',
- 'sync/jpake/stage/ComputeStepOneStage.java',
- 'sync/jpake/stage/ComputeStepTwoStage.java',
- 'sync/jpake/stage/DecryptDataStage.java',
- 'sync/jpake/stage/DeleteChannel.java',
- 'sync/jpake/stage/GetChannelStage.java',
- 'sync/jpake/stage/GetRequestStage.java',
- 'sync/jpake/stage/JPakeStage.java',
- 'sync/jpake/stage/PutRequestStage.java',
- 'sync/jpake/stage/VerifyPairingStage.java',
- 'sync/jpake/Zkp.java',
'sync/JSONRecordFetcher.java',
'sync/KeyBundleProvider.java',
'sync/MetaGlobal.java',
'sync/MetaGlobalException.java',
'sync/MetaGlobalMissingEnginesException.java',
'sync/MetaGlobalNotSetException.java',
'sync/middleware/Crypto5MiddlewareRepository.java',
'sync/middleware/Crypto5MiddlewareRepositorySession.java',
@@ -964,19 +939,16 @@ sync_java_files = [TOPSRCDIR + '/mobile/
'sync/net/WBORequestDelegate.java',
'sync/NoCollectionKeysSetException.java',
'sync/NodeAuthenticationException.java',
'sync/NonArrayJSONException.java',
'sync/NonObjectJSONException.java',
'sync/NullClusterURLException.java',
'sync/PersistedMetaGlobal.java',
'sync/PrefsBackoffHandler.java',
- 'sync/receivers/SyncAccountDeletedReceiver.java',
- 'sync/receivers/SyncAccountDeletedService.java',
- 'sync/receivers/UpgradeReceiver.java',
'sync/repositories/android/AndroidBrowserBookmarksDataAccessor.java',
'sync/repositories/android/AndroidBrowserBookmarksRepository.java',
'sync/repositories/android/AndroidBrowserBookmarksRepositorySession.java',
'sync/repositories/android/AndroidBrowserHistoryDataAccessor.java',
'sync/repositories/android/AndroidBrowserHistoryDataExtender.java',
'sync/repositories/android/AndroidBrowserHistoryRepository.java',
'sync/repositories/android/AndroidBrowserHistoryRepositorySession.java',
'sync/repositories/android/AndroidBrowserRepository.java',
@@ -1044,36 +1016,21 @@ sync_java_files = [TOPSRCDIR + '/mobile/
'sync/repositories/RepositorySessionBundle.java',
'sync/repositories/Server11Repository.java',
'sync/repositories/Server11RepositorySession.java',
'sync/repositories/StoreFailedException.java',
'sync/repositories/StoreTracker.java',
'sync/repositories/StoreTrackingRepositorySession.java',
'sync/Server11PreviousPostFailedException.java',
'sync/Server11RecordPostFailedException.java',
- 'sync/setup/activities/AccountActivity.java',
'sync/setup/activities/ActivityUtils.java',
- 'sync/setup/activities/RedirectToSetupActivity.java',
- 'sync/setup/activities/SendTabData.java',
- 'sync/setup/activities/SetupFailureActivity.java',
- 'sync/setup/activities/SetupSuccessActivity.java',
- 'sync/setup/activities/SetupSyncActivity.java',
- 'sync/setup/activities/SyncActivity.java',
'sync/setup/activities/WebURLFinder.java',
- 'sync/setup/activities/WebViewActivity.java',
- 'sync/setup/auth/AccountAuthenticator.java',
- 'sync/setup/auth/AuthenticateAccountStage.java',
- 'sync/setup/auth/AuthenticationResult.java',
- 'sync/setup/auth/AuthenticatorStage.java',
- 'sync/setup/auth/EnsureUserExistenceStage.java',
- 'sync/setup/auth/FetchUserNodeStage.java',
'sync/setup/Constants.java',
'sync/setup/InvalidSyncKeyException.java',
'sync/setup/SyncAccounts.java',
- 'sync/setup/SyncAuthenticatorService.java',
'sync/SharedPreferencesClientsDataDelegate.java',
'sync/SharedPreferencesNodeAssignmentCallback.java',
'sync/stage/AbstractNonRepositorySyncStage.java',
'sync/stage/AbstractSessionManagingSyncStage.java',
'sync/stage/AndroidBrowserBookmarksServerSyncStage.java',
'sync/stage/AndroidBrowserHistoryServerSyncStage.java',
'sync/stage/CheckPreconditionsStage.java',
'sync/stage/CompletedStage.java',
@@ -1087,18 +1044,16 @@ sync_java_files = [TOPSRCDIR + '/mobile/
'sync/stage/NoSuchStageException.java',
'sync/stage/NoSyncIDException.java',
'sync/stage/PasswordsServerSyncStage.java',
'sync/stage/SafeConstrainedServer11Repository.java',
'sync/stage/ServerSyncStage.java',
'sync/stage/SyncClientsEngineStage.java',
'sync/stage/UploadMetaGlobalStage.java',
'sync/Sync11Configuration.java',
- 'sync/syncadapter/SyncAdapter.java',
- 'sync/syncadapter/SyncService.java',
'sync/SyncConfiguration.java',
'sync/SyncConfigurationException.java',
'sync/SyncConstants.java',
'sync/SyncException.java',
'sync/synchronizer/ConcurrentRecordConsumer.java',
'sync/synchronizer/RecordConsumer.java',
'sync/synchronizer/RecordsChannel.java',
'sync/synchronizer/RecordsChannelDelegate.java',
--- a/mobile/android/config/proguard/proguard.cfg
+++ b/mobile/android/config/proguard/proguard.cfg
@@ -11,18 +11,18 @@
# Preserve all fundamental application classes.
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.preference.Preference
--keep public class * extends org.mozilla.gecko.sync.syncadapter.SyncAdapter
--keep class org.mozilla.gecko.sync.syncadapter.SyncAdapter
+-keep public class * extends org.mozilla.gecko.fxa.sync.FxAccountSyncAdapter
+-keep class org.mozilla.gecko.fxa.sync.FxAccountSyncAdapter
-keep public class * extends android.support.v4.app.Fragment
# Preserve all native method names and the names of their classes.
-keepclasseswithmembernames class * {
native <methods>;
}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/config/ConfigurationMigrator.java
+++ /dev/null
@@ -1,382 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.config;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.Utils;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-
-/**
- * Migrate Sync preferences between versions.
- * <p>
- * The original preferences were un-versioned; we refer to that as "version 0".
- * The original preferences were stored in three places:
- * <ul>
- * <li>most prefs were kept in per-Sync account Android shared prefs;</li>
- * <li>some prefs were kept in per-App Android shared prefs;</li>
- * <li>some client prefs were kept in the (assumed unique) Android Account.</li>
- * </ul>
- * <p>
- * Post version 0, all preferences are stored in per-Sync account Android shared prefs.
- */
-public class ConfigurationMigrator {
- public static final String LOG_TAG = "ConfigMigrator";
-
- /**
- * Copy and rename preferences.
- *
- * @param from source.
- * @param to sink.
- * @param map map from old preference names to new preference names.
- * @return the number of preferences migrated.
- */
- protected static int copyPreferences(final SharedPreferences from, final Map<String, String> map, final Editor to) {
- int count = 0;
-
- // SharedPreferences has no way to get a key/value pair without specifying the value type, so we do this instead.
- for (Entry<String, ?> entry : from.getAll().entrySet()) {
- String fromKey = entry.getKey();
- String toKey = map.get(fromKey);
- if (toKey == null) {
- continue;
- }
-
- Object value = entry.getValue();
- if (value instanceof Boolean) {
- to.putBoolean(toKey, (Boolean) value);
- } else if (value instanceof Float) {
- to.putFloat(toKey, (Float) value);
- } else if (value instanceof Integer) {
- to.putInt(toKey, (Integer) value);
- } else if (value instanceof Long) {
- to.putLong(toKey, (Long) value);
- } else if (value instanceof String) {
- to.putString(toKey, (String) value);
- } else {
- // Do nothing -- perhaps SharedPreferences accepts types we don't know about.
- }
-
- if (Logger.LOG_PERSONAL_INFORMATION) {
- Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "' (" + value + ").");
- } else {
- Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "'.");
- }
- count += 1;
- }
-
- return count;
- }
-
- protected final static String V0_PREF_CLUSTER_URL_IS_STALE = "clusterurlisstale";
- protected final static String V1_PREF_CLUSTER_URL_IS_STALE = V0_PREF_CLUSTER_URL_IS_STALE;
- protected final static String V0_PREF_EARLIEST_NEXT_SYNC = "earliestnextsync";
- protected final static String V1_PREF_EARLIEST_NEXT_SYNC = V0_PREF_EARLIEST_NEXT_SYNC;
-
- /**
- * Extract version 0 preferences from per-App Android shared prefs and write to version 1 per-Sync account shared prefs.
- *
- * @param from per-App version 0 Android shared prefs.
- * @param to per-Sync account version 1 shared prefs.
- * @return the number of preferences migrated.
- * @throws Exception
- */
- protected static int upgradeGlobals0to1(final SharedPreferences from, final SharedPreferences to) throws Exception {
- Map<String, String> map = new HashMap<String, String>();
- map.put(V0_PREF_CLUSTER_URL_IS_STALE, V1_PREF_CLUSTER_URL_IS_STALE);
- map.put(V0_PREF_EARLIEST_NEXT_SYNC, V1_PREF_EARLIEST_NEXT_SYNC);
-
- Editor editor = to.edit();
- int count = copyPreferences(from, map, editor);
- if (count > 0) {
- editor.commit();
- }
- return count;
- }
-
- /**
- * Extract version 1 per-Sync account shared prefs and write to version 0 preferences from per-App Android shared prefs.
- *
- * @param from per-Sync account version 1 shared prefs.
- * @param to per-App version 0 Android shared prefs.
- * @return the number of preferences migrated.
- * @throws Exception
- */
- protected static int downgradeGlobals1to0(final SharedPreferences from, final SharedPreferences to) throws Exception {
- Map<String, String> map = new HashMap<String, String>();
- map.put(V1_PREF_CLUSTER_URL_IS_STALE, V0_PREF_CLUSTER_URL_IS_STALE);
- map.put(V1_PREF_EARLIEST_NEXT_SYNC, V0_PREF_EARLIEST_NEXT_SYNC);
-
- Editor editor = to.edit();
- int count = copyPreferences(from, map, editor);
- if (count > 0) {
- editor.commit();
- }
- return count;
- }
-
- protected static final String V0_PREF_ACCOUNT_GUID = "account.guid";
- protected static final String V1_PREF_ACCOUNT_GUID = V0_PREF_ACCOUNT_GUID;
- protected static final String V0_PREF_CLIENT_NAME = "account.clientName";
- protected static final String V1_PREF_CLIENT_NAME = V0_PREF_CLIENT_NAME;
- protected static final String V0_PREF_NUM_CLIENTS = "account.numClients";
- protected static final String V1_PREF_NUM_CLIENTS = V0_PREF_NUM_CLIENTS;
-
- /**
- * Extract version 0 per-Android account user data and write to version 1 per-Sync account shared prefs.
- *
- * @param accountManager Android account manager.
- * @param account Android account.
- * @param to per-Sync account version 1 shared prefs.
- * @return the number of preferences migrated.
- * @throws Exception
- */
- protected static int upgradeAndroidAccount0to1(final AccountManager accountManager, final Account account, final SharedPreferences to) throws Exception {
- final String V0_PREF_ACCOUNT_GUID = "account.guid";
- final String V1_PREF_ACCOUNT_GUID = V0_PREF_ACCOUNT_GUID;
- final String V0_PREF_CLIENT_NAME = "account.clientName";
- final String V1_PREF_CLIENT_NAME = V0_PREF_CLIENT_NAME;
- final String V0_PREF_NUM_CLIENTS = "account.numClients";
- final String V1_PREF_NUM_CLIENTS = V0_PREF_NUM_CLIENTS;
-
- String accountGUID = null;
- String clientName = null;
- long numClients = -1;
- try {
- accountGUID = accountManager.getUserData(account, V0_PREF_ACCOUNT_GUID);
- } catch (Exception e) {
- // Do nothing.
- }
- try {
- clientName = accountManager.getUserData(account, V0_PREF_CLIENT_NAME);
- } catch (Exception e) {
- // Do nothing.
- }
- try {
- numClients = Long.parseLong(accountManager.getUserData(account, V0_PREF_NUM_CLIENTS));
- } catch (Exception e) {
- // Do nothing.
- }
-
- final Editor editor = to.edit();
-
- int count = 0;
- if (accountGUID != null) {
- final String fromKey = V0_PREF_ACCOUNT_GUID;
- final String toKey = V1_PREF_ACCOUNT_GUID;
- if (Logger.LOG_PERSONAL_INFORMATION) {
- Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "' (" + accountGUID + ").");
- } else {
- Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "'.");
- }
- editor.putString(toKey, accountGUID);
- count += 1;
- }
- if (clientName != null) {
- final String fromKey = V0_PREF_CLIENT_NAME;
- final String toKey = V1_PREF_CLIENT_NAME;
- if (Logger.LOG_PERSONAL_INFORMATION) {
- Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "' (" + clientName + ").");
- } else {
- Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "'.");
- }
- editor.putString(toKey, clientName);
- count += 1;
- }
- if (numClients > -1) {
- final String fromKey = V0_PREF_NUM_CLIENTS;
- final String toKey = V1_PREF_NUM_CLIENTS;
- if (Logger.LOG_PERSONAL_INFORMATION) {
- Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "' (" + numClients + ").");
- } else {
- Logger.debug(LOG_TAG, "Migrated '" + fromKey + "' to '" + toKey + "'.");
- }
- editor.putLong(toKey, numClients);
- count += 1;
- }
-
- if (count > 0) {
- editor.commit();
- }
- return count;
- }
-
- /**
- * Extract version 1 per-Sync account shared prefs and write to version 0 per-Android account user data.
- *
- * @param from per-Sync account version 1 shared prefs.
- * @param accountManager Android account manager.
- * @param account Android account.
- * @return the number of preferences migrated.
- * @throws Exception
- */
- protected static int downgradeAndroidAccount1to0(final SharedPreferences from, final AccountManager accountManager, final Account account) throws Exception {
- final String accountGUID = from.getString(V1_PREF_ACCOUNT_GUID, null);
- final String clientName = from.getString(V1_PREF_CLIENT_NAME, null);
- final long numClients = from.getLong(V1_PREF_NUM_CLIENTS, -1L);
-
- int count = 0;
- if (accountGUID != null) {
- Logger.debug(LOG_TAG, "Migrated account GUID.");
- accountManager.setUserData(account, V0_PREF_ACCOUNT_GUID, accountGUID);
- count += 1;
- }
- if (clientName != null) {
- Logger.debug(LOG_TAG, "Migrated client name.");
- accountManager.setUserData(account, V1_PREF_CLIENT_NAME, clientName);
- count += 1;
- }
- if (numClients > -1) {
- Logger.debug(LOG_TAG, "Migrated clients count.");
- accountManager.setUserData(account, V1_PREF_NUM_CLIENTS, Long.toString(numClients));
- count += 1;
- }
- return count;
- }
-
- /**
- * Extract version 0 per-Android account user data and write to version 1 per-Sync account shared prefs.
- *
- * @param from per-Sync account version 0 shared prefs.
- * @param to per-Sync account version 1 shared prefs.
- * @return the number of preferences migrated.
- * @throws Exception
- */
- protected static int upgradeShared0to1(final SharedPreferences from, final SharedPreferences to) {
- final Map<String, String> map = new HashMap<String, String>();
- final String[] prefs = new String [] {
- "syncID",
- "clusterURL",
- "enabledEngineNames",
-
- "metaGlobalLastModified", "metaGlobalServerResponseBody",
-
- "crypto5KeysLastModified", "crypto5KeysServerResponseBody",
-
- "serverClientsTimestamp", "serverClientRecordTimestamp",
-
- "forms.remote", "forms.local", "forms.syncID",
- "tabs.remote", "tabs.local", "tabs.syncID",
- "passwords.remote", "passwords.local", "passwords.syncID",
- "history.remote", "history.local", "history.syncID",
- "bookmarks.remote", "bookmarks.local", "bookmarks.syncID",
- };
- for (String pref : prefs) {
- map.put(pref, pref);
- }
-
- Editor editor = to.edit();
- int count = copyPreferences(from, map, editor);
- if (count > 0) {
- editor.commit();
- }
- return count;
- }
-
- /**
- * Extract version 1 per-Sync account shared prefs and write to version 0 per-Android account user data.
- *
- * @param from per-Sync account version 1 shared prefs.
- * @param to per-Sync account version 0 shared prefs.
- * @return the number of preferences migrated.
- * @throws Exception
- */
- protected static int downgradeShared1to0(final SharedPreferences from, final SharedPreferences to) {
- // Strictly a copy, no re-naming, no deletions -- so just invert.
- return upgradeShared0to1(from, to);
- }
-
- public static void upgrade0to1(final Context context, final AccountManager accountManager, final Account account,
- final String product, final String username, final String serverURL, final String profile) throws Exception {
-
- final String GLOBAL_SHARED_PREFS = "sync.prefs.global";
-
- final SharedPreferences globalPrefs = context.getSharedPreferences(GLOBAL_SHARED_PREFS, Utils.SHARED_PREFERENCES_MODE);
- final SharedPreferences accountPrefs = Utils.getSharedPreferences(context, product, username, serverURL, profile, 0);
- final SharedPreferences newPrefs = Utils.getSharedPreferences(context, product, username, serverURL, profile, 1);
-
- upgradeGlobals0to1(globalPrefs, newPrefs);
- upgradeAndroidAccount0to1(accountManager, account, newPrefs);
- upgradeShared0to1(accountPrefs, newPrefs);
- }
-
- public static void downgrade1to0(final Context context, final AccountManager accountManager, final Account account,
- final String product, final String username, final String serverURL, final String profile) throws Exception {
-
- final String GLOBAL_SHARED_PREFS = "sync.prefs.global";
-
- final SharedPreferences globalPrefs = context.getSharedPreferences(GLOBAL_SHARED_PREFS, Utils.SHARED_PREFERENCES_MODE);
- final SharedPreferences accountPrefs = Utils.getSharedPreferences(context, product, username, serverURL, profile, 0);
- final SharedPreferences oldPrefs = Utils.getSharedPreferences(context, product, username, serverURL, profile, 1);
-
- downgradeGlobals1to0(oldPrefs, globalPrefs);
- downgradeAndroidAccount1to0(oldPrefs, accountManager, account);
- downgradeShared1to0(oldPrefs, accountPrefs);
- }
-
- /**
- * Migrate, if necessary, existing prefs to a certain version.
- * <p>
- * Stores current prefs version in Android shared prefs with root
- * "sync.prefs.version", which corresponds to the file
- * "sync.prefs.version.xml".
- *
- * @param desiredVersion
- * version to finish it.
- * @param context
- * @param accountManager
- * @param account
- * @param product
- * @param username
- * @param serverURL
- * @param profile
- * @throws Exception
- */
- public static void ensurePrefsAreVersion(final long desiredVersion,
- final Context context, final AccountManager accountManager, final Account account,
- final String product, final String username, final String serverURL, final String profile) throws Exception {
- if (desiredVersion < 0 || desiredVersion > SyncConfiguration.CURRENT_PREFS_VERSION) {
- throw new IllegalArgumentException("Cannot migrate to unknown version " + desiredVersion + ".");
- }
-
- SharedPreferences versionPrefs = context.getSharedPreferences("sync.prefs.version", Utils.SHARED_PREFERENCES_MODE);
-
- // We default to 0 since clients getting this code for the first time will
- // not have "sync.prefs.version.xml" *at all*, and upgrading when all old
- // data is missing is expected to be safe.
- long currentVersion = versionPrefs.getLong(SyncConfiguration.PREF_PREFS_VERSION, 0);
- if (currentVersion == desiredVersion) {
- Logger.info(LOG_TAG, "Current version (" + currentVersion + ") is desired version; no need to migrate.");
- return;
- }
-
- if (currentVersion < 0 || currentVersion > SyncConfiguration.CURRENT_PREFS_VERSION) {
- throw new IllegalStateException("Cannot migrate from unknown version " + currentVersion + ".");
- }
-
- // Now we're down to either version 0 or version 1.
- if (currentVersion == 0 && desiredVersion == 1) {
- Logger.info(LOG_TAG, "Upgrading from version 0 to version 1.");
- upgrade0to1(context, accountManager, account, product, username, serverURL, profile);
- } else if (currentVersion == 1 && desiredVersion == 0) {
- Logger.info(LOG_TAG, "Upgrading from version 0 to version 1.");
- downgrade1to0(context, accountManager, account, product, username, serverURL, profile);
- } else {
- Logger.warn(LOG_TAG, "Don't know how to migrate from version " + currentVersion + " to " + desiredVersion + ".");
- }
-
- Logger.info(LOG_TAG, "Migrated from version " + currentVersion + " to version " + desiredVersion + ".");
- versionPrefs.edit().putLong(SyncConfiguration.PREF_PREFS_VERSION, desiredVersion).commit();
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/config/activities/SelectEnginesActivity.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.config.activities;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.ThreadPool;
-import org.mozilla.gecko.sync.setup.SyncAccounts;
-import org.mozilla.gecko.sync.syncadapter.SyncAdapter;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnDismissListener;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.widget.ListView;
-import android.widget.Toast;
-
-/**
- * Provides a user-facing interface for selecting engines to sync. This activity
- * can be launched from the Sync Settings preferences screen, and will save the
- * selected engines to the
- * <code>SyncConfiguration.PREF_USER_SELECTED_ENGINES_TO_SYNC</code> pref.
- *
- * On launch, it displays the engines stored in the saved pref if it exists, or
- * <code>SyncConfiguration.enabledEngineNames()</code> if it doesn't, defaulting
- * to <code>SyncConfiguration.validEngineNames()</code> if neither exists.
- *
- * During a sync, the
- * <code>SyncConfiguration.PREF_USER_SELECTED_ENGINES_TO_SYNC</code> pref will
- * be cleared after the engine changes are applied to meta/global.
- */
-
-public class SelectEnginesActivity extends Activity implements
- DialogInterface.OnClickListener, DialogInterface.OnMultiChoiceClickListener {
- public final static String LOG_TAG = "SelectEnginesAct";
-
- protected AccountManager mAccountManager;
- protected Context mContext;
-
- // Collections names corresponding to displayed (localized) engine options.
- final String[] _collectionsNames = new String[] {
- "bookmarks",
- "passwords",
- "history",
- "tabs"
- };
-
- // Engine names localized for display in Sync Settings.
- protected String[] _options;
- // Selection state of engines corresponding to _options array.
- final boolean[] _selections = new boolean[_collectionsNames.length];
- protected Account account;
- protected SharedPreferences accountPrefs;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mContext = getApplicationContext();
- mAccountManager = AccountManager.get(mContext);
- _options = new String[] {
- getString(R.string.sync_configure_engines_title_bookmarks),
- getString(R.string.sync_configure_engines_title_passwords),
- getString(R.string.sync_configure_engines_title_history),
- getString(R.string.sync_configure_engines_title_tabs) };
-
- // Fetch account prefs for configuring engines.
- ThreadPool.run(new Runnable() {
- @Override
- public void run() {
- Account[] accounts = SyncAccounts.syncAccounts(mContext);
- if (accounts.length == 0) {
- Logger.error(LOG_TAG, "Failed to get account!");
- finish();
- return;
- } else {
- // Only supports one account per type.
- account = accounts[0];
- try {
- if (accountPrefs == null) {
- accountPrefs = SyncAccounts.blockingPrefsFromDefaultProfileV0(mContext, mAccountManager, account);
- }
- } catch (Exception e) {
- Logger.error(LOG_TAG, "Failed to get sync account info or shared preferences.", e);
- finish();
- }
- setSelectionsInArray(getEnginesToSelect(accountPrefs), _selections);
- }
- }
- });
- }
-
- @Override
- public void onResume() {
- super.onResume();
- if (accountPrefs != null) {
- setSelectionsInArray(getEnginesToSelect(accountPrefs), _selections);
- }
- AlertDialog dialog = new AlertDialog.Builder(this)
- .setTitle(R.string.sync_configure_engines_sync_my_title)
- .setMultiChoiceItems(_options, _selections, this)
- .setIcon(R.drawable.icon).setPositiveButton(android.R.string.ok, this)
- .setNegativeButton(android.R.string.cancel, this).create();
-
- dialog.setOnDismissListener(new OnDismissListener() {
- @Override
- public void onDismiss(DialogInterface dialog) {
- finish();
- }
- });
-
- dialog.show();
- }
-
- private static Set<String> getEnginesFromPrefs(SharedPreferences syncPrefs) {
- Set<String> engines = SyncConfiguration.getEnabledEngineNames(syncPrefs);
- if (engines == null) {
- engines = SyncConfiguration.validEngineNames();
- }
- return engines;
- }
-
- /**
- * Fetches the engine names that should be displayed as selected for syncing.
- * Check first for selected engines set by this activity, then the enabled
- * engines, and finally default to the set of valid engine names for Android
- * Sync if neither exists.
- *
- * @param syncPrefs
- * <code>SharedPreferences</code> of Account being modified.
- * @return Set<String> of engine names to display as selected. Should never be
- * null.
- */
- public static Set<String> getEnginesToSelect(SharedPreferences syncPrefs) {
- Set<String> engines = getEnginesFromPrefs(syncPrefs);
- Map<String, Boolean> engineSelections = SyncConfiguration.getUserSelectedEngines(syncPrefs);
- if (engineSelections != null) {
- for (Entry<String, Boolean> pair : engineSelections.entrySet()) {
- if (pair.getValue()) {
- engines.add(pair.getKey());
- } else {
- engines.remove(pair.getKey());
- }
- }
- }
- return engines;
- }
-
- public void setSelectionsInArray(Set<String> selected, boolean[] array) {
- for (int i = 0; i < _collectionsNames.length; i++) {
- array[i] = selected.contains(_collectionsNames[i]);
- }
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- Logger.debug(LOG_TAG, "Saving selected engines.");
- saveSelections();
- setResult(RESULT_OK);
- Toast.makeText(this, R.string.sync_notification_savedprefs, Toast.LENGTH_SHORT).show();
- } else {
- setResult(RESULT_CANCELED);
- }
- finish();
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which, boolean isChecked) {
- // Display multi-selection clicks in UI.
- _selections[which] = isChecked;
- ListView selectionsList = ((AlertDialog) dialog).getListView();
- selectionsList.setItemChecked(which, isChecked);
- }
-
- /**
- * Persists engine selection state to SharedPreferences if it has changed.
- *
- * @return true if changed, false otherwise.
- */
- private void saveSelections() {
- boolean[] origSelections = new boolean[_options.length];
- setSelectionsInArray(getEnginesFromPrefs(accountPrefs), origSelections);
-
- Map<String, Boolean> engineSelections = new HashMap<String, Boolean>();
- for (int i = 0; i < _selections.length; i++) {
- if (_selections[i] != origSelections[i]) {
- engineSelections.put(_collectionsNames[i], _selections[i]);
- }
- }
-
- // No GlobalSession.config, so store directly to prefs.
- SyncConfiguration.storeSelectedEnginesToPrefs(accountPrefs, engineSelections);
-
- // Request immediate sync.
- SyncAdapter.requestImmediateSync(account, null);
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/BigIntegerHelper.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake;
-
-import java.math.BigInteger;
-
-public class BigIntegerHelper {
-
- public static byte[] BigIntegerToByteArrayWithoutSign(BigInteger value) {
- byte[] bytes = value.toByteArray();
- if (bytes[0] == (byte) 0) {
- bytes = copyArray(bytes, 1, bytes.length - 1);
- }
- return bytes;
- }
-
- private static byte[] copyArray(byte[] original, int start, int length) {
- byte[] copy = new byte[length];
- System.arraycopy(original, start, copy, 0,
- Math.min(original.length - start, length));
- return copy;
- }
-
- /**
- * Convert an array of bytes to a non-negative big integer.
- */
- public static BigInteger ByteArrayToBigIntegerWithoutSign(byte[] array) {
- return new BigInteger(1, array);
- }
-
- /**
- * Convert a big integer into hex string. If the length is not even, add an
- * '0' character in the beginning to make it even.
- */
- public static String toEvenLengthHex(BigInteger value) {
- String result = value.toString(16);
- if (result.length() % 2 != 0) {
- result = "0" + result;
- }
- return result;
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/Gx3OrGx4IsZeroOrOneException.java
+++ /dev/null
@@ -1,9 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake;
-
-public class Gx3OrGx4IsZeroOrOneException extends Exception {
- private static final long serialVersionUID = 7347530447460039679L;
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/IncorrectZkpException.java
+++ /dev/null
@@ -1,14 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake;
-
-public class IncorrectZkpException extends Exception {
-
- /**
- * Exception thrown when Zero Knowledge Proof does not compute correctly.
- **/
- private static final long serialVersionUID = -3289260904620418313L;
-
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/JPakeClient.java
+++ /dev/null
@@ -1,433 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake;
-
-import java.io.UnsupportedEncodingException;
-import java.math.BigInteger;
-import java.util.LinkedList;
-import java.util.Queue;
-
-import org.json.simple.JSONObject;
-import org.mozilla.apache.commons.codec.binary.Base64;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.ThreadPool;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.CryptoInfo;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.crypto.NoKeyBundleException;
-import org.mozilla.gecko.sync.jpake.stage.CompleteStage;
-import org.mozilla.gecko.sync.jpake.stage.ComputeFinalStage;
-import org.mozilla.gecko.sync.jpake.stage.ComputeKeyVerificationStage;
-import org.mozilla.gecko.sync.jpake.stage.ComputeStepOneStage;
-import org.mozilla.gecko.sync.jpake.stage.ComputeStepTwoStage;
-import org.mozilla.gecko.sync.jpake.stage.DecryptDataStage;
-import org.mozilla.gecko.sync.jpake.stage.DeleteChannel;
-import org.mozilla.gecko.sync.jpake.stage.GetChannelStage;
-import org.mozilla.gecko.sync.jpake.stage.GetRequestStage;
-import org.mozilla.gecko.sync.jpake.stage.JPakeStage;
-import org.mozilla.gecko.sync.jpake.stage.PutRequestStage;
-import org.mozilla.gecko.sync.jpake.stage.VerifyPairingStage;
-import org.mozilla.gecko.sync.setup.Constants;
-import org.mozilla.gecko.sync.setup.activities.SetupSyncActivity;
-
-import ch.boye.httpclientandroidlib.entity.StringEntity;
-
-public class JPakeClient {
-
- private static final String LOG_TAG = "JPakeClient";
-
- // J-PAKE constants.
- public static final int REQUEST_TIMEOUT = 60 * 1000; // 1 min
- public static final int KEYEXCHANGE_VERSION = 3;
- public static final String JPAKE_VERIFY_VALUE = "0123456789ABCDEF";
-
- private static final String JPAKE_SIGNERID_SENDER = "sender";
- private static final String JPAKE_SIGNERID_RECEIVER = "receiver";
- private static final int JPAKE_LENGTH_SECRET = 8;
- private static final int JPAKE_LENGTH_CLIENTID = 256;
-
- private static final int MAX_TRIES = 10;
- private static final int MAX_TRIES_FIRST_MSG = 300;
- private static final int MAX_TRIES_LAST_MSG = 300;
-
- // J-PAKE session values.
- public String clientId;
- public String secret;
-
- public String myEtag;
- public String mySignerId;
- public String theirEtag;
- public String theirSignerId;
- public String jpakeServer;
-
- // J-PAKE state.
- public boolean paired;
- public boolean finished;
-
- // J-PAKE values.
- public final int jpakePollInterval;
- public int jpakeMaxTries;
- public String channel;
- public volatile String channelUrl;
-
- // J-PAKE session data.
- public KeyBundle myKeyBundle;
- public JSONObject jCreds;
-
- public ExtendedJSONObject jOutgoing;
- public ExtendedJSONObject jIncoming;
-
- public JPakeParty jParty;
- public final JPakeNumGenerator numGen;
-
- public int pollTries;
-
- // UI controller.
- private final SetupSyncActivity controllerActivity;
- private Queue<JPakeStage> stages;
-
- public JPakeClient(SetupSyncActivity activity) {
- controllerActivity = activity;
- jpakeServer = "https://setup.services.mozilla.com/";
- jpakePollInterval = 1 * 1000; // 1 second
- jpakeMaxTries = MAX_TRIES;
-
- if (!jpakeServer.endsWith("/")) {
- jpakeServer += "/";
- }
-
- setClientId();
- numGen = new JPakeNumGeneratorRandom();
- }
-
- /**
- * Set up Sender sequence of stages for J-PAKE. (sender of credentials)
- *
- */
-
- private void prepareSenderStages() {
- Queue<JPakeStage> jStages = new LinkedList<JPakeStage>();
- jStages.add(new ComputeStepOneStage());
- jStages.add(new GetRequestStage());
- jStages.add(new PutRequestStage());
- jStages.add(new ComputeStepTwoStage());
- jStages.add(new GetRequestStage());
- jStages.add(new PutRequestStage());
- jStages.add(new ComputeFinalStage());
- jStages.add(new GetRequestStage());
- jStages.add(new VerifyPairingStage()); // Calls onPaired if verified.
-
- stages = jStages;
- }
-
- /**
- * Set up Receiver sequence of stages for J-PAKE. (receiver of credentials)
- *
- */
- private void prepareReceiverStages() {
- Queue<JPakeStage> jStages = new LinkedList<JPakeStage>();
- jStages.add(new GetChannelStage());
- jStages.add(new ComputeStepOneStage());
- jStages.add(new PutRequestStage());
- jStages.add(new GetRequestStage());
- jStages.add(new JPakeStage() {
- @Override
- public void execute(JPakeClient jpakeClient) {
-
- // Notify controller that pairing has started.
- jpakeClient.onPairingStart();
-
- // Switch back to smaller time-out.
- jpakeClient.jpakeMaxTries = JPakeClient.MAX_TRIES;
- jpakeClient.runNextStage();
- }
- });
- jStages.add(new ComputeStepTwoStage());
- jStages.add(new PutRequestStage());
- jStages.add(new GetRequestStage());
- jStages.add(new ComputeFinalStage());
- jStages.add(new ComputeKeyVerificationStage());
- jStages.add(new PutRequestStage());
- jStages.add(new JPakeStage() {
-
- @Override
- public void execute(JPakeClient jpakeClient) {
- jpakeMaxTries = MAX_TRIES_LAST_MSG;
- jpakeClient.runNextStage();
- }
-
- });
- jStages.add(new GetRequestStage());
- jStages.add(new DecryptDataStage());
- jStages.add(new CompleteStage());
-
- stages = jStages;
- }
-
- /**
- *
- * Pairing using PIN provided on other device. Functionality available only
- * when a Sync account has already been set up.
- *
- * @param pin
- * 12-character string containing PIN entered by the user.
- */
- public void pairWithPin(String pin) {
- mySignerId = JPAKE_SIGNERID_SENDER;
- theirSignerId = JPAKE_SIGNERID_RECEIVER;
- jParty = new JPakeParty(mySignerId);
-
- // Extract secret and server channel.
- secret = pin.substring(0, JPAKE_LENGTH_SECRET);
- channel = pin.substring(JPAKE_LENGTH_SECRET);
- channelUrl = jpakeServer + channel;
-
- prepareSenderStages();
- runNextStage();
- }
-
- /**
- *
- * Initiate pairing and receive data, without having received a PIN. The PIN
- * will be generated and passed on to the controller to be displayed to the
- * user.
- *
- * Starts J-PAKE protocol.
- */
- public void receiveNoPin() {
- mySignerId = JPAKE_SIGNERID_RECEIVER;
- theirSignerId = JPAKE_SIGNERID_SENDER;
- jParty = new JPakeParty(mySignerId);
-
- // TODO: fetch from prefs
- jpakeMaxTries = MAX_TRIES_FIRST_MSG;
-
- createSecret();
- prepareReceiverStages();
- runNextStage();
- }
-
- /**
- * Run next stage of J-PAKE.
- */
- public void runNextStage() {
- if (finished || stages.size() == 0) {
- Logger.debug(LOG_TAG, "All stages complete.");
- return;
- }
- JPakeStage currentStage = null;
- try{
- currentStage = stages.remove();
- Logger.debug(LOG_TAG, "starting stage " + currentStage.toString());
- currentStage.execute(this);
- } catch (Exception e) {
- Logger.error(LOG_TAG, "Exception in stage " + currentStage, e);
- abort("Stage exception.");
- }
- }
-
- /**
- * Abort J-PAKE. This can propagate an error from the stages, or result from
- * UI abort (onPause, user abort)
- *
- * @param reason
- * Reason for abort.
- */
- public void abort(String reason) {
- finished = true;
- // We do not need to clean up the channel in the following cases:
- if (Constants.JPAKE_ERROR_CHANNEL.equals(reason) ||
- Constants.JPAKE_ERROR_NETWORK.equals(reason) ||
- Constants.JPAKE_ERROR_NODATA.equals(reason) ||
- channelUrl == null) {
- // We may leak a channel if the activity aborts sync while requesting the channel.
- // The server, however, will delete the channel anyways after a certain time has passed.
- displayAbort(reason);
- } else {
- // Delete channel, then call controller's displayAbort in callback.
- new DeleteChannel().execute(this, reason);
- }
- }
-
- public void displayAbort(String reason) {
- controllerActivity.displayAbort(reason);
- }
-
- /* Static helper methods used by stages. */
-
- /**
- * Run on a different thread from the thread pool.
- *
- * @param run
- * Runnable to run on separate thread.
- */
- public static void runOnThread(Runnable run) {
- ThreadPool.run(run);
- }
-
- /**
- *
- * @param secretString
- * String to convert to BigInteger
- * @return BigInteger representation of secretString
- *
- * @throws UnsupportedEncodingException
- */
- public static BigInteger secretAsBigInteger(String secretString) throws UnsupportedEncodingException {
- return new BigInteger(secretString.getBytes("UTF-8"));
- }
-
- /**
- * Helper method for doing actual encryption.
- *
- * Input: String of JSONObject KeyBundle with keys for encryption
- *
- * Output: ExtendedJSONObject with IV, ciphertext, hmac (if sender)
- *
- * @throws CryptoException
- * @throws UnsupportedEncodingException
- */
- public static ExtendedJSONObject encryptPayload(String data, KeyBundle keyBundle, boolean makeHmac)
- throws UnsupportedEncodingException, CryptoException {
- if (keyBundle == null) {
- throw new NoKeyBundleException();
- }
-
- byte[] cleartextBytes = data.getBytes("UTF-8");
- CryptoInfo encrypted = CryptoInfo.encrypt(cleartextBytes, keyBundle);
-
- ExtendedJSONObject payload = new ExtendedJSONObject();
-
- String message64 = new String(Base64.encodeBase64(encrypted.getMessage()));
- String iv64 = new String(Base64.encodeBase64(encrypted.getIV()));
-
- payload.put(Constants.JSON_KEY_CIPHERTEXT, message64);
- payload.put(Constants.JSON_KEY_IV, iv64);
- if (makeHmac) {
- String hmacHex = Utils.byte2Hex(encrypted.getHMAC());
- payload.put(Constants.JSON_KEY_HMAC, hmacHex);
- }
- return payload;
- }
-
- /*
- * Helper for turning a JSON object into a payload.
- *
- * @param body JSONObject body to be converted to StringEntity.
- * @return StringEntity representation of JSONObject.
- *
- * @throws UnsupportedEncodingException
- */
- public static StringEntity jsonEntity(JSONObject body)
- throws UnsupportedEncodingException {
- StringEntity entity = new StringEntity(body.toJSONString(), "UTF-8");
- entity.setContentType("application/json");
- return entity;
- }
-
- /*
- * Controller methods.
- */
- public void makeAndDisplayPin(String channel) {
- controllerActivity.displayPin(secret + channel);
- }
-
- public void onPairingStart() {
- Logger.debug(LOG_TAG, "Pairing started.");
- controllerActivity.onPairingStart();
- }
-
- public void onPaired() {
- Logger.debug(LOG_TAG, "Pairing completed. Starting credential exchange.");
- controllerActivity.onPaired();
- }
-
- public void complete(JSONObject credentials) {
- controllerActivity.onComplete(credentials);
- }
-
- /*
- * Called from controller, with Sync credentials to be encrypted and sent.
- */
- public void sendAndComplete(JSONObject jObj)
- throws JPakeNoActivePairingException {
- if (!paired || finished) {
- Logger.error(LOG_TAG, "Can't send data, no active pairing!");
- throw new JPakeNoActivePairingException();
- }
- stages.clear();
- stages.add(new PutRequestStage());
- stages.add(new CompleteStage());
-
- // Encrypt data to send and set as jOutgoing.
- String outData = jObj.toJSONString();
- encryptData(myKeyBundle, outData);
-
- // Start stages for sending credentials.
- runNextStage();
- }
-
- /* Setup helper functions */
-
- /*
- * Generates and sets a clientId for communications with JPAKE setup server.
- */
- private void setClientId() {
- byte[] rBytes = Utils.generateRandomBytes(JPAKE_LENGTH_CLIENTID / 2);
- StringBuilder id = new StringBuilder();
-
- for (byte b : rBytes) {
- String hexString = Integer.toHexString(b);
- if (hexString.length() == 1) {
- hexString = "0" + hexString;
- }
- int len = hexString.length();
- id.append(hexString.substring(len - 2, len));
- }
- clientId = id.toString();
- }
-
- /*
- * Generates and sets a JPAKE PIN to be displayed to user.
- */
- private void createSecret() {
- // 0-9a-z without 1,l,o,0
- String key = "23456789abcdefghijkmnpqrstuvwxyz";
- int keylen = key.length();
-
- byte[] rBytes = Utils.generateRandomBytes(JPAKE_LENGTH_SECRET);
- StringBuilder secret = new StringBuilder();
- for (byte b : rBytes) {
- secret.append(key.charAt(Math.abs(b) * keylen / 256));
- }
- this.secret = secret.toString();
- }
-
- /*
- *
- * Encrypt payload and package into jOutgoing for sending with a PUT request.
- *
- * @param keyBundle Encryption keys derived during J-PAKE.
- *
- * @param payload Credentials data to be encrypted.
- */
- private void encryptData(KeyBundle keyBundle, String payload) {
- Logger.debug(LOG_TAG, "Encrypting data.");
- ExtendedJSONObject jPayload = null;
- try {
- jPayload = encryptPayload(payload, keyBundle, true);
- } catch (UnsupportedEncodingException | CryptoException e) {
- Logger.error(LOG_TAG, "Failed to encrypt data.", e);
- abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- }
- jOutgoing = new ExtendedJSONObject();
- jOutgoing.put(Constants.JSON_KEY_TYPE, mySignerId + "3");
- jOutgoing.put(Constants.JSON_KEY_VERSION, KEYEXCHANGE_VERSION);
- jOutgoing.put(Constants.JSON_KEY_PAYLOAD, jPayload.object);
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/JPakeCrypto.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake;
-
-import java.io.UnsupportedEncodingException;
-import java.math.BigInteger;
-import java.security.GeneralSecurityException;
-import java.security.InvalidKeyException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.crypto.HKDF;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-
-public class JPakeCrypto {
- private static final String LOG_TAG = "JPakeCrypto";
-
- /*
- * Primes P and Q, and generator G - from original Mozilla J-PAKE
- * implementation.
- */
- public static final BigInteger P = new BigInteger(
- "90066455B5CFC38F9CAA4A48B4281F292C260FEEF01FD61037E56258A7795A1C" +
- "7AD46076982CE6BB956936C6AB4DCFE05E6784586940CA544B9B2140E1EB523F" +
- "009D20A7E7880E4E5BFA690F1B9004A27811CD9904AF70420EEFD6EA11EF7DA1" +
- "29F58835FF56B89FAA637BC9AC2EFAAB903402229F491D8D3485261CD068699B" +
- "6BA58A1DDBBEF6DB51E8FE34E8A78E542D7BA351C21EA8D8F1D29F5D5D159394" +
- "87E27F4416B0CA632C59EFD1B1EB66511A5A0FBF615B766C5862D0BD8A3FE7A0" +
- "E0DA0FB2FE1FCB19E8F9996A8EA0FCCDE538175238FC8B0EE6F29AF7F642773E" +
- "BE8CD5402415A01451A840476B2FCEB0E388D30D4B376C37FE401C2A2C2F941D" +
- "AD179C540C1C8CE030D460C4D983BE9AB0B20F69144C1AE13F9383EA1C08504F" +
- "B0BF321503EFE43488310DD8DC77EC5B8349B8BFE97C2C560EA878DE87C11E3D" +
- "597F1FEA742D73EEC7F37BE43949EF1A0D15C3F3E3FC0A8335617055AC91328E" +
- "C22B50FC15B941D3D1624CD88BC25F3E941FDDC6200689581BFEC416B4B2CB73",
- 16);
-
- public static final BigInteger Q = new BigInteger(
- "CFA0478A54717B08CE64805B76E5B14249A77A4838469DF7F7DC987EFCCFB11D",
- 16);
-
- public static final BigInteger G = new BigInteger(
- "5E5CBA992E0A680D885EB903AEA78E4A45A469103D448EDE3B7ACCC54D521E37" +
- "F84A4BDD5B06B0970CC2D2BBB715F7B82846F9A0C393914C792E6A923E2117AB" +
- "805276A975AADB5261D91673EA9AAFFEECBFA6183DFCB5D3B7332AA19275AFA1" +
- "F8EC0B60FB6F66CC23AE4870791D5982AAD1AA9485FD8F4A60126FEB2CF05DB8" +
- "A7F0F09B3397F3937F2E90B9E5B9C9B6EFEF642BC48351C46FB171B9BFA9EF17" +
- "A961CE96C7E7A7CC3D3D03DFAD1078BA21DA425198F07D2481622BCE45969D9C" +
- "4D6063D72AB7A0F08B2F49A7CC6AF335E08C4720E31476B67299E231F8BD90B3" +
- "9AC3AE3BE0C6B6CACEF8289A2E2873D58E51E029CAFBD55E6841489AB66B5B4B" +
- "9BA6E2F784660896AFF387D92844CCB8B69475496DE19DA2E58259B090489AC8" +
- "E62363CDF82CFD8EF2A427ABCD65750B506F56DDE3B988567A88126B914D7828" +
- "E2B63A6D7ED0747EC59E0E0A23CE7D8A74C1D2C2A7AFB6A29799620F00E11C33" +
- "787F7DED3B30E1A22D09F1FBDA1ABBBFBF25CAE05A13F812E34563F99410E73B",
- 16);
-
- /**
- *
- * Round 1 of J-PAKE protocol.
- * Generate x1, x2, and ZKP for other party.
- */
- public static void round1(JPakeParty jp, JPakeNumGenerator gen) throws NoSuchAlgorithmException, UnsupportedEncodingException {
- // Randomly select x1 from [0,q), x2 from [1,q).
- BigInteger x1 = gen.generateFromRange(Q); // [0, q)
- BigInteger x2 = jp.x2 = BigInteger.ONE.add(gen.generateFromRange(Q
- .subtract(BigInteger.ONE))); // [1, q)
-
- BigInteger gx1 = G.modPow(x1, P);
- BigInteger gx2 = G.modPow(x2, P);
-
- jp.gx1 = gx1;
- jp.gx2 = gx2;
-
- // Generate and store zero knowledge proofs.
- jp.zkp1 = createZkp(G, x1, gx1, jp.signerId, gen);
- jp.zkp2 = createZkp(G, x2, gx2, jp.signerId, gen);
- }
-
- /**
- * Round 2 of J-PAKE protocol.
- * Generate A and ZKP for A.
- * Verify ZKP from other party. Does not check for replay ZKP.
- */
- public static void round2(BigInteger secretValue, JPakeParty jp, JPakeNumGenerator gen)
- throws IncorrectZkpException, NoSuchAlgorithmException,
- Gx3OrGx4IsZeroOrOneException, UnsupportedEncodingException {
-
- Logger.debug(LOG_TAG, "round2 started.");
-
- // checkZkp does some additional checks, but we can throw a more informative exception here.
- if (BigInteger.ZERO.compareTo(jp.gx3) == 0 || BigInteger.ONE.compareTo(jp.gx3) == 0 ||
- BigInteger.ZERO.compareTo(jp.gx4) == 0 || BigInteger.ONE.compareTo(jp.gx4) == 0) {
- throw new Gx3OrGx4IsZeroOrOneException();
- }
-
- // Check ZKP.
- checkZkp(G, jp.gx3, jp.zkp3);
- checkZkp(G, jp.gx4, jp.zkp4);
-
- // Compute a = g^[(x1+x3+x4)*(x2*secret)].
- BigInteger y1 = jp.gx3.multiply(jp.gx4).mod(P).multiply(jp.gx1).mod(P);
- BigInteger y2 = jp.x2.multiply(secretValue).mod(P);
-
- BigInteger a = y1.modPow(y2, P);
- jp.thisZkpA = createZkp(y1, y2, a, jp.signerId, gen);
- jp.thisA = a;
-
- Logger.debug(LOG_TAG, "round2 finished.");
- }
-
- /**
- * Final round of J-PAKE protocol.
- */
- public static KeyBundle finalRound(BigInteger secretValue, JPakeParty jp)
- throws IncorrectZkpException, NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
- Logger.debug(LOG_TAG, "Final round started.");
- BigInteger gb = jp.gx1.multiply(jp.gx2).mod(P).multiply(jp.gx3)
- .mod(P);
- checkZkp(gb, jp.otherA, jp.otherZkpA);
-
- // Calculate shared key g^(x1+x3)*x2*x4*secret, which is equivalent to
- // (B/g^(x2*x4*s))^x2 = (B*(g^x4)^x2^s^-1)^2.
- BigInteger k = jp.gx4.modPow(jp.x2.multiply(secretValue).negate().mod(Q), P).multiply(jp.otherA)
- .modPow(jp.x2, P);
-
- byte[] enc = new byte[32];
- byte[] hmac = new byte[32];
- generateKeyAndHmac(k, enc, hmac);
-
- Logger.debug(LOG_TAG, "Final round finished; returning key.");
- return new KeyBundle(enc, hmac);
- }
-
- // TODO Replace this function with the one in the crypto library
- private static byte[] HMACSHA256(byte[] data, byte[] key) {
- byte[] result = null;
- try {
- Mac hmacSha256;
- hmacSha256 = Mac.getInstance("HmacSHA256");
- SecretKeySpec secret_key = new SecretKeySpec(key, "HmacSHA256");
- hmacSha256.init(secret_key);
- result = hmacSha256.doFinal(data);
- } catch (GeneralSecurityException e) {
- Logger.error(LOG_TAG, "Got exception calculating HMAC.", e);
- }
- return result;
- }
-
- /* Helper Methods */
-
- /*
- * Generate the ZKP b = r - x*h, and g^r, where h = hash(g, g^r, g^x, id). (We
- * pass in gx to save on an exponentiation of g^x)
- */
- private static Zkp createZkp(BigInteger g, BigInteger x, BigInteger gx,
- String id, JPakeNumGenerator gen) throws NoSuchAlgorithmException, UnsupportedEncodingException {
- // Generate random r for exponent.
- BigInteger r = gen.generateFromRange(Q);
-
- // Calculate g^r for ZKP.
- BigInteger gr = g.modPow(r, P);
-
- // Calculate the ZKP b value = (r-x*h) % q.
- BigInteger h = computeBHash(g, gr, gx, id);
- Logger.debug(LOG_TAG, "myhash: " + h.toString(16));
-
- // ZKP value = b = r-x*h
- BigInteger b = r.subtract(x.multiply(h)).mod(Q);
-
- return new Zkp(gr, b, id);
- }
-
- /*
- * Verify ZKP.
- */
- private static void checkZkp(BigInteger g, BigInteger gx, Zkp zkp)
- throws IncorrectZkpException, NoSuchAlgorithmException, UnsupportedEncodingException {
-
- BigInteger h = computeBHash(g, zkp.gr, gx, zkp.id);
-
- // Check parameters of zkp, and compare to computed hash. These shouldn't
- // fail.
- if (gx.compareTo(BigInteger.ONE) < 1) { // g^x > 1.
- Logger.error(LOG_TAG, "g^x > 1 fails.");
- throw new IncorrectZkpException();
- }
- if (gx.compareTo(P.subtract(BigInteger.ONE)) > -1) { // g^x < p-1
- Logger.error(LOG_TAG, "g^x < p-1 fails.");
- throw new IncorrectZkpException();
- }
- if (gx.modPow(Q, P).compareTo(BigInteger.ONE) != 0) {
- Logger.error(LOG_TAG, "g^x^q % p = 1 fails.");
- throw new IncorrectZkpException();
- }
- if (zkp.gr.compareTo(g.modPow(zkp.b, P).multiply(gx.modPow(h, P)).mod(P)) != 0) {
- // b = r-h*x ==> g^r = g^b*g^x^(h)
- Logger.debug(LOG_TAG, "gb*g(xh) = " + g.modPow(zkp.b, P).multiply(gx.modPow(h, P)).mod(P).toString(16));
- Logger.debug(LOG_TAG, "gr = " + zkp.gr.toString(16));
- Logger.debug(LOG_TAG, "b = " + zkp.b.toString(16));
- Logger.debug(LOG_TAG, "g^b = " + g.modPow(zkp.b, P).toString(16));
- Logger.debug(LOG_TAG, "g^(xh) = " + gx.modPow(h, P).toString(16));
- Logger.debug(LOG_TAG, "gx = " + gx.toString(16));
- Logger.debug(LOG_TAG, "h = " + h.toString(16));
- Logger.error(LOG_TAG, "zkp calculation incorrect.");
- throw new IncorrectZkpException();
- }
- Logger.debug(LOG_TAG, "*** ZKP SUCCESS ***");
- }
-
- /*
- * Use SHA-256 to compute a BigInteger hash of g, gr, gx values with
- * mySignerId to prevent replay. Does not make a twos-complement BigInteger
- * form hash.
- */
- private static BigInteger computeBHash(BigInteger g, BigInteger gr, BigInteger gx,
- String id) throws NoSuchAlgorithmException, UnsupportedEncodingException {
- MessageDigest sha = MessageDigest.getInstance("SHA-256");
- sha.reset();
-
- /*
- * Note: you should ensure the items in H(...) have clear boundaries. It
- * is simple if the other party knows sizes of g, gr, gx and signerID and
- * hence the boundary is unambiguous. If not, you'd better prepend each
- * item with its byte length, but I've omitted that here.
- */
-
- hashByteArrayWithLength(sha, BigIntegerHelper.BigIntegerToByteArrayWithoutSign(g));
- hashByteArrayWithLength(sha, BigIntegerHelper.BigIntegerToByteArrayWithoutSign(gr));
- hashByteArrayWithLength(sha, BigIntegerHelper.BigIntegerToByteArrayWithoutSign(gx));
- hashByteArrayWithLength(sha, id.getBytes("UTF-8"));
-
- byte[] hash = sha.digest();
-
- return BigIntegerHelper.ByteArrayToBigIntegerWithoutSign(hash);
- }
-
- /*
- * Update a hash with a byte array's length and the byte array.
- */
- private static void hashByteArrayWithLength(MessageDigest sha, byte[] data) {
- int length = data.length;
- byte[] b = new byte[] { (byte) (length >>> 8), (byte) (length & 0xff) };
- sha.update(b);
- sha.update(data);
- }
-
- /*
- * Helper function to generate encryption key and HMAC from a byte array.
- */
- public static void generateKeyAndHmac(BigInteger k, byte[] encOut, byte[] hmacOut) throws NoSuchAlgorithmException, InvalidKeyException {
- // Generate HMAC and Encryption keys from synckey.
- byte[] zerokey = new byte[32];
- byte[] prk = HMACSHA256(BigIntegerHelper.BigIntegerToByteArrayWithoutSign(k), zerokey);
-
- byte[] okm = HKDF.hkdfExpand(prk, HKDF.HMAC_INPUT, 32 * 2);
- System.arraycopy(okm, 0, encOut, 0, 32);
- System.arraycopy(okm, 32, hmacOut, 0, 32);
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/JPakeJson.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake;
-
-import java.math.BigInteger;
-
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.setup.Constants;
-
-public class JPakeJson {
- /*
- * Helper function to generate a JSON-encoded ZKP.
- */
- public static ExtendedJSONObject makeJZkp(BigInteger gr, BigInteger b, String id) {
- ExtendedJSONObject result = new ExtendedJSONObject();
- result.put(Constants.ZKP_KEY_GR, BigIntegerHelper.toEvenLengthHex(gr));
- result.put(Constants.ZKP_KEY_B, BigIntegerHelper.toEvenLengthHex(b));
- result.put(Constants.ZKP_KEY_ID, id);
- return result;
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/JPakeNoActivePairingException.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake;
-
-import org.mozilla.gecko.sync.SyncException;
-
-public class JPakeNoActivePairingException extends SyncException {
- private static final long serialVersionUID = 715366241252256473L;
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/JPakeNumGenerator.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake;
-
-import java.math.BigInteger;
-
-public interface JPakeNumGenerator {
- public BigInteger generateFromRange(BigInteger r);
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/JPakeNumGeneratorRandom.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake;
-
-import java.math.BigInteger;
-
-import org.mozilla.gecko.sync.Utils;
-
-/**
- * Helper Function to generate a uniformly random value in [0, r).
- */
-public class JPakeNumGeneratorRandom implements JPakeNumGenerator {
-
- @Override
- public BigInteger generateFromRange(BigInteger r) {
- return Utils.generateBigIntegerLessThan(r);
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/JPakeParty.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake;
-
-import java.math.BigInteger;
-
-public class JPakeParty {
-
- // Generated values for key exchange.
- public String signerId;
- public BigInteger gx1;
- public Zkp zkp1;
-
- public BigInteger x2;
- public BigInteger gx2;
- public Zkp zkp2;
-
- public BigInteger thisA;
- public Zkp thisZkpA;
-
- // Received values during key exchange.
- public BigInteger gx3;
- public Zkp zkp3;
-
- public BigInteger gx4;
- public Zkp zkp4;
-
- public BigInteger otherA;
- public Zkp otherZkpA;
-
-
- public JPakeParty(String mySignerId) {
- this.signerId = mySignerId;
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/Zkp.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake;
-
-import java.math.BigInteger;
-
-public class Zkp {
- public BigInteger gr;
- public BigInteger b;
- public String id;
-
- public Zkp(BigInteger gr, BigInteger b, String id) {
- this.gr = gr;
- this.b = b;
- this.id = id;
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/stage/CompleteStage.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake.stage;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.jpake.JPakeClient;
-
-public class CompleteStage extends JPakeStage {
-
- @Override
- public void execute(JPakeClient jClient) {
- Logger.debug(LOG_TAG, "Exchange complete.");
- jClient.finished = true;
- jClient.complete(jClient.jCreds);
- jClient.runNextStage();
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/stage/ComputeFinalStage.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake.stage;
-
-import java.io.UnsupportedEncodingException;
-import java.math.BigInteger;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.jpake.IncorrectZkpException;
-import org.mozilla.gecko.sync.jpake.JPakeClient;
-import org.mozilla.gecko.sync.jpake.JPakeCrypto;
-import org.mozilla.gecko.sync.jpake.Zkp;
-import org.mozilla.gecko.sync.setup.Constants;
-
-public class ComputeFinalStage extends JPakeStage {
-
- @Override
- public void execute(JPakeClient jClient) {
- Logger.debug(LOG_TAG, "Computing final round.");
-
- // Check incoming message type.
- if (!jClient.jIncoming.get(Constants.JSON_KEY_TYPE).equals(jClient.theirSignerId + "2")) {
- Logger.error(LOG_TAG, "Invalid round 2 message: " + jClient.jIncoming.toJSONString());
- jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
-
- // Check incoming message fields.
- ExtendedJSONObject iPayload;
- ExtendedJSONObject zkpPayload;
- try {
- iPayload = jClient.jIncoming.getObject(Constants.JSON_KEY_PAYLOAD);
- if (iPayload == null
- || iPayload.getObject(Constants.ZKP_KEY_ZKP_A) == null) {
- Logger.error(LOG_TAG,
- "Invalid round 2 message: " + jClient.jIncoming.toJSONString());
- jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
- zkpPayload = iPayload.getObject(Constants.ZKP_KEY_ZKP_A);
- } catch (NonObjectJSONException e) {
- Logger.error(LOG_TAG, "JSON object Exception.", e);
- jClient.abort(Constants.JPAKE_ERROR_INVALID);
- return;
- }
-
- if (!jClient.theirSignerId.equals(zkpPayload.get(Constants.ZKP_KEY_ID))) {
- Logger.error(LOG_TAG, "Invalid round 2 message: " + jClient.jIncoming.toJSONString());
- jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
-
- // Extract fields.
- jClient.jParty.otherA = new BigInteger((String) iPayload.get(Constants.ZKP_KEY_A), 16);
-
- // Extract ZKP.
- String gr = (String) zkpPayload.get(Constants.ZKP_KEY_GR);
- String b = (String) zkpPayload.get(Constants.ZKP_KEY_B);
- String id = (String) zkpPayload.get(Constants.ZKP_KEY_ID);
-
- jClient.jParty.otherZkpA = new Zkp(new BigInteger(gr, 16), new BigInteger(b, 16), id);
-
- jClient.myKeyBundle = null;
- try {
- jClient.myKeyBundle = JPakeCrypto.finalRound(JPakeClient.secretAsBigInteger(jClient.secret), jClient.jParty);
- } catch (IncorrectZkpException e) {
- Logger.error(LOG_TAG, "ZKP mismatch");
- jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE);
- return;
- } catch (NoSuchAlgorithmException e) {
- Logger.error(LOG_TAG, "NoSuchAlgorithmException", e);
- jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- } catch (InvalidKeyException e) {
- Logger.error(LOG_TAG, "InvalidKeyException", e);
- jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- } catch (UnsupportedEncodingException e) {
- Logger.error(LOG_TAG, "UnsupportedEncodingException", e);
- jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- }
-
- // Run next stage.
- jClient.runNextStage();
- }
-
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/stage/ComputeKeyVerificationStage.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake.stage;
-
-import java.io.UnsupportedEncodingException;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.jpake.JPakeClient;
-import org.mozilla.gecko.sync.setup.Constants;
-
-public class ComputeKeyVerificationStage extends JPakeStage {
-
- @Override
- public void execute(JPakeClient jClient) {
- Logger.debug(LOG_TAG, "Computing verification to send.");
- if (jClient.myKeyBundle == null) {
- Logger.error(LOG_TAG, "KeyBundle has not been set; aborting.");
- jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- }
- try {
- jClient.jOutgoing = computeKeyVerification(jClient.myKeyBundle, jClient.mySignerId);
- } catch (UnsupportedEncodingException e) {
- Logger.error(LOG_TAG, "Failure in key verification.", e);
- jClient.abort(Constants.JPAKE_ERROR_INVALID);
- return;
- } catch (CryptoException e) {
- Logger.error(LOG_TAG, "Encryption failure in key verification.", e);
- jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- }
-
- jClient.runNextStage();
- }
-
- /*
- * Helper function to compute a ciphertext, IV, and HMAC from derived
- * keyBundle for verifying other party.
- *
- * (Made 'public' for testing and is a stateless function.)
- */
- public ExtendedJSONObject computeKeyVerification(KeyBundle keyBundle, String signerId)
- throws UnsupportedEncodingException, CryptoException
- {
- Logger.debug(LOG_TAG, "Encrypting key verification value.");
- ExtendedJSONObject jPayload = JPakeClient.encryptPayload(JPakeClient.JPAKE_VERIFY_VALUE, keyBundle, true);
- ExtendedJSONObject result = new ExtendedJSONObject();
- result.put(Constants.JSON_KEY_TYPE, signerId + "3");
- result.put(Constants.JSON_KEY_VERSION, JPakeClient.KEYEXCHANGE_VERSION);
- result.put(Constants.JSON_KEY_PAYLOAD, jPayload.object);
- return result;
- }
-
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/stage/ComputeStepOneStage.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake.stage;
-
-import java.io.UnsupportedEncodingException;
-import java.security.NoSuchAlgorithmException;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.jpake.BigIntegerHelper;
-import org.mozilla.gecko.sync.jpake.JPakeClient;
-import org.mozilla.gecko.sync.jpake.JPakeCrypto;
-import org.mozilla.gecko.sync.jpake.JPakeJson;
-import org.mozilla.gecko.sync.jpake.JPakeParty;
-import org.mozilla.gecko.sync.jpake.Zkp;
-import org.mozilla.gecko.sync.setup.Constants;
-
-public class ComputeStepOneStage extends JPakeStage {
-
- @Override
- public void execute(JPakeClient jClient) {
- Logger.debug(LOG_TAG, "Computing round 1.");
-
- JPakeParty jClientParty = jClient.jParty;
- try {
- JPakeCrypto.round1(jClientParty, jClient.numGen);
- } catch (NoSuchAlgorithmException e) {
- Logger.error(LOG_TAG, "No such algorithm.", e);
- jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- } catch (UnsupportedEncodingException e) {
- Logger.error(LOG_TAG, "Unsupported encoding.", e);
- jClient.abort(Constants.JPAKE_ERROR_INVALID);
- return;
- } catch (Exception e) {
- Logger.error(LOG_TAG, "Unexpected exception.", e);
- jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- }
-
- // Set outgoing message.
- ExtendedJSONObject jOne = new ExtendedJSONObject();
- jOne.put(Constants.ZKP_KEY_GX1,
- BigIntegerHelper.toEvenLengthHex(jClientParty.gx1));
- jOne.put(Constants.ZKP_KEY_GX2,
- BigIntegerHelper.toEvenLengthHex(jClientParty.gx2));
-
- Zkp zkp1 = jClientParty.zkp1;
- Zkp zkp2 = jClientParty.zkp2;
- ExtendedJSONObject jZkp1 = JPakeJson.makeJZkp(zkp1.gr, zkp1.b, jClient.mySignerId);
- ExtendedJSONObject jZkp2 = JPakeJson.makeJZkp(zkp2.gr, zkp2.b, jClient.mySignerId);
-
- jOne.put(Constants.ZKP_KEY_ZKP_X1, jZkp1);
- jOne.put(Constants.ZKP_KEY_ZKP_X2, jZkp2);
-
- jClient.jOutgoing = new ExtendedJSONObject();
- jClient.jOutgoing.put(Constants.JSON_KEY_TYPE, jClient.mySignerId + "1");
- jClient.jOutgoing.put(Constants.JSON_KEY_PAYLOAD, jOne);
- jClient.jOutgoing.put(Constants.JSON_KEY_VERSION, JPakeClient.KEYEXCHANGE_VERSION);
- Logger.debug(LOG_TAG, "Sending: " + jClient.jOutgoing.toJSONString());
-
- jClient.runNextStage();
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/stage/ComputeStepTwoStage.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake.stage;
-
-import java.io.UnsupportedEncodingException;
-import java.math.BigInteger;
-import java.security.NoSuchAlgorithmException;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.jpake.BigIntegerHelper;
-import org.mozilla.gecko.sync.jpake.Gx3OrGx4IsZeroOrOneException;
-import org.mozilla.gecko.sync.jpake.IncorrectZkpException;
-import org.mozilla.gecko.sync.jpake.JPakeClient;
-import org.mozilla.gecko.sync.jpake.JPakeCrypto;
-import org.mozilla.gecko.sync.jpake.JPakeJson;
-import org.mozilla.gecko.sync.jpake.Zkp;
-import org.mozilla.gecko.sync.setup.Constants;
-
-public class ComputeStepTwoStage extends JPakeStage {
-
- @Override
- public void execute(JPakeClient jClient) {
- Logger.debug(LOG_TAG, "Computing round 2.");
-
- // Check incoming message sender.
- if (!jClient.jIncoming.get(Constants.JSON_KEY_TYPE).equals(jClient.theirSignerId + "1")) {
- Logger.error(LOG_TAG, "Invalid round 1 message: " + jClient.jIncoming.toJSONString());
- jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
-
- // Check incoming message fields.
- ExtendedJSONObject iPayload;
- try {
- iPayload = jClient.jIncoming.getObject(Constants.JSON_KEY_PAYLOAD);
- } catch (NonObjectJSONException e) {
- Logger.error(LOG_TAG, "JSON object exception.", e);
- jClient.abort(Constants.JPAKE_ERROR_INVALID);
- return;
- }
- if (iPayload == null) {
- Logger.error(LOG_TAG, "Invalid round 1 message: " + jClient.jIncoming.toJSONString());
- jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
- ExtendedJSONObject zkpPayload3;
- ExtendedJSONObject zkpPayload4;
- try {
- zkpPayload3 = iPayload.getObject(Constants.ZKP_KEY_ZKP_X1);
- zkpPayload4 = iPayload.getObject(Constants.ZKP_KEY_ZKP_X2);
- } catch (NonObjectJSONException e1) {
- jClient.abort(Constants.JPAKE_ERROR_INVALID);
- return;
- }
-
- if (zkpPayload3 == null || zkpPayload4 == null) {
- Logger.error(LOG_TAG, "Invalid round 1 zkpPayload message");
- jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
-
- if (!jClient.theirSignerId.equals(zkpPayload3.get(Constants.ZKP_KEY_ID)) ||
- !jClient.theirSignerId.equals(zkpPayload4.get(Constants.ZKP_KEY_ID))) {
- Logger.error(LOG_TAG, "Invalid round 1 zkpPayload message");
- jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
-
- // Extract message fields.
- jClient.jParty.gx3 = new BigInteger((String) iPayload.get(Constants.ZKP_KEY_GX1), 16);
- jClient.jParty.gx4 = new BigInteger((String) iPayload.get(Constants.ZKP_KEY_GX2), 16);
-
- // Extract ZKPs.
- String zkp3_gr = (String) zkpPayload3.get(Constants.ZKP_KEY_GR);
- String zkp3_b = (String) zkpPayload3.get(Constants.ZKP_KEY_B);
- String zkp3_id = (String) zkpPayload3.get(Constants.ZKP_KEY_ID);
-
- String zkp4_gr = (String) zkpPayload4.get(Constants.ZKP_KEY_GR);
- String zkp4_b = (String) zkpPayload4.get(Constants.ZKP_KEY_B);
- String zkp4_id = (String) zkpPayload4.get(Constants.ZKP_KEY_ID);
-
- jClient.jParty.zkp3 = new Zkp(new BigInteger(zkp3_gr, 16), new BigInteger(zkp3_b, 16), zkp3_id);
- jClient.jParty.zkp4 = new Zkp(new BigInteger(zkp4_gr, 16), new BigInteger(zkp4_b, 16), zkp4_id);
-
- // J-PAKE round 2.
- try {
- JPakeCrypto.round2(JPakeClient.secretAsBigInteger(jClient.secret), jClient.jParty, jClient.numGen);
- } catch (Gx3OrGx4IsZeroOrOneException e) {
- Logger.error(LOG_TAG, "gx3 and gx4 cannot equal 0 or 1.");
- jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- } catch (IncorrectZkpException e) {
- Logger.error(LOG_TAG, "ZKP mismatch");
- jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE);
- return;
- } catch (NoSuchAlgorithmException e) {
- Logger.error(LOG_TAG, "NoSuchAlgorithmException", e);
- jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- } catch (UnsupportedEncodingException e) {
- Logger.error(LOG_TAG, "UnsupportedEncodingException", e);
- jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- }
-
- // Make outgoing payload.
- Zkp zkpA = jClient.jParty.thisZkpA;
- ExtendedJSONObject oPayload = new ExtendedJSONObject();
- ExtendedJSONObject jZkpA = JPakeJson.makeJZkp(zkpA.gr, zkpA.b, zkpA.id);
- oPayload.put(Constants.ZKP_KEY_A, BigIntegerHelper.toEvenLengthHex(jClient.jParty.thisA));
- oPayload.put(Constants.ZKP_KEY_ZKP_A, jZkpA);
-
- // Make outgoing message.
- jClient.jOutgoing = new ExtendedJSONObject();
- jClient.jOutgoing.put(Constants.JSON_KEY_TYPE, jClient.mySignerId + "2");
- jClient.jOutgoing.put(Constants.JSON_KEY_VERSION, JPakeClient.KEYEXCHANGE_VERSION);
- jClient.jOutgoing.put(Constants.JSON_KEY_PAYLOAD, oPayload);
-
- jClient.runNextStage();
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/stage/DecryptDataStage.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake.stage;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-
-import org.json.simple.JSONObject;
-import org.json.simple.parser.ParseException;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.CryptoInfo;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.jpake.JPakeClient;
-import org.mozilla.gecko.sync.setup.Constants;
-
-public class DecryptDataStage extends JPakeStage {
-
- @Override
- public void execute(JPakeClient jClient) {
- Logger.debug(LOG_TAG, "Decrypting their payload.");
- if (!(jClient.theirSignerId + "3").equals((String) jClient.jIncoming
- .get(Constants.JSON_KEY_TYPE))) {
- Logger.error(LOG_TAG, "Invalid round 3 data: " + jClient.jIncoming.toJSONString());
- jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
-
- // Decrypt payload and verify HMAC.
- Logger.debug(LOG_TAG, "Decrypting payload.");
- ExtendedJSONObject iPayload = null;
- try {
- iPayload = jClient.jIncoming.getObject(Constants.JSON_KEY_PAYLOAD);
- } catch (NonObjectJSONException e1) {
- Logger.error(LOG_TAG, "Invalid round 3 data.", e1);
- jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
- Logger.debug(LOG_TAG, "Decrypting data.");
- String cleartext = null;
- try {
- cleartext = new String(decryptPayload(iPayload, jClient.myKeyBundle), "UTF-8");
- } catch (UnsupportedEncodingException e) {
- Logger.error(LOG_TAG, "Failed to decrypt data.", e);
- jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- } catch (CryptoException e) {
- Logger.error(LOG_TAG, "Failed to decrypt data.", e);
- jClient.abort(Constants.JPAKE_ERROR_KEYMISMATCH);
- return;
- }
- try {
- jClient.jCreds = ExtendedJSONObject.parseJSONObject(cleartext).object;
- } catch (IOException e) {
- Logger.error(LOG_TAG, "I/O exception while creating JSON object.", e);
- jClient.abort(Constants.JPAKE_ERROR_INVALID);
- return;
- } catch (ParseException | NonObjectJSONException e) {
- Logger.error(LOG_TAG, "JSON parse error.", e);
- jClient.abort(Constants.JPAKE_ERROR_INVALID);
- return;
- }
-
- // Check that credentials were actually sent over.
- if (!checkCredentials(jClient.jCreds)) {
- Logger.error(LOG_TAG, "Credentials contain nulls, setup cannot be completed.");
- jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- }
-
- jClient.runNextStage();
- }
-
- /**
- * Helper method for doing actual decryption.
- *
- * Input: JSONObject containing a valid payload (cipherText, IV, HMAC),
- * KeyBundle with keys for decryption. Output: byte[] clearText
- *
- * @throws CryptoException
- * @throws UnsupportedEncodingException
- */
- private byte[] decryptPayload(ExtendedJSONObject payload, KeyBundle keybundle)
- throws CryptoException, UnsupportedEncodingException {
-
- String sCiphertext = (String) payload.get(Constants.JSON_KEY_CIPHERTEXT);
- String sIv = (String) payload.get(Constants.JSON_KEY_IV);
- String sHmac = (String) payload.get(Constants.JSON_KEY_HMAC);
-
- byte[] ciphertext = Utils.decodeBase64(sCiphertext);
- byte[] iv = Utils.decodeBase64(sIv);
- byte[] hmac = Utils.hex2Byte(sHmac);
-
- CryptoInfo decrypted = CryptoInfo.decrypt(ciphertext, iv, hmac, keybundle);
- return decrypted.getMessage();
- }
-
- private boolean checkCredentials(JSONObject creds) {
- final String accountName = (String) creds.get(Constants.JSON_KEY_ACCOUNT);
- final String password = (String) creds.get(Constants.JSON_KEY_PASSWORD);
- final String syncKey = (String) creds.get(Constants.JSON_KEY_SYNCKEY);
- final String serverUrl = (String) creds.get(Constants.JSON_KEY_SERVER);
-
- if (accountName == null || accountName.equals("") ||
- password == null || password.equals("") ||
- syncKey == null || syncKey.equals("") ||
- serverUrl == null || serverUrl.equals("")) {
- return false;
- }
- return true;
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/stage/DeleteChannel.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake.stage;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.security.GeneralSecurityException;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.jpake.JPakeClient;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BaseResourceDelegate;
-import org.mozilla.gecko.sync.setup.auth.AccountAuthenticator;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.client.ClientProtocolException;
-import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
-import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
-import ch.boye.httpclientandroidlib.message.BasicHeader;
-
-public class DeleteChannel {
- private static final String LOG_TAG = "DeleteChannel";
-
- public static final String KEYEXCHANGE_ID_HEADER = "X-KeyExchange-Id";
- public static final String KEYEXCHANGE_CID_HEADER = "X-KeyExchange-Cid";
-
- public void execute(final JPakeClient jClient, final String reason) {
- final BaseResource httpResource;
- try {
- httpResource = new BaseResource(jClient.channelUrl);
- } catch (URISyntaxException e) {
- Logger.debug(LOG_TAG, "Encountered URISyntax exception, displaying abort anyway.");
- jClient.displayAbort(reason);
- return;
- }
- httpResource.delegate = new BaseResourceDelegate(httpResource) {
- @Override
- public String getUserAgent() {
- return SyncConstants.USER_AGENT;
- }
-
- @Override
- public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
- request.setHeader(new BasicHeader(KEYEXCHANGE_ID_HEADER, jClient.clientId));
- request.setHeader(new BasicHeader(KEYEXCHANGE_CID_HEADER, jClient.channel));
- }
-
- @Override
- public void handleHttpResponse(HttpResponse response) {
- try {
- int statusCode = response.getStatusLine().getStatusCode();
- switch (statusCode) {
- case 200:
- Logger.info(LOG_TAG, "Successfully reported error to server.");
- break;
- case 403:
- Logger.info(LOG_TAG, "IP is blacklisted.");
- break;
- case 400:
- Logger.info(LOG_TAG, "Bad request (missing logs, or bad ids");
- break;
- default:
- Logger.info(LOG_TAG, "Server returned " + statusCode);
- }
- } finally {
- BaseResource.consumeEntity(response);
- // Always call displayAbort, even if abort fails. We can't do anything about it.
- jClient.displayAbort(reason);
- }
- }
-
- @Override
- public void handleHttpProtocolException(ClientProtocolException e) {
- Logger.debug(LOG_TAG, "Encountered HttpProtocolException, displaying abort anyway.");
- jClient.displayAbort(reason);
- }
-
- @Override
- public void handleHttpIOException(IOException e) {
- Logger.debug(LOG_TAG, "Encountered IOException, displaying abort anyway.");
- jClient.displayAbort(reason);
- }
-
- @Override
- public void handleTransportException(GeneralSecurityException e) {
- Logger.debug(LOG_TAG, "Encountered GeneralSecurityException, displaying abort anyway.");
- jClient.displayAbort(reason);
- }
- };
-
- AccountAuthenticator.runOnThread(new Runnable() {
- @Override
- public void run() {
- httpResource.delete();
- }
- });
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/stage/GetChannelStage.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake.stage;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.security.GeneralSecurityException;
-
-import org.json.simple.parser.JSONParser;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.jpake.JPakeClient;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BaseResourceDelegate;
-import org.mozilla.gecko.sync.net.SyncResponse;
-import org.mozilla.gecko.sync.setup.Constants;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.client.ClientProtocolException;
-import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
-import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
-import ch.boye.httpclientandroidlib.message.BasicHeader;
-
-public class GetChannelStage extends JPakeStage {
-
- private interface GetChannelStageDelegate {
- public void handleSuccess(String channel);
- public void handleFailure(String error);
- public void handleError(Exception e);
- }
-
- @Override
- public void execute(final JPakeClient jClient) {
- Logger.debug(LOG_TAG, "Getting channel.");
-
- // Make delegate to handle responses and propagate them to JPakeClient.
- GetChannelStageDelegate callbackDelegate = new GetChannelStageDelegate() {
-
- @Override
- public void handleSuccess(String channel) {
- if (jClient.finished) {
- Logger.debug(LOG_TAG, "Finished; returning.");
- return;
- }
-
- jClient.channelUrl = jClient.jpakeServer + channel;
- Logger.debug(LOG_TAG, "Using channel " + channel);
- jClient.makeAndDisplayPin(channel);
-
- jClient.runNextStage();
- }
-
- @Override
- public void handleFailure(String error) {
- Logger.error(LOG_TAG, "Got HTTP failure: " + error);
- jClient.abort(error);
- }
-
- @Override
- public void handleError(Exception e) {
- Logger.error(LOG_TAG, "Threw HTTP exception.", e);
- jClient.abort(Constants.JPAKE_ERROR_CHANNEL);
- }
- };
-
- try {
- makeChannelRequest(callbackDelegate, jClient.jpakeServer + "new_channel", jClient.clientId);
- } catch (URISyntaxException e) {
- Logger.error(LOG_TAG, "Incorrect URI syntax.", e);
- jClient.abort(Constants.JPAKE_ERROR_CHANNEL);
- return;
- } catch (Exception e) {
- Logger.error(LOG_TAG, "Unexpected exception.", e);
- jClient.abort(Constants.JPAKE_ERROR_CHANNEL);
- return;
- }
- }
-
- private void makeChannelRequest(final GetChannelStageDelegate callbackDelegate, String getChannelUrl, final String clientId) throws URISyntaxException {
- final BaseResource httpResource = new BaseResource(getChannelUrl);
- httpResource.delegate = new BaseResourceDelegate(httpResource) {
- @Override
- public String getUserAgent() {
- return SyncConstants.USER_AGENT;
- }
-
- @Override
- public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
- request.setHeader(new BasicHeader("X-KeyExchange-Id", clientId));
- }
-
- @Override
- public void handleHttpResponse(HttpResponse response) {
- try {
- SyncResponse res = new SyncResponse(response);
- String channel = null;
- try {
- String body = res.body();
- channel = (String) new JSONParser().parse(body);
- } catch (Exception e) {
- callbackDelegate.handleError(e);
- return;
- }
-
- if (channel == null) {
- Logger.warn(LOG_TAG, "Got null channel.");
- callbackDelegate.handleFailure(Constants.JPAKE_ERROR_CHANNEL);
- return;
- }
-
- // Verify input.
- // From http://docs.services.mozilla.com/keyexchange/apis.html#apis
- // Returns in the response body a JSON-encoded random channel id of N chars from [a-z0-9].
- for (int i = 0; i < channel.length(); i++) {
- char c = channel.charAt(i);
- if (('a' <= c && c <= 'z') || ('0' <= c && c <= '9')) {
- continue;
- }
-
- Logger.warn(LOG_TAG, "Got bad channel name: " + channel + ".");
- callbackDelegate.handleFailure(Constants.JPAKE_ERROR_CHANNEL);
- return;
- }
-
- callbackDelegate.handleSuccess(channel);
- } finally {
- BaseResource.consumeEntity(response);
- }
- }
-
- @Override
- public void handleHttpProtocolException(ClientProtocolException e) {
- callbackDelegate.handleError(e);
- }
-
- @Override
- public void handleHttpIOException(IOException e) {
- callbackDelegate.handleError(e);
- }
-
- @Override
- public void handleTransportException(GeneralSecurityException e) {
- callbackDelegate.handleError(e);
- }
-
- @Override
- public int connectionTimeout() {
- return JPakeClient.REQUEST_TIMEOUT;
- }
- };
-
- // Make GET request.
- JPakeClient.runOnThread(new Runnable() {
- @Override
- public void run() {
- httpResource.get();
- }
- });
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/stage/GetRequestStage.java
+++ /dev/null
@@ -1,217 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake.stage;
-
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.security.GeneralSecurityException;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.jpake.JPakeClient;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BaseResourceDelegate;
-import org.mozilla.gecko.sync.net.Resource;
-import org.mozilla.gecko.sync.net.SyncResponse;
-import org.mozilla.gecko.sync.setup.Constants;
-
-import ch.boye.httpclientandroidlib.Header;
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.client.ClientProtocolException;
-import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
-import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
-import ch.boye.httpclientandroidlib.message.BasicHeader;
-
-public class GetRequestStage extends JPakeStage {
-
- private final Timer timerScheduler = new Timer();
- private int pollTries;
- private GetStepTimerTask getStepTimerTask;
-
- private interface GetRequestStageDelegate {
- public void handleSuccess(HttpResponse response);
- public void handleFailure(String error);
- public void handleError(Exception e);
- }
-
- @Override
- public void execute(final JPakeClient jClient) {
- Logger.debug(LOG_TAG, "Retrieving next message.");
-
- final GetRequestStageDelegate callbackDelegate = new GetRequestStageDelegate() {
-
- @Override
- public void handleSuccess(HttpResponse response) {
- if (jClient.finished) {
- Logger.debug(LOG_TAG, "Finished; returning.");
- return;
- }
- SyncResponse res = new SyncResponse(response);
-
- Header etagHeader = response.getFirstHeader("etag");
- if (etagHeader == null) {
- Logger.error(LOG_TAG, "Server did not supply ETag.");
- jClient.abort(Constants.JPAKE_ERROR_SERVER);
- return;
- }
-
- jClient.theirEtag = etagHeader.getValue();
- try {
- jClient.jIncoming = res.jsonObjectBody();
- } catch (Exception e) {
- Logger.error(LOG_TAG, "Illegal state.", e);
- jClient.abort(Constants.JPAKE_ERROR_INVALID);
- return;
- }
- Logger.debug(LOG_TAG, "incoming message: " + jClient.jIncoming.toJSONString());
-
- jClient.runNextStage();
- }
-
- @Override
- public void handleFailure(String error) {
- Logger.error(LOG_TAG, "Got HTTP failure: " + error);
- jClient.abort(error);
- }
-
- @Override
- public void handleError(Exception e) {
- Logger.error(LOG_TAG, "Threw HTTP exception.", e);
- jClient.abort(Constants.JPAKE_ERROR_NETWORK);
- }
- };
-
- Resource httpRequest;
- try {
- httpRequest = createGetRequest(callbackDelegate, jClient);
- } catch (URISyntaxException e) {
- Logger.error(LOG_TAG, "Incorrect URI syntax.", e);
- jClient.abort(Constants.JPAKE_ERROR_INVALID);
- return;
- }
-
- Logger.debug(LOG_TAG, "Scheduling GET request.");
- getStepTimerTask = new GetStepTimerTask(httpRequest);
- timerScheduler.schedule(getStepTimerTask, jClient.jpakePollInterval);
- }
-
- private Resource createGetRequest(final GetRequestStageDelegate callbackDelegate, final JPakeClient jpakeClient) throws URISyntaxException {
- BaseResource httpResource = new BaseResource(jpakeClient.channelUrl);
- httpResource.delegate = new BaseResourceDelegate(httpResource) {
- @Override
- public String getUserAgent() {
- return SyncConstants.USER_AGENT;
- }
-
- @Override
- public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
- request.setHeader(new BasicHeader("X-KeyExchange-Id", jpakeClient.clientId));
- if (jpakeClient.myEtag != null) {
- request.setHeader(new BasicHeader("If-None-Match", jpakeClient.myEtag));
- }
- }
-
- @Override
- public void handleHttpResponse(HttpResponse response) {
- try {
- int statusCode = response.getStatusLine().getStatusCode();
- switch (statusCode) {
- case 200:
- jpakeClient.pollTries = 0; // Reset pollTries for next GET.
- callbackDelegate.handleSuccess(response);
- break;
- case 304:
- Logger.debug(LOG_TAG, "Channel hasn't been updated yet. Will try again later");
- if (pollTries >= jpakeClient.jpakeMaxTries) {
- Logger.error(LOG_TAG, "Tried for " + pollTries + " times, maxTries " + jpakeClient.jpakeMaxTries + ", aborting");
- callbackDelegate.handleFailure(Constants.JPAKE_ERROR_TIMEOUT);
- break;
- }
- jpakeClient.pollTries += 1;
- if (!jpakeClient.finished) {
- Logger.debug(LOG_TAG, "Scheduling next GET request.");
- scheduleGetRequest(jpakeClient.jpakePollInterval, jpakeClient);
- } else {
- Logger.debug(LOG_TAG, "Resetting pollTries");
- jpakeClient.pollTries = 0;
- }
- break;
- case 404:
- Logger.error(LOG_TAG, "No data found in channel.");
- callbackDelegate.handleFailure(Constants.JPAKE_ERROR_NODATA);
- break;
- case 412: // "Precondition failed"
- Logger.debug(LOG_TAG, "Message already replaced on server by other party.");
- callbackDelegate.handleSuccess(response);
- break;
- default:
- Logger.error(LOG_TAG, "Could not retrieve data. Server responded with HTTP " + statusCode);
- callbackDelegate.handleFailure(Constants.JPAKE_ERROR_SERVER);
- break;
- }
- } finally {
- // Clean up.
- BaseResource.consumeEntity(response);
- }
- }
-
- @Override
- public void handleHttpProtocolException(ClientProtocolException e) {
- callbackDelegate.handleError(e);
- }
-
- @Override
- public void handleHttpIOException(IOException e) {
- callbackDelegate.handleError(e);
-
- }
-
- @Override
- public void handleTransportException(GeneralSecurityException e) {
- callbackDelegate.handleError(e);
- }
-
- @Override
- public int connectionTimeout() {
- return JPakeClient.REQUEST_TIMEOUT;
- }
- };
- return httpResource;
- }
-
- /**
- * TimerTask for use with delayed GET requests.
- *
- */
- public class GetStepTimerTask extends TimerTask {
- private final Resource request;
-
- public GetStepTimerTask(Resource request) {
- this.request = request;
- }
-
- @Override
- public void run() {
- request.get();
- }
- }
-
- /*
- * Helper method to schedule a GET request with some delay.
- * Basically, run another GetRequestStage.
- */
- private void scheduleGetRequest(int delay, final JPakeClient jClient) {
- timerScheduler.schedule(new TimerTask() {
-
- @Override
- public void run() {
- new GetRequestStage().execute(jClient);
- }
- }, delay);
- }
-
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/stage/JPakeStage.java
+++ /dev/null
@@ -1,12 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake.stage;
-
-import org.mozilla.gecko.sync.jpake.JPakeClient;
-
-public abstract class JPakeStage {
- protected final String LOG_TAG = "SyncJPakeStage";
- public abstract void execute(JPakeClient jClient);
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/stage/PutRequestStage.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake.stage;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URISyntaxException;
-import java.security.GeneralSecurityException;
-import java.util.Timer;
-import java.util.TimerTask;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.jpake.JPakeClient;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BaseResourceDelegate;
-import org.mozilla.gecko.sync.net.Resource;
-import org.mozilla.gecko.sync.setup.Constants;
-
-import ch.boye.httpclientandroidlib.Header;
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.client.ClientProtocolException;
-import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
-import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
-import ch.boye.httpclientandroidlib.message.BasicHeader;
-
-public class PutRequestStage extends JPakeStage {
-
- private interface PutRequestStageDelegate {
- public void handleSuccess(HttpResponse response);
- public void handleFailure(String error);
- public void handleError(Exception e);
- };
-
- @Override
- public void execute(final JPakeClient jClient) {
- Logger.debug(LOG_TAG, "Upload message.");
-
- // Create delegate.
- final PutRequestStageDelegate callbackDelegate = new PutRequestStageDelegate() {
-
- @Override
- public void handleSuccess(HttpResponse response) {
- TimerTask runNextStage = new TimerTask() {
- @Override
- public void run() {
- jClient.runNextStage();
- }
- };
- Timer timer = new Timer();
-
- Logger.debug(LOG_TAG, "Pause for 2 * pollInterval before continuing.");
- // There's no point in returning early here since the next step will
- // always be a GET, so let's pause for twice the poll interval.
- timer.schedule(runNextStage, 2 * jClient.jpakePollInterval);
- }
-
- @Override
- public void handleFailure(String error) {
- Logger.error(LOG_TAG, "Got HTTP failure: " + error);
- jClient.abort(error);
- }
-
- @Override
- public void handleError(Exception e) {
- Logger.error(LOG_TAG, "HTTP exception.", e);
- jClient.abort(Constants.JPAKE_ERROR_NETWORK);
- }
- };
-
- // Create PUT request.
- Resource putRequest;
- try {
- putRequest = createPutRequest(callbackDelegate, jClient);
- } catch (URISyntaxException e) {
- Logger.error(LOG_TAG, "URISyntaxException", e);
- jClient.abort(Constants.JPAKE_ERROR_CHANNEL);
- return;
- }
-
- try {
- putRequest.put(JPakeClient.jsonEntity(jClient.jOutgoing.object));
- } catch (UnsupportedEncodingException e) {
- Logger.error(LOG_TAG, "UnsupportedEncodingException", e);
- jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- }
- Logger.debug(LOG_TAG, "Outgoing message: " + jClient.jOutgoing.toJSONString());
- }
-
- private Resource createPutRequest(final PutRequestStageDelegate callbackDelegate, final JPakeClient jpakeClient) throws URISyntaxException {
- BaseResource httpResource = new BaseResource(jpakeClient.channelUrl);
- httpResource.delegate = new BaseResourceDelegate(httpResource) {
- @Override
- public String getUserAgent() {
- return SyncConstants.USER_AGENT;
- }
-
- @Override
- public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
- request.setHeader(new BasicHeader("X-KeyExchange-Id", jpakeClient.clientId));
- if (jpakeClient.theirEtag != null) {
- request.setHeader(new BasicHeader("If-Match", jpakeClient.theirEtag));
- } else {
- request.setHeader(new BasicHeader("If-None-Match", "*"));
- }
- }
-
- @Override
- public void handleHttpResponse(HttpResponse response) {
- try {
- int statusCode = response.getStatusLine().getStatusCode();
- switch (statusCode) {
- case 200:
- Header etagHeader = response.getFirstHeader("etag");
- if (etagHeader == null) {
- Logger.error(LOG_TAG, "Server did not supply ETag.");
- callbackDelegate.handleFailure(Constants.JPAKE_ERROR_SERVER);
- return;
- }
- jpakeClient.myEtag = etagHeader.getValue();
- callbackDelegate.handleSuccess(response);
- break;
- default:
- Logger.error(LOG_TAG, "Could not upload data. Server responded with HTTP " + statusCode);
- callbackDelegate.handleFailure(Constants.JPAKE_ERROR_SERVER);
- }
- } finally {
- BaseResource.consumeEntity(response);
- }
- }
-
- @Override
- public void handleHttpProtocolException(ClientProtocolException e) {
- callbackDelegate.handleError(e);
- }
-
- @Override
- public void handleHttpIOException(IOException e) {
- callbackDelegate.handleError(e);
- }
-
- @Override
- public void handleTransportException(GeneralSecurityException e) {
- callbackDelegate.handleError(e);
- }
-
- @Override
- public int connectionTimeout() {
- return JPakeClient.REQUEST_TIMEOUT;
- }
-
- };
- return httpResource;
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/jpake/stage/VerifyPairingStage.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.jpake.stage;
-
-import java.io.UnsupportedEncodingException;
-
-import org.mozilla.apache.commons.codec.binary.Base64;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.CryptoInfo;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.jpake.JPakeClient;
-import org.mozilla.gecko.sync.setup.Constants;
-
-public class VerifyPairingStage extends JPakeStage {
-
- @Override
- public void execute(JPakeClient jClient) {
- Logger.debug(LOG_TAG, "Verifying their key.");
-
- ExtendedJSONObject verificationObj = jClient.jIncoming;
- String signerId = (String) verificationObj.get(Constants.JSON_KEY_TYPE);
- if (!signerId.equals(jClient.theirSignerId + "3")) {
- Logger.error(LOG_TAG, "Invalid round 3 message: " + verificationObj.toJSONString());
- jClient.abort(Constants.JPAKE_ERROR_WRONGMESSAGE);
- return;
- }
- ExtendedJSONObject payload;
- try {
- payload = verificationObj.getObject(Constants.JSON_KEY_PAYLOAD);
- } catch (NonObjectJSONException e) {
- Logger.error(LOG_TAG, "JSON exception.", e);
- jClient.abort(Constants.JPAKE_ERROR_INVALID);
- return;
- }
- String theirCiphertext = (String) payload.get(Constants.JSON_KEY_CIPHERTEXT);
- String iv = (String) payload.get(Constants.JSON_KEY_IV);
- boolean correctPairing;
- try {
- correctPairing = verifyCiphertext(theirCiphertext, iv, jClient.myKeyBundle);
- } catch (UnsupportedEncodingException e) {
- Logger.error(LOG_TAG, "Unsupported encoding.", e);
- jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- } catch (CryptoException e) {
- Logger.error(LOG_TAG, "Crypto exception.", e);
- jClient.abort(Constants.JPAKE_ERROR_INTERNAL);
- return;
- }
- if (correctPairing) {
- Logger.debug(LOG_TAG, "Keys verified successfully.");
- jClient.paired = true;
- jClient.onPaired();
- } else {
- Logger.error(LOG_TAG, "Keys don't match.");
- jClient.abort(Constants.JPAKE_ERROR_KEYMISMATCH);
- return;
- }
- }
-
- /*
- * Helper function to verify an incoming ciphertext and IV against derived
- * keyBundle.
- *
- * (Made 'public' for testing and is a stateless function.)
- */
-
- public boolean verifyCiphertext(String theirCiphertext, String iv,
- KeyBundle keyBundle) throws UnsupportedEncodingException, CryptoException {
- byte[] cleartextBytes = JPakeClient.JPAKE_VERIFY_VALUE.getBytes("UTF-8");
- CryptoInfo encrypted = CryptoInfo.encrypt(cleartextBytes, Base64.decodeBase64(iv), keyBundle);
- String myCiphertext = new String(Base64.encodeBase64(encrypted.getMessage()), "UTF-8");
- return myCiphertext.equals(theirCiphertext);
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/receivers/SyncAccountDeletedReceiver.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.receivers;
-
-import org.mozilla.gecko.background.common.log.Logger;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-public class SyncAccountDeletedReceiver extends BroadcastReceiver {
- public static final String LOG_TAG = "SyncAccountDeletedReceiver";
-
- /**
- * This receiver can be killed as soon as it returns, but we have things to do
- * that can't be done on the main thread (network activity). Therefore we
- * start a service to do our clean up work for us, with Android doing the
- * heavy lifting for the service's lifecycle.
- * <p>
- * See <a href="http://developer.android.com/reference/android/content/BroadcastReceiver.html#ReceiverLifecycle">the Android documentation</a>
- * for details.
- */
- @Override
- public void onReceive(final Context context, Intent broadcastIntent) {
- Logger.debug(LOG_TAG, "Sync Account Deleted broadcast received.");
-
- Intent serviceIntent = new Intent(context, SyncAccountDeletedService.class);
- serviceIntent.putExtras(broadcastIntent);
- context.startService(serviceIntent);
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/receivers/SyncAccountDeletedService.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.receivers;
-
-import org.mozilla.gecko.fxa.FirefoxAccounts;
-import org.mozilla.gecko.fxa.FxAccountConstants;
-import org.mozilla.gecko.fxa.activities.FxAccountWebFlowActivity;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.background.common.GlobalConstants;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.Sync11Configuration;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.config.AccountPickler;
-import org.mozilla.gecko.sync.config.ClientRecordTerminator;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
-import org.mozilla.gecko.sync.setup.Constants;
-import org.mozilla.gecko.sync.setup.SyncAccounts;
-import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.app.IntentService;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-
-public class SyncAccountDeletedService extends IntentService {
- public static final String LOG_TAG = "SyncAccountDeletedService";
-
- public SyncAccountDeletedService() {
- super(LOG_TAG);
- }
-
- @Override
- protected void onHandleIntent(Intent intent) {
- // Intent can, in theory, be null. Bug 1025937.
- if (intent == null) {
- Logger.debug(LOG_TAG, "Short-circuiting on null intent.");
- return;
- }
-
- final Context context = this;
-
- if (SyncConstants.SYNC_ACCOUNT_DEPRECATED_ACTION.equals(intent.getAction())) {
- // Delete Old Sync account.
- final Account[] accounts = SyncAccounts.syncAccounts(this);
- for (Account account : accounts) {
- AccountManager.get(this).removeAccount(account, null, null);
- }
-
- // Offer signin for Firefox Account if we don't already have one.
- if (!FirefoxAccounts.firefoxAccountsExist(this)) {
- final Intent fxAccountWebIntent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
- fxAccountWebIntent.putExtra(FxAccountWebFlowActivity.EXTRA_ENDPOINT, FxAccountConstants.ENDPOINT_PREFERENCES);
- fxAccountWebIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- fxAccountWebIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
- context.startActivity(fxAccountWebIntent);
- }
-
- // Return early. The SYNC_ACCOUNT_DELETED_ACTION spawn by the account
- // deletion above will remove the pickle file.
- return;
- }
-
- long intentVersion = intent.getLongExtra(Constants.JSON_KEY_VERSION, 0);
- long expectedVersion = SyncConstants.SYNC_ACCOUNT_DELETED_INTENT_VERSION;
- if (intentVersion != expectedVersion) {
- Logger.warn(LOG_TAG, "Intent malformed: version " + intentVersion + " given but version " + expectedVersion + "expected. " +
- "Not cleaning up after deleted Account.");
- return;
- }
-
- String accountName = intent.getStringExtra(Constants.JSON_KEY_ACCOUNT); // Android Account name, not Sync encoded account name.
- if (accountName == null) {
- Logger.warn(LOG_TAG, "Intent malformed: no account name given. Not cleaning up after deleted Account.");
- return;
- }
-
- // Delete the Account pickle.
- Logger.info(LOG_TAG, "Sync account named " + accountName + " being removed; " +
- "deleting saved pickle file '" + Constants.ACCOUNT_PICKLE_FILENAME + "'.");
- deletePickle(context);
-
- SyncAccountParameters params;
- try {
- String payload = intent.getStringExtra(Constants.JSON_KEY_PAYLOAD);
- if (payload == null) {
- Logger.warn(LOG_TAG, "Intent malformed: no payload given. Not deleting client record.");
- return;
- }
- ExtendedJSONObject o = ExtendedJSONObject.parseJSONObject(payload);
- params = new SyncAccountParameters(context, AccountManager.get(context), o);
- } catch (Exception e) {
- Logger.warn(LOG_TAG, "Got exception fetching account parameters from intent data; not deleting client record.");
- return;
- }
-
- // Bug 770785: delete the Account's client record.
- Logger.info(LOG_TAG, "Account named " + accountName + " being removed; " +
- "deleting client record from server.");
- deleteClientRecord(context, accountName, params.password, params.serverURL);
-
- // Delete client database and non-local tabs.
- Logger.info(LOG_TAG, "Deleting the entire clients database and non-local tabs");
- FennecTabsRepository.deleteNonLocalClientsAndTabs(context);
- }
-
- public static void deletePickle(final Context context) {
- try {
- AccountPickler.deletePickle(context, Constants.ACCOUNT_PICKLE_FILENAME);
- } catch (Exception e) {
- // This should never happen, but we really don't want to die in a background thread.
- Logger.warn(LOG_TAG, "Got exception deleting saved pickle file; ignoring.", e);
- }
- }
-
- public static void deleteClientRecord(final Context context, final String accountName,
- final String password, final String serverURL) {
- String encodedUsername;
- try {
- encodedUsername = Utils.usernameFromAccount(accountName);
- } catch (Exception e) {
- Logger.warn(LOG_TAG, "Got exception deleting client record from server; ignoring.", e);
- return;
- }
-
- if (accountName == null || encodedUsername == null || password == null || serverURL == null) {
- Logger.warn(LOG_TAG, "Account parameters were null; not deleting client record from server.");
- return;
- }
-
- // This is not exactly modular. We need to get some information about
- // the account, namely the current clusterURL and client GUID, and we
- // extract it by hand. We're not worried about the Account being
- // deleted out from under us since the prefs remain even after Account
- // deletion.
- final String product = GlobalConstants.BROWSER_INTENT_PACKAGE;
- final String profile = Constants.DEFAULT_PROFILE;
- final long version = SyncConfiguration.CURRENT_PREFS_VERSION;
-
- SharedPreferences prefs;
- try {
- prefs = Utils.getSharedPreferences(context, product, encodedUsername, serverURL, profile, version);
- } catch (Exception e) {
- Logger.warn(LOG_TAG, "Caught exception fetching preferences; not deleting client record from server.", e);
- return;
- }
-
- try {
- final String clientGUID = prefs.getString(SyncConfiguration.PREF_ACCOUNT_GUID, null);
- if (clientGUID == null) {
- Logger.warn(LOG_TAG, "Client GUID was null; not deleting client record from server.");
- return;
- }
-
- BasicAuthHeaderProvider authHeaderProvider = new BasicAuthHeaderProvider(encodedUsername, password);
- SyncConfiguration configuration = new Sync11Configuration(encodedUsername, authHeaderProvider, prefs);
- if (configuration.getClusterURL() == null) {
- Logger.warn(LOG_TAG, "Cluster URL was null; not deleting client record from server.");
- return;
- }
-
- try {
- ClientRecordTerminator.deleteClientRecord(configuration, clientGUID);
- } catch (Exception e) {
- // This should never happen, but we really don't want to die in a background thread.
- Logger.warn(LOG_TAG, "Got exception deleting client record from server; ignoring.", e);
- }
- } finally {
- // Finally, a good place to do this.
- prefs.edit().clear().commit();
- }
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/receivers/UpgradeReceiver.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.receivers;
-
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.GlobalConstants;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.CredentialException;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.ThreadPool;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.config.ConfigurationMigrator;
-import org.mozilla.gecko.sync.setup.Constants;
-import org.mozilla.gecko.sync.setup.SyncAccounts;
-import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.support.v4.app.NotificationCompat.Builder;
-
-public class UpgradeReceiver extends BroadcastReceiver {
- private static final String LOG_TAG = "UpgradeReceiver";
-
- @Override
- public void onReceive(final Context context, Intent intent) {
- Logger.debug(LOG_TAG, "Broadcast received.");
-
- // This unpickles any pickled accounts.
- if (!SyncAccounts.syncAccountsExist(context)) {
- Logger.info(LOG_TAG, "No Sync Accounts found; not upgrading anything.");
- return;
- }
-
- // Show account not supported notification.
- ThreadPool.run(new Runnable() {
- @Override
- public void run() {
- notifyAccountDeprecation(context);
- }
- });
-
- // Should filter for specific MY_PACKAGE_REPLACED intent, but Android does
- // not expose it.
- ThreadPool.run(new Runnable() {
- @Override
- public void run() {
- final AccountManager accountManager = AccountManager.get(context);
- final Account[] accounts = SyncAccounts.syncAccounts(context);
-
- for (Account a : accounts) {
- if ("1".equals(accountManager.getUserData(a, Constants.DATA_ENABLE_ON_UPGRADE))) {
- SyncAccounts.setSyncAutomatically(a, true);
- accountManager.setUserData(a, Constants.DATA_ENABLE_ON_UPGRADE, "0");
- }
-
- // If we are both set to enable after upgrade, and to be removed: we
- // enable after upgrade first and then we try to remove. If removal
- // fails, since we enabled sync, we'll try again the next time we
- // sync, until we (eventually) remove the account.
- if ("1".equals(accountManager.getUserData(a, Constants.DATA_SHOULD_BE_REMOVED))) {
- accountManager.removeAccount(a, null, null);
- }
- }
- }
- });
-
- /**
- * Bug 761682: migrate preferences forward.
- */
- ThreadPool.run(new Runnable() {
- @Override
- public void run() {
- AccountManager accountManager = AccountManager.get(context);
- final Account[] accounts = SyncAccounts.syncAccounts(context);
-
- for (Account account : accounts) {
- Logger.info(LOG_TAG, "Migrating preferences on upgrade for Android account named " + Utils.obfuscateEmail(account.name) + ".");
-
- SyncAccountParameters params;
- try {
- params = SyncAccounts.blockingFromAndroidAccountV0(context, accountManager, account);
- } catch (CredentialException e) {
- Logger.warn(LOG_TAG, "Caught exception fetching account parameters while trying to migrate preferences; ignoring.", e);
- continue;
- }
-
- final String product = GlobalConstants.BROWSER_INTENT_PACKAGE;
- final String username = params.username;
- final String serverURL = params.serverURL;
- final String profile = "default";
- try {
- ConfigurationMigrator.ensurePrefsAreVersion(SyncConfiguration.CURRENT_PREFS_VERSION, context, accountManager, account,
- product, username, serverURL, profile);
- } catch (Exception e) {
- Logger.warn(LOG_TAG, "Caught exception trying to migrate preferences; ignoring.", e);
- continue;
- }
- }
- }
- });
- }
-
- /**
- * Show a persistent notification telling the user that their Old Sync account is deprecated.
- */
- private void notifyAccountDeprecation(final Context context) {
- final Intent notificationIntent = new Intent(SyncConstants.SYNC_ACCOUNT_DEPRECATED_ACTION);
- notificationIntent.setClass(context, SyncAccountDeletedService.class);
- final PendingIntent pendingIntent = PendingIntent.getService(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
- final Builder builder = new Builder(context)
- .setSmallIcon(R.drawable.ic_status_logo)
- .setContentTitle(context.getString(R.string.old_sync_deprecated_notification_title))
- .setContentText(context.getString(R.string.old_sync_deprecated_notification_content))
- .setAutoCancel(true)
- .setOngoing(true)
- .setContentIntent(pendingIntent);
-
- final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
- final int notificationID = SyncConstants.SYNC_ACCOUNT_DEPRECATED_ACTION.hashCode();
- notificationManager.notify(notificationID, builder.build());
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/SyncAuthenticatorService.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.setup;
-
-import java.io.UnsupportedEncodingException;
-import java.security.NoSuchAlgorithmException;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.setup.activities.SetupSyncActivity;
-
-import android.accounts.AbstractAccountAuthenticator;
-import android.accounts.Account;
-import android.accounts.AccountAuthenticatorResponse;
-import android.accounts.AccountManager;
-import android.accounts.NetworkErrorException;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.IBinder;
-
-public class SyncAuthenticatorService extends Service {
- private static final String LOG_TAG = "SyncAuthService";
-
- private SyncAccountAuthenticator sAccountAuthenticator = null;
-
- @Override
- public void onCreate() {
- Logger.debug(LOG_TAG, "onCreate");
- sAccountAuthenticator = getAuthenticator();
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- if (intent.getAction().equals(android.accounts.AccountManager.ACTION_AUTHENTICATOR_INTENT)) {
- return getAuthenticator().getIBinder();
- }
- return null;
- }
-
- private SyncAccountAuthenticator getAuthenticator() {
- if (sAccountAuthenticator == null) {
- sAccountAuthenticator = new SyncAccountAuthenticator(this);
- }
- return sAccountAuthenticator;
- }
-
- /**
- * Generate a "plain" auth token.
- * <p>
- * Android caches only the value of the key
- * <code>AccountManager.KEY_AUTHTOKEN</code>, so if a caller needs the other
- * keys in this bundle, it needs to invalidate the token (so that the bundle
- * is re-generated).
- *
- * @param context
- * Android context.
- * @param account
- * Android account.
- * @return a <code>Bundle</code> instance containing a subset of the following
- * keys: (caller's must check for missing keys)
- * <ul>
- * <li><code>AccountManager.KEY_ACCOUNT_TYPE</code>: the Android
- * Account's type</li>
- *
- * <li><code>AccountManager.KEY_ACCOUNT_NAME</code>: the Android
- * Account's name</li>
- *
- * <li><code>AccountManager.KEY_AUTHTOKEN</code>: the Sync account's
- * password </li>
- *
- * <li><code> Constants.OPTION_USERNAME</code>: the Sync account's
- * hashed username</li>
- *
- * <li><code>Constants.OPTION_SERVER</code>: the Sync account's
- * server</li>
- *
- * <li><code> Constants.OPTION_SYNCKEY</code>: the Sync account's
- * sync key</li>
- *
- * </ul>
- * @throws NetworkErrorException
- */
- public static Bundle getPlainAuthToken(final Context context, final Account account)
- throws NetworkErrorException {
- // Extract the username and password from the Account Manager, and ask
- // the server for an appropriate AuthToken.
- final AccountManager am = AccountManager.get(context);
- final String password = am.getPassword(account);
- if (password == null) {
- Logger.warn(LOG_TAG, "Returning null bundle for getPlainAuthToken since Account password is null.");
- return null;
- }
-
- final Bundle result = new Bundle();
-
- // This is a Sync account.
- result.putString(AccountManager.KEY_ACCOUNT_TYPE, SyncConstants.ACCOUNTTYPE_SYNC);
-
- // Server.
- String serverURL = am.getUserData(account, Constants.OPTION_SERVER);
- result.putString(Constants.OPTION_SERVER, serverURL);
-
- // Full username, before hashing.
- result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
-
- // Username after hashing.
- try {
- String username = Utils.usernameFromAccount(account.name);
- Logger.pii(LOG_TAG, "Account " + account.name + " hashes to " + username + ".");
- Logger.debug(LOG_TAG, "Setting username. Null? " + (username == null));
- result.putString(Constants.OPTION_USERNAME, username);
- } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
- // Do nothing. Calling code must check for missing value.
- Logger.debug(LOG_TAG, "Exception in account lookup: " + e);
- }
-
- // Sync key.
- final String syncKey = am.getUserData(account, Constants.OPTION_SYNCKEY);
- Logger.debug(LOG_TAG, "Setting sync key. Null? " + (syncKey == null));
- result.putString(Constants.OPTION_SYNCKEY, syncKey);
-
- // Password.
- result.putString(AccountManager.KEY_AUTHTOKEN, password);
- return result;
- }
-
- private static class SyncAccountAuthenticator extends AbstractAccountAuthenticator {
- private final Context mContext;
- public SyncAccountAuthenticator(Context context) {
- super(context);
- mContext = context;
- }
-
- @Override
- public Bundle addAccount(AccountAuthenticatorResponse response,
- String accountType, String authTokenType, String[] requiredFeatures,
- Bundle options) throws NetworkErrorException {
- Logger.debug(LOG_TAG, "addAccount()");
- final Intent intent = new Intent(mContext, SetupSyncActivity.class);
- intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
- response);
- intent.putExtra("accountType", SyncConstants.ACCOUNTTYPE_SYNC);
- intent.putExtra(Constants.INTENT_EXTRA_IS_SETUP, true);
-
- final Bundle result = new Bundle();
- result.putParcelable(AccountManager.KEY_INTENT, intent);
-
- return result;
- }
-
- @Override
- public Bundle confirmCredentials(AccountAuthenticatorResponse response,
- Account account,
- Bundle options) throws NetworkErrorException {
- Logger.debug(LOG_TAG, "confirmCredentials()");
- return null;
- }
-
- @Override
- public Bundle editProperties(AccountAuthenticatorResponse response,
- String accountType) {
- Logger.debug(LOG_TAG, "editProperties");
- return null;
- }
-
- @Override
- public Bundle getAuthToken(AccountAuthenticatorResponse response,
- Account account, String authTokenType, Bundle options)
- throws NetworkErrorException {
- Logger.debug(LOG_TAG, "getAuthToken()");
-
- if (Constants.AUTHTOKEN_TYPE_PLAIN.equals(authTokenType)) {
- return getPlainAuthToken(mContext, account);
- }
-
- final Bundle result = new Bundle();
- result.putString(AccountManager.KEY_ERROR_MESSAGE, "invalid authTokenType");
- return result;
- }
-
- @Override
- public String getAuthTokenLabel(String authTokenType) {
- Logger.debug(LOG_TAG, "getAuthTokenLabel()");
- return null;
- }
-
- @Override
- public Bundle hasFeatures(AccountAuthenticatorResponse response,
- Account account, String[] features) throws NetworkErrorException {
- Logger.debug(LOG_TAG, "hasFeatures()");
- return null;
- }
-
- @Override
- public Bundle updateCredentials(AccountAuthenticatorResponse response,
- Account account, String authTokenType, Bundle options)
- throws NetworkErrorException {
- Logger.debug(LOG_TAG, "updateCredentials()");
- return null;
- }
-
- /**
- * Bug 769745: persist pickled Sync account settings so that we can unpickle
- * after Fennec is moved to the SD card.
- * <p>
- * This is <b>not</b> called when an Android Account is blown away due to
- * the SD card being unmounted.
- * <p>
- * Broadcasting a Firefox intent to version sharing this Android Account is
- * a terrible hack, but it's better than the catching the generic
- * "accounts changed" broadcast intent and trying to figure out whether our
- * Account disappeared.
- */
- @Override
- public Bundle getAccountRemovalAllowed(final AccountAuthenticatorResponse response, Account account)
- throws NetworkErrorException {
- Bundle result = super.getAccountRemovalAllowed(response, account);
-
- if (result == null ||
- !result.containsKey(AccountManager.KEY_BOOLEAN_RESULT) ||
- result.containsKey(AccountManager.KEY_INTENT)) {
- return result;
- }
-
- final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
- if (!removalAllowed) {
- return result;
- }
-
- // Bug 790931: Broadcast a message to all Firefox versions sharing this
- // Android Account type telling that this Sync Account has been deleted.
- //
- // We would really prefer to receive Android's
- // LOGIN_ACCOUNTS_CHANGED_ACTION broadcast, but that
- // doesn't include enough information about which Accounts changed to
- // correctly identify whether a Sync account has been removed (when some
- // Firefox versions are installed on the SD card).
- //
- // Broadcast intents protected with permissions are secure, so it's okay
- // to include password and sync key, etc.
- final Intent intent = SyncAccounts.makeSyncAccountDeletedIntent(mContext, AccountManager.get(mContext), account);
- Logger.info(LOG_TAG, "Account named " + account.name + " being removed; " +
- "broadcasting secure intent " + intent.getAction() + ".");
- mContext.sendBroadcast(intent, SyncConstants.PER_ACCOUNT_TYPE_PERMISSION);
-
- return result;
- }
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/activities/AccountActivity.java
+++ /dev/null
@@ -1,353 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.setup.activities;
-
-import java.util.Locale;
-
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.ThreadPool;
-import org.mozilla.gecko.sync.setup.Constants;
-import org.mozilla.gecko.sync.setup.InvalidSyncKeyException;
-import org.mozilla.gecko.sync.setup.SyncAccounts;
-import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
-import org.mozilla.gecko.sync.setup.auth.AccountAuthenticator;
-import org.mozilla.gecko.sync.setup.auth.AuthenticationResult;
-
-import android.accounts.Account;
-import android.accounts.AccountAuthenticatorActivity;
-import android.accounts.AccountManager;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.EditText;
-import android.widget.Toast;
-
-public class AccountActivity extends AccountAuthenticatorActivity {
- private final static String LOG_TAG = "AccountActivity";
-
- private AccountManager mAccountManager;
- private Context mContext;
- private String username;
- private String password;
- private String key;
- private String server = SyncConstants.DEFAULT_AUTH_SERVER;
-
- // UI elements.
- private EditText serverInput;
- private EditText usernameInput;
- private EditText passwordInput;
- private EditText synckeyInput;
- private CheckBox serverCheckbox;
- private Button connectButton;
- private Button cancelButton;
- private ProgressDialog progressDialog;
-
- private AccountAuthenticator accountAuthenticator;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.sync_account);
-
- ActivityUtils.prepareLogging();
- mContext = getApplicationContext();
- Logger.debug(LOG_TAG, "AccountManager.get(" + mContext + ")");
- mAccountManager = AccountManager.get(mContext);
-
- // Set "screen on" flag.
- Logger.debug(LOG_TAG, "Setting screen-on flag.");
- Window w = getWindow();
- w.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-
- // Find UI elements.
- usernameInput = (EditText) findViewById(R.id.usernameInput);
- passwordInput = (EditText) findViewById(R.id.passwordInput);
- synckeyInput = (EditText) findViewById(R.id.keyInput);
- serverInput = (EditText) findViewById(R.id.serverInput);
-
- TextWatcher inputValidator = makeInputValidator();
-
- usernameInput.addTextChangedListener(inputValidator);
- passwordInput.addTextChangedListener(inputValidator);
- synckeyInput.addTextChangedListener(inputValidator);
- serverInput.addTextChangedListener(inputValidator);
-
- connectButton = (Button) findViewById(R.id.accountConnectButton);
- cancelButton = (Button) findViewById(R.id.accountCancelButton);
- serverCheckbox = (CheckBox) findViewById(R.id.checkbox_server);
-
- serverCheckbox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- Logger.info(LOG_TAG, "Toggling checkbox: " + isChecked);
- if (!isChecked) { // Clear server input.
- serverInput.setVisibility(View.GONE);
- findViewById(R.id.server_error).setVisibility(View.GONE);
- serverInput.setText("");
- } else {
- serverInput.setVisibility(View.VISIBLE);
- serverInput.setEnabled(true);
- }
- // Activate connectButton if necessary.
- activateView(connectButton, validateInputs());
- }
- });
- }
-
- @Override
- public void onResume() {
- super.onResume();
- ActivityUtils.prepareLogging();
- clearCredentials();
- usernameInput.requestFocus();
- cancelButton.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- cancelClickHandler(v);
- }
-
- });
- }
-
- public void cancelClickHandler(View target) {
- finish();
- }
-
- public void cancelConnectHandler(View target) {
- if (accountAuthenticator != null) {
- accountAuthenticator.isCanceled = true;
- accountAuthenticator = null;
- }
- displayVerifying(false);
- activateView(connectButton, true);
- clearCredentials();
- usernameInput.requestFocus();
- }
-
- private void clearCredentials() {
- // Only clear password. Re-typing the sync key or email is annoying.
- passwordInput.setText("");
- }
- /*
- * Get credentials on "Connect" and write to AccountManager, where it can be
- * accessed by Fennec and Sync Service.
- */
- public void connectClickHandler(View target) {
- Logger.debug(LOG_TAG, "connectClickHandler for view " + target);
- // Validate sync key format.
- try {
- key = ActivityUtils.validateSyncKey(synckeyInput.getText().toString());
- } catch (InvalidSyncKeyException e) {
- // Toast: invalid sync key format.
- Toast toast = Toast.makeText(mContext, R.string.sync_new_recoverykey_status_incorrect, Toast.LENGTH_LONG);
- toast.show();
- return;
- }
- username = usernameInput.getText().toString().toLowerCase(Locale.US);
- password = passwordInput.getText().toString();
- key = synckeyInput.getText().toString();
- server = SyncConstants.DEFAULT_AUTH_SERVER;
-
- if (serverCheckbox.isChecked()) {
- String userServer = serverInput.getText().toString();
- if (userServer != null) {
- userServer = userServer.trim();
- if (userServer.length() != 0) {
- if (!userServer.startsWith("https://") &&
- !userServer.startsWith("http://")) {
- // Assume HTTPS if not specified.
- userServer = "https://" + userServer;
- serverInput.setText(userServer);
- }
- server = userServer;
- }
- }
- }
-
- clearErrors();
- displayVerifying(true);
- cancelButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- cancelConnectHandler(v);
- // Set cancel click handler to leave account setup.
- cancelButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- cancelClickHandler(v);
- }
- });
- }
- });
-
- accountAuthenticator = new AccountAuthenticator(this);
- accountAuthenticator.authenticate(server, username, password);
- }
-
- private TextWatcher makeInputValidator() {
- return new TextWatcher() {
-
- @Override
- public void afterTextChanged(Editable s) {
- activateView(connectButton, validateInputs());
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
- };
- }
-
- private boolean validateInputs() {
- if (usernameInput.length() == 0 ||
- passwordInput.length() == 0 ||
- synckeyInput.length() == 0 ||
- (serverCheckbox.isChecked() &&
- serverInput.length() == 0)) {
- return false;
- }
- return true;
- }
-
- /*
- * Callback that handles auth based on success/failure
- */
- public void authCallback(final AuthenticationResult result) {
- displayVerifying(false);
- if (result != AuthenticationResult.SUCCESS) {
- Logger.debug(LOG_TAG, "displayFailure()");
- displayFailure(result);
- return;
- }
- // Successful authentication. Create and add account to AccountManager.
- SyncAccountParameters syncAccount = new SyncAccountParameters(
- mContext, mAccountManager, username, key, password, server);
- createAccountOnThread(syncAccount);
- }
-
- private void createAccountOnThread(final SyncAccountParameters syncAccount) {
- ThreadPool.run(new Runnable() {
- @Override
- public void run() {
- Account account = SyncAccounts.createSyncAccount(syncAccount);
- boolean isSuccess = (account != null);
- if (!isSuccess) {
- setResult(RESULT_CANCELED);
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- displayFailure(AuthenticationResult.FAILURE_ACCOUNT);
- }
- });
- return;
- }
-
- // Account created successfully.
- clearErrors();
-
- Bundle resultBundle = new Bundle();
- resultBundle.putString(AccountManager.KEY_ACCOUNT_NAME, syncAccount.username);
- resultBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, SyncConstants.ACCOUNTTYPE_SYNC);
- resultBundle.putString(AccountManager.KEY_AUTHTOKEN, SyncConstants.ACCOUNTTYPE_SYNC);
- setAccountAuthenticatorResult(resultBundle);
-
- setResult(RESULT_OK);
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- authSuccess();
- }
- });
- }
- });
- }
-
- private void displayVerifying(final boolean isVerifying) {
- if (isVerifying) {
- progressDialog = ProgressDialog.show(AccountActivity.this, "", getString(R.string.sync_verifying_label), true);
- } else {
- progressDialog.dismiss();
- }
- }
-
- private void displayFailure(final AuthenticationResult result) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Intent intent;
- switch (result) {
- case FAILURE_USERNAME:
- // No such username. Don't leak whether the username exists.
- case FAILURE_PASSWORD:
- findViewById(R.id.cred_error).setVisibility(View.VISIBLE);
- usernameInput.requestFocus();
- break;
- case FAILURE_SERVER:
- findViewById(R.id.server_error).setVisibility(View.VISIBLE);
- serverInput.requestFocus();
- break;
- case FAILURE_ACCOUNT:
- intent = new Intent(mContext, SetupFailureActivity.class);
- intent.setFlags(Constants.FLAG_ACTIVITY_REORDER_TO_FRONT_NO_ANIMATION);
- intent.putExtra(Constants.INTENT_EXTRA_IS_ACCOUNTERROR, true);
- startActivity(intent);
- break;
- case FAILURE_OTHER:
- default:
- // Display default error screen.
- Logger.debug(LOG_TAG, "displaying default failure.");
- intent = new Intent(mContext, SetupFailureActivity.class);
- intent.setFlags(Constants.FLAG_ACTIVITY_REORDER_TO_FRONT_NO_ANIMATION);
- startActivity(intent);
- }
- }
- });
- }
-
- /**
- * Feedback to user of account setup success.
- */
- public void authSuccess() {
- // Display feedback of successful account setup.
- Intent intent = new Intent(mContext, SetupSuccessActivity.class);
- intent.setFlags(Constants.FLAG_ACTIVITY_REORDER_TO_FRONT_NO_ANIMATION);
- startActivity(intent);
- finish();
- }
-
- private void activateView(View view, boolean toActivate) {
- view.setEnabled(toActivate);
- view.setClickable(toActivate);
- }
-
- private void clearErrors() {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- findViewById(R.id.cred_error).setVisibility(View.GONE);
- findViewById(R.id.server_error).setVisibility(View.GONE);
- }
- });
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/activities/RedirectToSetupActivity.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.setup.activities;
-
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.setup.Constants;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-
-public class RedirectToSetupActivity extends SyncActivity {
- public static final String LOG_TAG = "RedirectToSetupActivity";
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.sync_redirect_to_setup);
- }
-
- public void redirectToSetupHandler(View view) {
- Logger.info(LOG_TAG, "Setup Sync was clicked.");
-
- Intent intent = new Intent(this, SetupSyncActivity.class);
- intent.setFlags(Constants.FLAG_ACTIVITY_REORDER_TO_FRONT_NO_ANIMATION);
- startActivity(intent);
- }
-
- public void cancelClickHandler(View target) {
- setResult(RESULT_CANCELED);
- finish();
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/activities/SendTabData.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.setup.activities;
-
-import java.util.Arrays;
-import java.util.List;
-
-import android.content.Intent;
-import android.os.Bundle;
-
-/**
- * A static factory that extracts (title, uri) pairs suitable for send tab from
- * Android intent instances.
- * <p>
- * Takes some care to extract likely "Web URLs" in preference to general URIs.
- */
-public class SendTabData {
- public final String title;
- public final String uri;
-
- public SendTabData(String title, String uri) {
- this.title = title;
- this.uri = uri;
- }
-
- public static SendTabData fromIntent(Intent intent) {
- if (intent == null) {
- throw new IllegalArgumentException("intent must not be null");
- }
-
- return fromBundle(intent.getExtras());
- }
-
- protected static SendTabData fromBundle(Bundle bundle) {
- if (bundle == null) {
- throw new IllegalArgumentException("bundle must not be null");
- }
-
- String text = bundle.getString(Intent.EXTRA_TEXT);
- String subject = bundle.getString(Intent.EXTRA_SUBJECT);
- String title = bundle.getString(Intent.EXTRA_TITLE);
-
- // For title, prefer EXTRA_SUBJECT but accept EXTRA_TITLE.
- String theTitle = subject;
- if (theTitle == null) {
- theTitle = title;
- }
-
- // For URL, take first URL from EXTRA_TEXT, EXTRA_SUBJECT, and EXTRA_TITLE
- // (in that order).
- List<String> strings = Arrays.asList(text, subject, title);
- String theUri = new WebURLFinder(strings).bestWebURL();
-
- return new SendTabData(theTitle, theUri);
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/activities/SetupFailureActivity.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.setup.activities;
-
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.sync.setup.Constants;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.TextView;
-
-public class SetupFailureActivity extends SyncActivity {
- private Context mContext;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.sync_setup_failure);
- mContext = this.getApplicationContext();
-
- // Modify general error message if necessary.
- Bundle extras = this.getIntent().getExtras();
- if (extras != null) {
- boolean isAccountError = extras.getBoolean(Constants.INTENT_EXTRA_IS_ACCOUNTERROR);
- if (isAccountError) {
- TextView subtitle1 = (TextView) findViewById(R.id.failure_subtitle1);
- // Display error for multiple accounts.
- // TODO: Remove when Bug 761206 is resolved (support for multiple versions).
- TextView subtitle2 = (TextView) findViewById(R.id.failure_subtitle2);
- subtitle1.setText(getString(R.string.sync_subtitle_failaccount));
- subtitle2.setVisibility(View.VISIBLE);
- subtitle2.setText(getString(R.string.sync_subtitle_failmultiple));
- }
- }
- }
-
- public void manualClickHandler(View target) {
- Intent intent = new Intent(mContext, AccountActivity.class);
- intent.setFlags(Constants.FLAG_ACTIVITY_REORDER_TO_FRONT_NO_ANIMATION);
- startActivity(intent);
- overridePendingTransition(0, 0);
- finish();
- }
-
- public void tryAgainClickHandler(View target) {
- finish();
- }
-
- public void cancelClickHandler(View target) {
- setResult(RESULT_CANCELED);
- moveTaskToBack(true);
- finish();
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/activities/SetupSuccessActivity.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.setup.activities;
-
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.sync.setup.Constants;
-import org.mozilla.gecko.sync.setup.SyncAccounts;
-
-import android.os.Bundle;
-import android.view.View;
-import android.widget.TextView;
-
-public class SetupSuccessActivity extends SyncActivity {
- private TextView setupSubtitle;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Bundle extras = this.getIntent().getExtras();
- setContentView(R.layout.sync_setup_success);
- setupSubtitle = ((TextView) findViewById(R.id.setup_success_subtitle));
- if (extras != null) {
- boolean isSetup = extras.getBoolean(Constants.INTENT_EXTRA_IS_SETUP);
- if (!isSetup) {
- setupSubtitle.setText(getString(R.string.sync_subtitle_manage));
- }
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- }
-
- /* Click Handlers */
- public void settingsClickHandler(View target) {
- SyncAccounts.openSyncSettings(this);
- }
-
- public void launchBrowser(View target) {
- ActivityUtils.openURLInFennec(this, null);
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/activities/SetupSyncActivity.java
+++ /dev/null
@@ -1,623 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.setup.activities;
-
-import java.io.UnsupportedEncodingException;
-import java.util.HashMap;
-
-import org.json.simple.JSONObject;
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.ThreadPool;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.jpake.JPakeClient;
-import org.mozilla.gecko.sync.jpake.JPakeNoActivePairingException;
-import org.mozilla.gecko.sync.setup.Constants;
-import org.mozilla.gecko.sync.setup.SyncAccounts;
-import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
-
-import android.accounts.Account;
-import android.accounts.AccountAuthenticatorActivity;
-import android.accounts.AccountManager;
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.Uri;
-import android.os.Bundle;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import android.widget.Toast;
-
-public class SetupSyncActivity extends AccountAuthenticatorActivity {
- private final static String LOG_TAG = "SetupSync";
-
- private boolean pairWithPin = false;
-
- // UI elements for pairing through PIN entry.
- private EditText row1;
- private EditText row2;
- private EditText row3;
- private Button connectButton;
- private LinearLayout pinError;
-
- // UI elements for pairing through PIN generation.
- private TextView pinTextView1;
- private TextView pinTextView2;
- private TextView pinTextView3;
- private JPakeClient jClient;
-
- // Android context.
- private AccountManager mAccountManager;
- private Context mContext;
-
- public SetupSyncActivity() {
- super();
- }
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- ActivityUtils.prepareLogging();
- Logger.info(LOG_TAG, "Called SetupSyncActivity.onCreate.");
- super.onCreate(savedInstanceState);
-
- // Set Activity variables.
- mContext = getApplicationContext();
- Logger.debug(LOG_TAG, "AccountManager.get(" + mContext + ")");
- mAccountManager = AccountManager.get(mContext);
-
- // Set "screen on" flag for this activity. Screen will not automatically dim as long as this
- // activity is at the top of the stack.
- // Attempting to set this flag more than once causes hanging, so we set it here, not in onResume().
- Window w = getWindow();
- w.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- Logger.debug(LOG_TAG, "Successfully set screen-on flag.");
- }
-
- @Override
- public void onResume() {
- ActivityUtils.prepareLogging();
- Logger.info(LOG_TAG, "Called SetupSyncActivity.onResume.");
- super.onResume();
-
- if (!hasInternet()) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- setContentView(R.layout.sync_setup_nointernet);
- }
- });
- return;
- }
-
- // Check whether Sync accounts exist; if not, display J-PAKE PIN.
- // Run this on a separate thread to comply with Strict Mode thread policies.
- ThreadPool.run(new Runnable() {
- @Override
- public void run() {
- ActivityUtils.prepareLogging();
- Account[] accts = mAccountManager.getAccountsByType(SyncConstants.ACCOUNTTYPE_SYNC);
- finishResume(accts);
- }
- });
- }
-
- public void finishResume(Account[] accts) {
- Logger.debug(LOG_TAG, "Finishing Resume after fetching accounts.");
-
- if (accts.length == 0) { // Start J-PAKE for pairing if no accounts present.
- Logger.debug(LOG_TAG, "No accounts; starting J-PAKE receiver.");
- displayReceiveNoPin();
- if (jClient != null) {
- // Mark previous J-PAKE as finished. Don't bother propagating back up to this Activity.
- jClient.finished = true;
- }
- jClient = new JPakeClient(this);
- jClient.receiveNoPin();
- return;
- }
-
- // Set layout based on starting Intent.
- Bundle extras = this.getIntent().getExtras();
- if (extras != null) {
- Logger.debug(LOG_TAG, "SetupSync with extras.");
- boolean isSetup = extras.getBoolean(Constants.INTENT_EXTRA_IS_SETUP);
- if (!isSetup) {
- Logger.debug(LOG_TAG, "Account exists; Pair a Device started.");
- pairWithPin = true;
- displayPairWithPin();
- return;
- }
- }
-
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- Logger.debug(LOG_TAG, "Only one account supported. Redirecting.");
- // Display toast for "Only one account supported."
- // Redirect to account management.
- Toast toast = Toast.makeText(mContext,
- R.string.sync_notification_oneaccount, Toast.LENGTH_LONG);
- toast.show();
-
- // Setting up Sync when an existing account exists only happens from Settings,
- // so we can safely finish() the activity to return to Settings.
- finish();
- }
- });
- }
-
-
- @Override
- public void onPause() {
- super.onPause();
-
- if (jClient != null) {
- jClient.abort(Constants.JPAKE_ERROR_USERABORT);
- }
- if (pairWithPin) {
- finish();
- }
- }
-
- @Override
- public void onNewIntent(Intent intent) {
- Logger.debug(LOG_TAG, "Started SetupSyncActivity with new intent.");
- setIntent(intent);
- }
-
- @Override
- public void onDestroy() {
- Logger.debug(LOG_TAG, "onDestroy() called.");
- super.onDestroy();
- }
-
- /* Click Handlers */
- public void manualClickHandler(View target) {
- Intent accountIntent = new Intent(this, AccountActivity.class);
- accountIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
- startActivityForResult(accountIntent, 0);
- overridePendingTransition(0, 0);
- }
-
- public void cancelClickHandler(View target) {
- finish();
- }
-
- public void connectClickHandler(View target) {
- Logger.debug(LOG_TAG, "Connect clicked.");
- // Set UI feedback.
- pinError.setVisibility(View.INVISIBLE);
- enablePinEntry(false);
- connectButton.requestFocus();
- activateButton(connectButton, false);
-
- // Extract PIN.
- String pin = row1.getText().toString();
- pin += row2.getText().toString() + row3.getText().toString();
-
- // Start J-PAKE.
- if (jClient != null) {
- // Cancel previous J-PAKE exchange.
- jClient.finished = true;
- }
- jClient = new JPakeClient(this);
- jClient.pairWithPin(pin);
- }
-
- /**
- * Handler when "Show me how" link is clicked.
- * @param target
- * View that received the click.
- */
- public void showClickHandler(View target) {
- Uri uri = null;
- // TODO: fetch these from fennec
- if (pairWithPin) {
- uri = Uri.parse(Constants.LINK_FIND_CODE);
- } else {
- uri = Uri.parse(Constants.LINK_FIND_ADD_DEVICE);
- }
- Intent intent = new Intent(this, WebViewActivity.class);
- intent.setData(uri);
- startActivity(intent);
- }
-
- /* Controller methods */
-
- /**
- * Display generated PIN to user.
- * @param pin
- * 12-character string generated for J-PAKE.
- */
- public void displayPin(String pin) {
- if (pin == null) {
- Logger.warn(LOG_TAG, "Asked to display null pin.");
- return;
- }
- // Format PIN for display.
- int charPerLine = pin.length() / 3;
- final String pin1 = pin.substring(0, charPerLine);
- final String pin2 = pin.substring(charPerLine, 2 * charPerLine);
- final String pin3 = pin.substring(2 * charPerLine, pin.length());
-
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- TextView view1 = pinTextView1;
- TextView view2 = pinTextView2;
- TextView view3 = pinTextView3;
- if (view1 == null || view2 == null || view3 == null) {
- Logger.warn(LOG_TAG, "Couldn't find view to display PIN.");
- return;
- }
- view1.setText(pin1);
- view1.setContentDescription(pin1.replaceAll("\\B", ", "));
-
- view2.setText(pin2);
- view2.setContentDescription(pin2.replaceAll("\\B", ", "));
-
- view3.setText(pin3);
- view3.setContentDescription(pin3.replaceAll("\\B", ", "));
- }
- });
- }
-
- /**
- * Abort current J-PAKE pairing. Clear forms/restart pairing.
- * @param error
- */
- public void displayAbort(String error) {
- if (!Constants.JPAKE_ERROR_USERABORT.equals(error) && !hasInternet()) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- setContentView(R.layout.sync_setup_nointernet);
- }
- });
- return;
- }
- if (pairWithPin) {
- // Clear PIN entries and display error.
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- enablePinEntry(true);
- row1.setText("");
- row2.setText("");
- row3.setText("");
- row1.requestFocus();
-
- // Display error.
- pinError.setVisibility(View.VISIBLE);
- }
- });
- return;
- }
-
- // Start new JPakeClient for restarting J-PAKE.
- Logger.debug(LOG_TAG, "abort reason: " + error);
- if (!Constants.JPAKE_ERROR_USERABORT.equals(error)) {
- jClient = new JPakeClient(this);
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- displayReceiveNoPin();
- jClient.receiveNoPin();
- }
- });
- }
- }
-
- @SuppressWarnings({ "unchecked", "static-method" })
- protected JSONObject makeAccountJSON(String username, String password,
- String syncKey, String serverURL) {
-
- JSONObject jAccount = new JSONObject();
-
- // Hack to try to keep Java 1.7 from complaining about unchecked types,
- // despite the presence of SuppressWarnings.
- HashMap<String, String> fields = (HashMap<String, String>) jAccount;
-
- fields.put(Constants.JSON_KEY_SYNCKEY, syncKey);
- fields.put(Constants.JSON_KEY_ACCOUNT, username);
- fields.put(Constants.JSON_KEY_PASSWORD, password);
- fields.put(Constants.JSON_KEY_SERVER, serverURL);
-
- if (Logger.LOG_PERSONAL_INFORMATION) {
- Logger.pii(LOG_TAG, "Extracted account data: " + jAccount.toJSONString());
- }
- return jAccount;
- }
-
- /**
- * Device has finished key exchange, waiting for remote device to set up or
- * link to a Sync account. Display "waiting for other device" dialog.
- */
- public void onPaired() {
- // Extract Sync account data.
- Account[] accts = mAccountManager.getAccountsByType(SyncConstants.ACCOUNTTYPE_SYNC);
- if (accts.length == 0) {
- // Error, no account present.
- Logger.error(LOG_TAG, "No accounts present.");
- displayAbort(Constants.JPAKE_ERROR_INVALID);
- return;
- }
-
- // TODO: Single account supported. Create account selection if spec changes.
- Account account = accts[0];
- String username = account.name;
- String password = mAccountManager.getPassword(account);
- String syncKey = mAccountManager.getUserData(account, Constants.OPTION_SYNCKEY);
- String serverURL = mAccountManager.getUserData(account, Constants.OPTION_SERVER);
-
- JSONObject jAccount = makeAccountJSON(username, password, syncKey, serverURL);
- try {
- jClient.sendAndComplete(jAccount);
- } catch (JPakeNoActivePairingException e) {
- Logger.error(LOG_TAG, "No active J-PAKE pairing.", e);
- displayAbort(Constants.JPAKE_ERROR_INVALID);
- }
- }
-
- /**
- * J-PAKE pairing has started, but when this device has generated the PIN for
- * pairing, does not require UI feedback to user.
- */
- public void onPairingStart() {
- if (!pairWithPin) {
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- setContentView(R.layout.sync_setup_jpake_waiting);
- }
- });
- return;
- }
- }
-
- /**
- * On J-PAKE completion, store the Sync Account credentials sent by other
- * device. Display progress to user.
- *
- * @param jCreds
- */
- public void onComplete(JSONObject jCreds) {
- if (!pairWithPin) {
- // Create account from received credentials.
- String accountName = (String) jCreds.get(Constants.JSON_KEY_ACCOUNT);
- String password = (String) jCreds.get(Constants.JSON_KEY_PASSWORD);
- String syncKey = (String) jCreds.get(Constants.JSON_KEY_SYNCKEY);
- String serverURL = (String) jCreds.get(Constants.JSON_KEY_SERVER);
-
- // The password we get is double-encoded.
- try {
- password = Utils.decodeUTF8(password);
- } catch (UnsupportedEncodingException e) {
- Logger.warn(LOG_TAG, "Unsupported encoding when decoding UTF-8 ASCII J-PAKE message. Ignoring.");
- }
-
- final SyncAccountParameters syncAccount = new SyncAccountParameters(mContext, mAccountManager, accountName,
- syncKey, password, serverURL);
- createAccountOnThread(syncAccount);
- } else {
- // No need to create an account; just clean up.
- displayResultAndFinish(true);
- }
- }
-
- private void displayResultAndFinish(final boolean isSuccess) {
- jClient = null;
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- int result = isSuccess ? RESULT_OK : RESULT_CANCELED;
- setResult(result);
- displayResult(isSuccess);
- }
- });
- }
-
- private void createAccountOnThread(final SyncAccountParameters syncAccount) {
- ThreadPool.run(new Runnable() {
- @Override
- public void run() {
- Account account = SyncAccounts.createSyncAccount(syncAccount);
- boolean isSuccess = (account != null);
- if (isSuccess) {
- Bundle resultBundle = new Bundle();
- resultBundle.putString(AccountManager.KEY_ACCOUNT_NAME, syncAccount.username);
- resultBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, SyncConstants.ACCOUNTTYPE_SYNC);
- resultBundle.putString(AccountManager.KEY_AUTHTOKEN, SyncConstants.ACCOUNTTYPE_SYNC);
- setAccountAuthenticatorResult(resultBundle);
- }
- displayResultAndFinish(isSuccess);
- }
- });
- }
-
- /*
- * Helper functions
- */
- private void activateButton(Button button, boolean toActivate) {
- button.setEnabled(toActivate);
- button.setClickable(toActivate);
- }
-
- private void enablePinEntry(boolean toEnable) {
- row1.setEnabled(toEnable);
- row2.setEnabled(toEnable);
- row3.setEnabled(toEnable);
- }
-
- /**
- * Displays Sync account setup result to user.
- *
- * @param isSetup
- * true if account was set up successfully, false otherwise.
- */
- private void displayResult(boolean isSuccess) {
- Intent intent = null;
- if (isSuccess) {
- intent = new Intent(mContext, SetupSuccessActivity.class);
- intent.setFlags(Constants.FLAG_ACTIVITY_REORDER_TO_FRONT_NO_ANIMATION);
- intent.putExtra(Constants.INTENT_EXTRA_IS_SETUP, !pairWithPin);
- startActivity(intent);
- finish();
- } else {
- intent = new Intent(mContext, SetupFailureActivity.class);
- intent.putExtra(Constants.INTENT_EXTRA_IS_ACCOUNTERROR, true);
- intent.setFlags(Constants.FLAG_ACTIVITY_REORDER_TO_FRONT_NO_ANIMATION);
- intent.putExtra(Constants.INTENT_EXTRA_IS_SETUP, !pairWithPin);
- startActivity(intent);
- // Do not finish, so user can retry setup by hitting "back."
- }
- }
-
- /**
- * Validate PIN entry fields to check if the three PIN entry fields are all
- * filled in.
- *
- * @return true, if all PIN fields have 4 characters, false otherwise
- */
- private boolean pinEntryCompleted() {
- if (row1.length() == 4 &&
- row2.length() == 4 &&
- row3.length() == 4) {
- return true;
- }
- return false;
- }
-
- private boolean hasInternet() {
- Logger.debug(LOG_TAG, "Checking internet connectivity.");
- ConnectivityManager connManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- NetworkInfo network = connManager.getActiveNetworkInfo();
-
- if (network != null && network.isConnected()) {
- Logger.debug(LOG_TAG, network + " is connected.");
- return true;
- }
- Logger.debug(LOG_TAG, "No connected networks.");
- return false;
- }
-
- /**
- * Displays layout for entering a PIN from another device.
- * A Sync Account has already been set up.
- */
- private void displayPairWithPin() {
- Logger.debug(LOG_TAG, "PairWithPin initiated.");
- runOnUiThread(new Runnable() {
-
- @Override
- public void run() {
- setContentView(R.layout.sync_setup_pair);
- connectButton = (Button) findViewById(R.id.pair_button_connect);
- pinError = (LinearLayout) findViewById(R.id.pair_error);
-
- row1 = (EditText) findViewById(R.id.pair_row1);
- row2 = (EditText) findViewById(R.id.pair_row2);
- row3 = (EditText) findViewById(R.id.pair_row3);
-
- row1.addTextChangedListener(new TextWatcher() {
- @Override
- public void afterTextChanged(Editable s) {
- activateButton(connectButton, pinEntryCompleted());
- if (s.length() == 4) {
- row2.requestFocus();
- }
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- });
- row2.addTextChangedListener(new TextWatcher() {
- @Override
- public void afterTextChanged(Editable s) {
- activateButton(connectButton, pinEntryCompleted());
- if (s.length() == 4) {
- row3.requestFocus();
- }
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- });
-
- row3.addTextChangedListener(new TextWatcher() {
- @Override
- public void afterTextChanged(Editable s) {
- activateButton(connectButton, pinEntryCompleted());
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count,
- int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
- });
-
- row1.requestFocus();
- }
- });
- }
-
- /**
- * Displays layout with PIN for pairing with another device.
- * No Sync Account has been set up yet.
- */
- private void displayReceiveNoPin() {
- Logger.debug(LOG_TAG, "ReceiveNoPin initiated");
- runOnUiThread(new Runnable(){
-
- @Override
- public void run() {
- setContentView(R.layout.sync_setup);
-
- // Set up UI.
- pinTextView1 = ((TextView) findViewById(R.id.text_pin1));
- pinTextView2 = ((TextView) findViewById(R.id.text_pin2));
- pinTextView3 = ((TextView) findViewById(R.id.text_pin3));
- }
- });
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (resultCode) {
- case Activity.RESULT_OK:
- // Setup completed in manual setup.
- finish();
- }
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/activities/SyncActivity.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.setup.activities;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-/**
- * Shared superclass of Sync activities. Currently exists to prepare per-thread
- * logging.
- */
-public abstract class SyncActivity extends Activity {
-
- @Override
- protected void onResume() {
- super.onResume();
- ActivityUtils.prepareLogging();
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- ActivityUtils.prepareLogging();
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/activities/WebViewActivity.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.setup.activities;
-
-import org.mozilla.gecko.R;
-import org.mozilla.gecko.background.common.log.Logger;
-
-import android.app.Activity;
-import android.net.Uri;
-import android.os.Bundle;
-import android.view.Window;
-import android.webkit.WebChromeClient;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-
-/**
- * Displays URI in an embedded WebView. Closes if there no URI is passed in.
- * @author liuche
- *
- */
-public class WebViewActivity extends SyncActivity {
- private final static String LOG_TAG = "WebViewActivity";
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- getWindow().requestFeature(Window.FEATURE_PROGRESS);
- setContentView(R.layout.sync_setup_webview);
- // Extract URI to launch from Intent.
- Uri uri = this.getIntent().getData();
- if (uri == null) {
- Logger.debug(LOG_TAG, "No URI passed to display.");
- finish();
- return;
- }
-
- WebView wv = (WebView) findViewById(R.id.web_engine);
- // Add a progress bar.
- final Activity activity = this;
- wv.setWebChromeClient(new WebChromeClient() {
- @Override
- public void onProgressChanged(WebView view, int progress) {
- // Activities and WebViews measure progress with different scales.
- // The progress meter will automatically disappear when we reach 100%
- activity.setProgress(progress * 100);
- }
- });
- wv.setWebViewClient(new WebViewClient() {
- // Handle url loading in this WebView, instead of asking the ActivityManager.
- @Override
- public boolean shouldOverrideUrlLoading(WebView view, String url) {
- view.loadUrl(url);
- return false;
- }
- });
- wv.loadUrl(uri.toString());
-
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/auth/AccountAuthenticator.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.setup.auth;
-
-import java.util.LinkedList;
-import java.util.Queue;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.ThreadPool;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.setup.activities.AccountActivity;
-
-public class AccountAuthenticator {
- private final String LOG_TAG = "AccountAuthenticator";
-
- private final AccountActivity activityCallback;
- private Queue<AuthenticatorStage> stages;
-
- // Values for authentication.
- public String password;
- public String username;
-
- public String authServer;
- public String nodeServer;
-
- public boolean isSuccess = false;
- public boolean isCanceled = false;
-
- public AccountAuthenticator(AccountActivity activity) {
- activityCallback = activity;
- prepareStages();
- }
-
- private void prepareStages() {
- stages = new LinkedList<AuthenticatorStage>();
- stages.add(new EnsureUserExistenceStage());
- stages.add(new FetchUserNodeStage());
- stages.add(new AuthenticateAccountStage());
- }
-
- public void authenticate(String server, String account, String password) {
- // Set authentication values.
- if (!server.endsWith("/")) {
- server += "/";
- }
- nodeServer = server;
- this.password = password;
-
- // Calculate and save username hash.
- try {
- username = Utils.usernameFromAccount(account);
- } catch (Exception e) {
- abort(AuthenticationResult.FAILURE_OTHER, e);
- return;
- }
- Logger.pii(LOG_TAG, "Username:" + username);
- Logger.debug(LOG_TAG, "Running first stage.");
- // Start first stage of authentication.
- runNextStage();
- }
-
- /**
- * Run next stage of authentication.
- */
- public void runNextStage() {
- if (isCanceled) {
- return;
- }
- if (stages.size() == 0) {
- Logger.debug(LOG_TAG, "Authentication completed.");
- activityCallback.authCallback(isSuccess ? AuthenticationResult.SUCCESS : AuthenticationResult.FAILURE_PASSWORD);
- return;
- }
- AuthenticatorStage nextStage = stages.remove();
- try {
- nextStage.execute(this);
- } catch (Exception e) {
- Logger.warn(LOG_TAG, "Unhandled exception in stage " + nextStage);
- abort(AuthenticationResult.FAILURE_OTHER, e);
- }
- }
-
- /**
- * Abort authentication.
- *
- * @param result
- * returned to callback.
- * @param e
- * Exception causing abort.
- */
- public void abort(AuthenticationResult result, Exception e) {
- if (isCanceled) {
- return;
- }
- Logger.warn(LOG_TAG, "Authentication failed.", e);
- activityCallback.authCallback(result);
- }
-
- /* Helper functions */
- public static void runOnThread(Runnable run) {
- ThreadPool.run(run);
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/auth/AuthenticateAccountStage.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.setup.auth;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.security.GeneralSecurityException;
-
-import org.mozilla.apache.commons.codec.binary.Base64;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BaseResourceDelegate;
-import org.mozilla.gecko.sync.setup.Constants;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.client.ClientProtocolException;
-import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
-import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
-import ch.boye.httpclientandroidlib.message.BasicHeader;
-
-public class AuthenticateAccountStage implements AuthenticatorStage {
- private final String LOG_TAG = "AuthAccountStage";
- private HttpRequestBase httpRequest = null;
-
- public interface AuthenticateAccountStageDelegate {
- public void handleSuccess(boolean isSuccess);
- public void handleFailure(HttpResponse response);
- public void handleError(Exception e);
- }
-
- @Override
- public void execute(final AccountAuthenticator aa) throws URISyntaxException, UnsupportedEncodingException {
- AuthenticateAccountStageDelegate callbackDelegate = new AuthenticateAccountStageDelegate() {
-
- @Override
- public void handleSuccess(boolean isSuccess) {
- aa.isSuccess = isSuccess;
- aa.runNextStage();
- }
-
- @Override
- public void handleFailure(HttpResponse response) {
- Logger.debug(LOG_TAG, "handleFailure");
- aa.abort(AuthenticationResult.FAILURE_OTHER, new Exception(response.getStatusLine().getStatusCode() + " error."));
- if (response.getEntity() == null) {
- // No cleanup necessary.
- return;
- }
- try {
- BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
- BaseResource.consumeReader(reader);
- } catch (IllegalStateException | IOException e) {
- Logger.debug(LOG_TAG, "Error reading content.", e);
- } catch (RuntimeException e) {
- Logger.debug(LOG_TAG, "Unexpected exception.", e);
- if (httpRequest != null) {
- httpRequest.abort();
- }
- }
- }
-
- @Override
- public void handleError(Exception e) {
- Logger.debug(LOG_TAG, "handleError", e);
- aa.abort(AuthenticationResult.FAILURE_OTHER, e);
- }
- };
-
- // Calculate BasicAuth hash of username/password.
- String authHeader = makeAuthHeader(aa.username, aa.password);
- String authRequestUrl = makeAuthRequestUrl(aa.authServer, aa.username);
- // Might contain plaintext username for old Sync accounts.
- Logger.pii(LOG_TAG, "Making auth request to: " + authRequestUrl);
- authenticateAccount(callbackDelegate, authRequestUrl, authHeader);
-
- }
-
- /**
- * Makes an authentication request to the server and passes appropriate response back to callback.
- * @param callbackDelegate
- * Delegate to deal with HTTP response.
- * @param authRequestUrl
- * @param authHeader
- * @throws URISyntaxException
- */
- // Made public for testing.
- public void authenticateAccount(final AuthenticateAccountStageDelegate callbackDelegate, final String authRequestUrl, final String authHeader) throws URISyntaxException {
- final BaseResource httpResource = new BaseResource(authRequestUrl);
- httpResource.delegate = new BaseResourceDelegate(httpResource) {
- @Override
- public String getUserAgent() {
- return SyncConstants.USER_AGENT;
- }
-
- @Override
- public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
- // Make reference to request, to abort if necessary.
- httpRequest = request;
- client.log.enableDebug(true);
- // Host header is not set for some reason, so do it explicitly.
- try {
- URI authServerUri = new URI(authRequestUrl);
- request.setHeader(new BasicHeader("Host", authServerUri.getHost()));
- } catch (URISyntaxException e) {
- Logger.error(LOG_TAG, "Malformed uri, will be caught elsewhere.", e);
- }
- request.setHeader(new BasicHeader("Authorization", authHeader));
- }
-
- @Override
- public void handleHttpResponse(HttpResponse response) {
- int statusCode = response.getStatusLine().getStatusCode();
- try {
- switch (statusCode) {
- case 200:
- callbackDelegate.handleSuccess(true);
- break;
- case 401:
- callbackDelegate.handleSuccess(false);
- break;
- default:
- callbackDelegate.handleFailure(response);
- }
- } finally {
- BaseResource.consumeEntity(response.getEntity());
- Logger.info(LOG_TAG, "Released entity.");
- }
- }
-
- @Override
- public void handleHttpProtocolException(ClientProtocolException e) {
- Logger.error(LOG_TAG, "Client protocol error.", e);
- callbackDelegate.handleError(e);
- }
-
- @Override
- public void handleHttpIOException(IOException e) {
- Logger.error(LOG_TAG, "I/O exception.");
- callbackDelegate.handleError(e);
- }
-
- @Override
- public void handleTransportException(GeneralSecurityException e) {
- Logger.error(LOG_TAG, "Transport exception.");
- callbackDelegate.handleError(e);
- }
- };
-
- AccountAuthenticator.runOnThread(new Runnable() {
- @Override
- public void run() {
- httpResource.get();
- }
- });
- }
-
- public String makeAuthHeader(String usernameHash, String password) {
- try {
- return "Basic " + Base64.encodeBase64String((usernameHash + ":" + password).getBytes("UTF-8"));
- } catch (UnsupportedEncodingException e) {
- Logger.debug(LOG_TAG, "Unsupported encoding: UTF-8.");
- return null;
- }
- }
-
- public String makeAuthRequestUrl(String authServer, String usernameHash) {
- return authServer + Constants.AUTH_SERVER_VERSION + usernameHash + "/" + Constants.AUTH_SERVER_SUFFIX;
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/auth/AuthenticationResult.java
+++ /dev/null
@@ -1,9 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.setup.auth;
-
-public enum AuthenticationResult {
- SUCCESS, FAILURE_USERNAME, FAILURE_PASSWORD, FAILURE_SERVER, FAILURE_ACCOUNT, FAILURE_OTHER
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/auth/AuthenticatorStage.java
+++ /dev/null
@@ -1,12 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.setup.auth;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URISyntaxException;
-
-public interface AuthenticatorStage {
- public void execute(AccountAuthenticator aa) throws URISyntaxException, UnsupportedEncodingException;
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/auth/EnsureUserExistenceStage.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.setup.auth;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
-import java.net.URISyntaxException;
-import java.security.GeneralSecurityException;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BaseResourceDelegate;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.client.ClientProtocolException;
-
-public class EnsureUserExistenceStage implements AuthenticatorStage {
- private final String LOG_TAG = "EnsureUserExistence";
-
- public interface EnsureUserExistenceStageDelegate {
- public void handleSuccess();
- public void handleFailure(AuthenticationResult result);
- public void handleError(Exception e);
- }
- @Override
- public void execute(final AccountAuthenticator aa) throws URISyntaxException,
- UnsupportedEncodingException {
- final EnsureUserExistenceStageDelegate callbackDelegate = new EnsureUserExistenceStageDelegate() {
-
- @Override
- public void handleSuccess() {
- // User exists; now determine auth node.
- Logger.debug(LOG_TAG, "handleSuccess()");
- aa.runNextStage();
- }
-
- @Override
- public void handleFailure(AuthenticationResult result) {
- aa.abort(result, new Exception("Failure in EnsureUser"));
- }
-
- @Override
- public void handleError(Exception e) {
- Logger.info(LOG_TAG, "Error checking for user existence.");
- aa.abort(AuthenticationResult.FAILURE_SERVER, e);
- }
-
- };
-
- // This is not the same as Utils.nodeWeaveURL: it's missing the trailing node/weave.
- String userRequestUrl = aa.nodeServer + "user/1.0/" + aa.username;
- final BaseResource httpResource = new BaseResource(userRequestUrl);
- httpResource.delegate = new BaseResourceDelegate(httpResource) {
- @Override
- public String getUserAgent() {
- return SyncConstants.USER_AGENT;
- }
-
- @Override
- public void handleHttpResponse(HttpResponse response) {
- int statusCode = response.getStatusLine().getStatusCode();
- switch(statusCode) {
- case 200:
- try {
- InputStream content = response.getEntity().getContent();
- BufferedReader reader = new BufferedReader(new InputStreamReader(content, "UTF-8"), 1024);
- String inUse = reader.readLine();
- BaseResource.consumeReader(reader);
- reader.close();
- // Removed Logger.debug inUse, because stalling.
- if (inUse.equals("1")) { // Username exists.
- callbackDelegate.handleSuccess();
- } else { // User does not exist.
- Logger.info(LOG_TAG, "No such user.");
- callbackDelegate.handleFailure(AuthenticationResult.FAILURE_USERNAME);
- }
- } catch (Exception e) {
- Logger.error(LOG_TAG, "Failure in content parsing.", e);
- callbackDelegate.handleFailure(AuthenticationResult.FAILURE_OTHER);
- }
- break;
- default: // No other response is acceptable.
- callbackDelegate.handleFailure(AuthenticationResult.FAILURE_OTHER);
- }
- Logger.debug(LOG_TAG, "Consuming entity.");
- BaseResource.consumeEntity(response.getEntity());
- }
-
- @Override
- public void handleHttpProtocolException(ClientProtocolException e) {
- callbackDelegate.handleError(e);
- }
-
- @Override
- public void handleHttpIOException(IOException e) {
- callbackDelegate.handleError(e);
- }
-
- @Override
- public void handleTransportException(GeneralSecurityException e) {
- callbackDelegate.handleError(e);
- }
-
- };
- // Make request.
- AccountAuthenticator.runOnThread(new Runnable() {
-
- @Override
- public void run() {
- httpResource.get();
- }
- });
- }
-
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/auth/FetchUserNodeStage.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.setup.auth;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URISyntaxException;
-import java.security.GeneralSecurityException;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.BaseResourceDelegate;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-import ch.boye.httpclientandroidlib.client.ClientProtocolException;
-
-public class FetchUserNodeStage implements AuthenticatorStage {
- private final String LOG_TAG = "FetchUserNodeStage";
-
- public interface FetchNodeStageDelegate {
- public void handleSuccess(String url);
- public void handleFailure(HttpResponse response);
- public void handleError(Exception e);
- }
-
- @Override
- public void execute(final AccountAuthenticator aa) throws URISyntaxException {
-
- FetchNodeStageDelegate callbackDelegate = new FetchNodeStageDelegate() {
-
- @Override
- public void handleSuccess(String server) {
- if (server == null) { // No separate auth node; use server url.
- Logger.debug(LOG_TAG, "Using server as auth node.");
- aa.authServer = aa.nodeServer;
- aa.runNextStage();
- return;
- }
- if (!server.endsWith("/")) {
- server += "/";
- }
- aa.authServer = server;
- aa.runNextStage();
- }
-
- @Override
- public void handleFailure(HttpResponse response) {
- int statusCode = response.getStatusLine().getStatusCode();
- Logger.debug(LOG_TAG, "Failed to fetch user node, with status " + statusCode);
- aa.abort(AuthenticationResult.FAILURE_OTHER, new Exception("HTTP " + statusCode + " error."));
- }
-
- @Override
- public void handleError(Exception e) {
- Logger.debug(LOG_TAG, "Error in fetching node.");
- aa.abort(AuthenticationResult.FAILURE_OTHER, e);
- }
- };
- String nodeRequestUrl = Utils.nodeWeaveURL(aa.nodeServer, aa.username);
- // Might contain a plaintext username in the case of old Sync accounts.
- Logger.pii(LOG_TAG, "NodeUrl: " + nodeRequestUrl);
- final BaseResource httpResource = makeFetchNodeRequest(callbackDelegate, nodeRequestUrl);
- // Make request on separate thread.
- AccountAuthenticator.runOnThread(new Runnable() {
- @Override
- public void run() {
- httpResource.get();
- }
- });
- }
-
- private BaseResource makeFetchNodeRequest(final FetchNodeStageDelegate callbackDelegate, String fetchNodeUrl) throws URISyntaxException {
- // Fetch node containing user.
- final BaseResource httpResource = new BaseResource(fetchNodeUrl);
- httpResource.delegate = new BaseResourceDelegate(httpResource) {
- @Override
- public String getUserAgent() {
- return SyncConstants.USER_AGENT;
- }
-
- @Override
- public void handleHttpResponse(HttpResponse response) {
- int statusCode = response.getStatusLine().getStatusCode();
- switch(statusCode) {
- case 200:
- try {
- InputStream content = response.getEntity().getContent();
- BufferedReader reader = new BufferedReader(new InputStreamReader(content, "UTF-8"), 1024);
- String server = reader.readLine();
- callbackDelegate.handleSuccess(server);
- BaseResource.consumeReader(reader);
- reader.close();
- } catch (IllegalStateException | IOException e) {
- callbackDelegate.handleError(e);
- }
- break;
- case 404: // Does not support auth nodes, use server instead.
- callbackDelegate.handleSuccess(null);
- break;
- default:
- // No other acceptable states.
- callbackDelegate.handleFailure(response);
- }
- BaseResource.consumeEntity(response.getEntity());
- }
-
- @Override
- public void handleHttpProtocolException(ClientProtocolException e) {
- callbackDelegate.handleError(e);
- }
-
- @Override
- public void handleHttpIOException(IOException e) {
- callbackDelegate.handleError(e);
- }
-
- @Override
- public void handleTransportException(GeneralSecurityException e) {
- callbackDelegate.handleError(e);
- }
- };
- return httpResource;
- }
-}
\ No newline at end of file
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/syncadapter/SyncAdapter.java
+++ /dev/null
@@ -1,628 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.syncadapter;
-
-import java.io.IOException;
-import java.net.URI;
-import java.security.NoSuchAlgorithmException;
-import java.util.Collection;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.json.simple.parser.ParseException;
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.background.common.GlobalConstants;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.fxa.FxAccountConstants;
-import org.mozilla.gecko.sync.AlreadySyncingException;
-import org.mozilla.gecko.sync.BackoffHandler;
-import org.mozilla.gecko.sync.CredentialException;
-import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.PrefsBackoffHandler;
-import org.mozilla.gecko.sync.SharedPreferencesClientsDataDelegate;
-import org.mozilla.gecko.sync.SharedPreferencesNodeAssignmentCallback;
-import org.mozilla.gecko.sync.Sync11Configuration;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.SyncConfigurationException;
-import org.mozilla.gecko.sync.SyncConstants;
-import org.mozilla.gecko.sync.SyncException;
-import org.mozilla.gecko.sync.ThreadPool;
-import org.mozilla.gecko.sync.Utils;
-import org.mozilla.gecko.sync.config.AccountPickler;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.delegates.BaseGlobalSessionCallback;
-import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
-import org.mozilla.gecko.sync.net.ConnectionMonitorThread;
-import org.mozilla.gecko.sync.receivers.SyncAccountDeletedService;
-import org.mozilla.gecko.sync.setup.Constants;
-import org.mozilla.gecko.sync.setup.SyncAccounts;
-import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
-import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
-import android.content.AbstractThreadedSyncAdapter;
-import android.content.ContentProviderClient;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SyncResult;
-import android.database.sqlite.SQLiteConstraintException;
-import android.database.sqlite.SQLiteException;
-import android.os.Bundle;
-
-public class SyncAdapter extends AbstractThreadedSyncAdapter implements BaseGlobalSessionCallback {
- private static final String LOG_TAG = "SyncAdapter";
-
- private static final int BACKOFF_PAD_SECONDS = 5;
- public static final int MULTI_DEVICE_INTERVAL_MILLISECONDS = 5 * 60 * 1000; // 5 minutes.
- public static final int SINGLE_DEVICE_INTERVAL_MILLISECONDS = 24 * 60 * 60 * 1000; // 24 hours.
-
- private final Context mContext;
-
- protected long syncStartTimestamp;
-
- protected volatile BackoffHandler backoffHandler;
-
- public SyncAdapter(Context context, boolean autoInitialize) {
- super(context, autoInitialize);
- mContext = context;
- }
-
- /**
- * Handle an exception: update stats, log errors, etc.
- * Wakes up sleeping threads by calling notifyMonitor().
- *
- * @param globalSession
- * current global session, or null.
- * @param e
- * Exception to handle.
- */
- protected void processException(final GlobalSession globalSession, final Exception e) {
- try {
- if (e instanceof SQLiteConstraintException) {
- Logger.error(LOG_TAG, "Constraint exception. Aborting sync.", e);
- syncResult.stats.numParseExceptions++; // This is as good as we can do.
- return;
- }
- if (e instanceof SQLiteException) {
- Logger.error(LOG_TAG, "Couldn't open database (locked?). Aborting sync.", e);
- syncResult.stats.numIoExceptions++;
- return;
- }
- if (e instanceof OperationCanceledException) {
- Logger.error(LOG_TAG, "Operation canceled. Aborting sync.", e);
- return;
- }
- if (e instanceof AuthenticatorException) {
- syncResult.stats.numParseExceptions++;
- Logger.error(LOG_TAG, "AuthenticatorException. Aborting sync.", e);
- return;
- }
- if (e instanceof IOException) {
- syncResult.stats.numIoExceptions++;
- Logger.error(LOG_TAG, "IOException. Aborting sync.", e);
- e.printStackTrace();
- return;
- }
-
- // Blanket stats updating for SyncException subclasses.
- if (e instanceof SyncException) {
- ((SyncException) e).updateStats(globalSession, syncResult);
- } else {
- // Generic exception.
- syncResult.stats.numIoExceptions++;
- }
-
- if (e instanceof CredentialException.MissingAllCredentialsException) {
- // This is bad: either we couldn't fetch credentials, or the credentials
- // were totally blank. Most likely the user has two copies of Firefox
- // installed, and something is misbehaving.
- // Either way, disable this account.
- if (localAccount == null) {
- // Should not happen, but be safe.
- Logger.error(LOG_TAG, "No credentials attached to account. Aborting sync.");
- return;
- }
-
- Logger.error(LOG_TAG, "No credentials attached to account " + localAccount.name + ". Aborting sync.");
- try {
- SyncAccounts.setSyncAutomatically(localAccount, false);
- } catch (Exception ex) {
- Logger.error(LOG_TAG, "Unable to disable account " + localAccount.name + ".", ex);
- }
- return;
- }
-
- if (e instanceof CredentialException.MissingCredentialException) {
- Logger.error(LOG_TAG, "Credentials attached to account, but missing " +
- ((CredentialException.MissingCredentialException) e).missingCredential + ". Aborting sync.");
- return;
- }
-
- if (e instanceof CredentialException) {
- Logger.error(LOG_TAG, "Credentials attached to account were bad.");
- return;
- }
-
- // Bug 755638 - Uncaught SecurityException when attempting to sync multiple Fennecs
- // to the same Sync account.
- // Uncheck Sync checkbox because we cannot sync this instance.
- if (e instanceof SecurityException) {
- Logger.error(LOG_TAG, "SecurityException, multiple Fennecs. Disabling this instance.", e);
- SyncAccounts.backgroundSetSyncAutomatically(localAccount, false);
- return;
- }
- // Generic exception.
- Logger.error(LOG_TAG, "Unknown exception. Aborting sync.", e);
- } finally {
- notifyMonitor();
- }
- }
-
- @Override
- public void onSyncCanceled() {
- super.onSyncCanceled();
- // TODO: cancel the sync!
- // From the docs: "This will be invoked on a separate thread than the sync
- // thread and so you must consider the multi-threaded implications of the
- // work that you do in this method."
- }
-
- public Object syncMonitor = new Object();
- private SyncResult syncResult;
-
- protected Account localAccount;
- protected boolean thisSyncIsForced = false;
- protected SharedPreferences accountSharedPreferences;
- protected SharedPreferencesClientsDataDelegate clientsDataDelegate;
- protected SharedPreferencesNodeAssignmentCallback nodeAssignmentDelegate;
-
- /**
- * Request that no sync start right away. A new sync won't start until
- * at least <code>backoff</code> milliseconds from now.
- *
- * Don't call this unless you are inside `run`.
- *
- * @param backoff time to wait in milliseconds.
- */
- @Override
- public void requestBackoff(final long backoff) {
- if (this.backoffHandler == null) {
- throw new IllegalStateException("No backoff handler: requesting backoff outside run()?");
- }
- if (backoff > 0) {
- // Fuzz the backoff time (up to 25% more) to prevent client lock-stepping; agrees with desktop.
- final long fuzzedBackoff = backoff + Math.round(backoff * 0.25d * Math.random());
- this.backoffHandler.extendEarliestNextRequest(System.currentTimeMillis() + fuzzedBackoff);
- }
- }
-
- @Override
- public boolean shouldBackOffStorage() {
- if (thisSyncIsForced) {
- /*
- * If the user asks us to sync, we should sync regardless. This path is
- * hit if the user force syncs and we restart a session after a
- * freshStart.
- */
- return false;
- }
-
- if (nodeAssignmentDelegate.wantNodeAssignment()) {
- /*
- * We recently had a 401 and we aborted the last sync. We should kick off
- * another sync to fetch a new node/weave cluster URL, since ours is
- * stale. If we have a user authentication error, the next sync will
- * determine that and will stop requesting node assignment, so this will
- * only force one abnormally scheduled sync.
- */
- return false;
- }
-
- if (this.backoffHandler == null) {
- throw new IllegalStateException("No backoff handler: checking backoff outside run()?");
- }
- return this.backoffHandler.delayMilliseconds() > 0;
- }
-
- /**
- * Asynchronously request an immediate sync, optionally syncing only the given
- * named stages.
- * <p>
- * Returns immediately.
- *
- * @param account
- * the Android <code>Account</code> instance to sync.
- * @param stageNames
- * stage names to sync, or <code>null</code> to sync all known stages.
- */
- public static void requestImmediateSync(final Account account, final String[] stageNames) {
- requestImmediateSync(account, stageNames, null);
- }
-
- /**
- * Asynchronously request an immediate sync, optionally syncing only the given
- * named stages.
- * <p>
- * Returns immediately.
- *
- * @param account
- * the Android <code>Account</code> instance to sync.
- * @param stageNames
- * stage names to sync, or <code>null</code> to sync all known stages.
- * @param moreExtras
- * bundle of extras to give to the sync, or <code>null</code>
- */
- public static void requestImmediateSync(final Account account, final String[] stageNames, Bundle moreExtras) {
- if (account == null) {
- Logger.warn(LOG_TAG, "Not requesting immediate sync because Android Account is null.");
- return;
- }
-
- final Bundle extras = new Bundle();
- Utils.putStageNamesToSync(extras, stageNames, null);
- extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
-
- if (moreExtras != null) {
- extras.putAll(moreExtras);
- }
-
- ContentResolver.requestSync(account, BrowserContract.AUTHORITY, extras);
- }
-
- @Override
- public void onPerformSync(final Account account,
- final Bundle extras,
- final String authority,
- final ContentProviderClient provider,
- final SyncResult syncResult) {
- syncStartTimestamp = System.currentTimeMillis();
-
- Logger.setThreadLogTag(SyncConstants.GLOBAL_LOG_TAG);
- Logger.resetLogging();
- Utils.reseedSharedRandom(); // Make sure we don't work with the same random seed for too long.
-
- // Set these so that we don't need to thread them through assorted calls and callbacks.
- this.syncResult = syncResult;
- this.localAccount = account;
-
- final AccountManager manager = AccountManager.get(mContext);
- final SyncAccountParameters params;
- try {
- if ("1".equals(manager.getUserData(account, Constants.DATA_SHOULD_BE_REMOVED))) {
- Logger.warn(LOG_TAG, "Account named like " + Utils.obfuscateEmail(account.name) + " should be removed. " +
- "Removing and aborting sync.");
- manager.removeAccount(account, null, null);
- return;
- }
-
- params = SyncAccounts.blockingFromAndroidAccountV0(mContext, manager, this.localAccount);
- } catch (Exception e) {
- // Updates syncResult and (harmlessly) calls notifyMonitor().
- processException(null, e);
- return;
- }
-
- // params and the following fields are non-null at this point.
- final String username = params.username; // Encoded with Utils.usernameFromAccount.
- final String password = params.password;
- final String serverURL = params.serverURL;
- final String syncKey = params.syncKey;
-
- final AtomicBoolean setNextSync = new AtomicBoolean(true);
- final SyncAdapter self = this;
- final Runnable runnable = new Runnable() {
- @Override
- public void run() {
- Logger.trace(LOG_TAG, "AccountManagerCallback invoked.");
- // TODO: N.B.: Future must not be used on the main thread.
- try {
- if (Logger.LOG_PERSONAL_INFORMATION) {
- Logger.pii(LOG_TAG, "Syncing account named " + account.name +
- " for authority " + authority + ".");
- } else {
- // Replace "foo@bar.com" with "XXX@XXX.XXX".
- Logger.info(LOG_TAG, "Syncing account named like " + Utils.obfuscateEmail(account.name) +
- " for authority " + authority + ".");
- }
-
- // We dump this information right away to help with debugging.
- Logger.debug(LOG_TAG, "Username: " + username);
- Logger.debug(LOG_TAG, "Server: " + serverURL);
- if (Logger.LOG_PERSONAL_INFORMATION) {
- Logger.debug(LOG_TAG, "Password: " + password);
- Logger.debug(LOG_TAG, "Sync key: " + syncKey);
- } else {
- Logger.debug(LOG_TAG, "Password? " + (password != null));
- Logger.debug(LOG_TAG, "Sync key? " + (syncKey != null));
- }
-
- // Support multiple accounts by mapping each server/account pair to a branch of the
- // shared preferences space.
- final String product = GlobalConstants.BROWSER_INTENT_PACKAGE;
- final String profile = Constants.DEFAULT_PROFILE;
- final long version = SyncConfiguration.CURRENT_PREFS_VERSION;
- self.accountSharedPreferences = Utils.getSharedPreferences(mContext, product, username, serverURL, profile, version);
- self.clientsDataDelegate = new SharedPreferencesClientsDataDelegate(accountSharedPreferences, mContext);
- self.backoffHandler = new PrefsBackoffHandler(accountSharedPreferences, SyncConstants.BACKOFF_PREF_SUFFIX_11);
- final String nodeWeaveURL = Utils.nodeWeaveURL(serverURL, username);
- self.nodeAssignmentDelegate = new SharedPreferencesNodeAssignmentCallback(accountSharedPreferences, nodeWeaveURL);
-
- Logger.info(LOG_TAG,
- "Client is named '" + clientsDataDelegate.getClientName() + "'" +
- ", has client guid " + clientsDataDelegate.getAccountGUID() +
- ", and has " + clientsDataDelegate.getClientsCount() + " clients.");
-
- final boolean thisSyncIsForced = (extras != null) && (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false));
- final long delayMillis = backoffHandler.delayMilliseconds();
- boolean shouldSync = thisSyncIsForced || (delayMillis <= 0L);
- if (!shouldSync) {
- long remainingSeconds = delayMillis / 1000;
- syncResult.delayUntil = remainingSeconds + BACKOFF_PAD_SECONDS;
- setNextSync.set(false);
- self.notifyMonitor();
- return;
- }
-
- final String prefsPath = Utils.getPrefsPath(product, username, serverURL, profile, version);
- self.performSync(account, extras, authority, provider, syncResult,
- username, password, prefsPath, serverURL, syncKey);
- } catch (Exception e) {
- self.processException(null, e);
- return;
- }
- }
- };
-
- synchronized (syncMonitor) {
- // Perform the work in a new thread from within this synchronized block,
- // which allows us to be waiting on the monitor before the callback can
- // notify us in a failure case. Oh, concurrent programming.
- new Thread(runnable).start();
-
- // Start our stale connection monitor thread.
- ConnectionMonitorThread stale = new ConnectionMonitorThread();
- stale.start();
-
- Logger.trace(LOG_TAG, "Waiting on sync monitor.");
- try {
- syncMonitor.wait();
-
- if (setNextSync.get()) {
- long interval = getSyncInterval(clientsDataDelegate);
- long next = System.currentTimeMillis() + interval;
-
- if (thisSyncIsForced) {
- Logger.info(LOG_TAG, "Setting minimum next sync time to " + next + " (" + interval + "ms from now).");
- self.backoffHandler.setEarliestNextRequest(next);
- } else {
- Logger.info(LOG_TAG, "Extending minimum next sync time to " + next + " (" + interval + "ms from now).");
- self.backoffHandler.extendEarliestNextRequest(next);
- }
- }
- Logger.info(LOG_TAG, "Sync took " + Utils.formatDuration(syncStartTimestamp, System.currentTimeMillis()) + ".");
- } catch (InterruptedException e) {
- Logger.warn(LOG_TAG, "Waiting on sync monitor interrupted.", e);
- } finally {
- // And we're done with HTTP stuff.
- stale.shutdown();
- }
- }
- }
-
- public int getSyncInterval(ClientsDataDelegate clientsDataDelegate) {
- // Must have been a problem that means we can't access the Account.
- if (this.localAccount == null) {
- return SINGLE_DEVICE_INTERVAL_MILLISECONDS;
- }
-
- int clientsCount = clientsDataDelegate.getClientsCount();
- if (clientsCount <= 1) {
- return SINGLE_DEVICE_INTERVAL_MILLISECONDS;
- }
-
- return MULTI_DEVICE_INTERVAL_MILLISECONDS;
- }
-
- /**
- * Now that we have a sync key and password, go ahead and do the work.
- * @throws NoSuchAlgorithmException
- * @throws IllegalArgumentException
- * @throws SyncConfigurationException
- * @throws AlreadySyncingException
- * @throws NonObjectJSONException
- * @throws ParseException
- * @throws IOException
- * @throws CryptoException
- */
- protected void performSync(final Account account,
- final Bundle extras,
- final String authority,
- final ContentProviderClient provider,
- final SyncResult syncResult,
- final String username,
- final String password,
- final String prefsPath,
- final String serverURL,
- final String syncKey)
- throws NoSuchAlgorithmException,
- SyncConfigurationException,
- IllegalArgumentException,
- AlreadySyncingException,
- IOException, ParseException,
- NonObjectJSONException, CryptoException {
- Logger.trace(LOG_TAG, "Performing sync.");
-
- /**
- * Bug 769745: pickle Sync account parameters to JSON file. Un-pickle in
- * <code>SyncAccounts.syncAccountsExist</code>.
- */
- try {
- // Constructor can throw on nulls, which should not happen -- but let's be safe.
- final SyncAccountParameters params = new SyncAccountParameters(mContext, null,
- account.name, // Un-encoded, like "test@mozilla.com".
- syncKey,
- password,
- serverURL,
- null, // We'll re-fetch cluster URL; not great, but not harmful.
- clientsDataDelegate.getClientName(),
- clientsDataDelegate.getAccountGUID());
-
- // Bug 772971: pickle Sync account parameters on background thread to
- // avoid strict mode warnings.
- ThreadPool.run(new Runnable() {
- @Override
- public void run() {
- final boolean syncAutomatically = ContentResolver.getSyncAutomatically(account, authority);
- try {
- AccountPickler.pickle(mContext, Constants.ACCOUNT_PICKLE_FILENAME, params, syncAutomatically);
- } catch (Exception e) {
- // Should never happen, but we really don't want to die in a background thread.
- Logger.warn(LOG_TAG, "Got exception pickling current account details; ignoring.", e);
- }
- }
- });
- } catch (IllegalArgumentException e) {
- // Do nothing.
- }
-
- if (username == null) {
- throw new IllegalArgumentException("username must not be null.");
- }
-
- if (syncKey == null) {
- throw new SyncConfigurationException();
- }
-
- final KeyBundle keyBundle = new KeyBundle(username, syncKey);
-
- if (keyBundle == null ||
- keyBundle.getEncryptionKey() == null ||
- keyBundle.getHMACKey() == null) {
- throw new SyncConfigurationException();
- }
-
- final AuthHeaderProvider authHeaderProvider = new BasicAuthHeaderProvider(username, password);
- final SharedPreferences prefs = getContext().getSharedPreferences(prefsPath, Utils.SHARED_PREFERENCES_MODE);
- final SyncConfiguration config = new Sync11Configuration(username, authHeaderProvider, prefs, keyBundle);
-
- Collection<String> knownStageNames = SyncConfiguration.validEngineNames();
- config.stagesToSync = Utils.getStagesToSyncFromBundle(knownStageNames, extras);
-
- GlobalSession globalSession = new GlobalSession(config, this, this.mContext, clientsDataDelegate, nodeAssignmentDelegate);
- globalSession.start();
- }
-
- private void notifyMonitor() {
- synchronized (syncMonitor) {
- Logger.trace(LOG_TAG, "Notifying sync monitor.");
- syncMonitor.notifyAll();
- }
- }
-
- // Implementing GlobalSession callbacks.
- @Override
- public void handleError(GlobalSession globalSession, Exception ex) {
- Logger.info(LOG_TAG, "GlobalSession indicated error.");
- this.processException(globalSession, ex);
- }
-
- @Override
- public void handleAborted(GlobalSession globalSession, String reason) {
- Logger.warn(LOG_TAG, "Sync aborted: " + reason);
- notifyMonitor();
- }
-
- @Override
- public void handleSuccess(GlobalSession globalSession) {
- Logger.info(LOG_TAG, "GlobalSession indicated success.");
- globalSession.config.persistToPrefs();
- notifyMonitor();
- }
-
- @Override
- public void handleStageCompleted(Stage currentState,
- GlobalSession globalSession) {
- Logger.trace(LOG_TAG, "Stage completed: " + currentState);
- }
-
- @Override
- public void informUnauthorizedResponse(GlobalSession session, URI oldClusterURL) {
- nodeAssignmentDelegate.setClusterURLIsStale(true);
- }
-
- @Override
- public void informUpgradeRequiredResponse(final GlobalSession session) {
- final AccountManager manager = AccountManager.get(mContext);
- final Account toDisable = localAccount;
- if (toDisable == null || manager == null) {
- Logger.warn(LOG_TAG, "Attempting to disable account, but null found.");
- return;
- }
- // Sync needs to be upgraded. Don't automatically sync anymore.
- ThreadPool.run(new Runnable() {
- @Override
- public void run() {
- manager.setUserData(toDisable, Constants.DATA_ENABLE_ON_UPGRADE, "1");
- SyncAccounts.setSyncAutomatically(toDisable, false);
- }
- });
- }
-
- @Override
- public void informMigrated(GlobalSession session) {
- final AccountManager manager = AccountManager.get(mContext);
- final Account account = localAccount;
- if (account == null || manager == null) {
- Logger.warn(LOG_TAG, "Attempting to mark account migrated, but no Account or AccountManager found.");
- return;
- }
-
- // Mark the account as slated for deletion. We're going to try to wipe the
- // account right now anyway, but if we fail, or a sync is triggered before
- // we succeed, the next sync will see this flag, try to delete the account,
- // and abort the sync.
- manager.setUserData(account, Constants.DATA_SHOULD_BE_REMOVED, "1");
-
- // We delete any existing pickle as soon as possible -- no sense unpickling
- // an account scheduled for deletion.
- SyncAccountDeletedService.deletePickle(mContext);
-
- // We write an escape hatch pickle of the Old Sync Account parameters,
- // just in case.
- try {
- final SyncAccountParameters params =
- SyncAccounts.blockingFromAndroidAccountV0(mContext, manager, account);
- AccountPickler.pickle(mContext, FxAccountConstants.OLD_SYNC_ACCOUNT_PICKLE_FILENAME, params, false);
- } catch (Exception e) {
- Logger.error(LOG_TAG, "Failed to pickle old Account; removing old Account without emergency pickle.", e);
- }
-
- // Try to remove this account entirely. We can't *guarantee* the account
- // will be removed, but it's a good deal of effort to retry over time. An
- // option would be to have the new Account we've migrated to try to clean up
- // the old Account as well; we'll do that if we see problems in the wild.
- try {
- manager.removeAccount(account, null, null);
- } catch (Exception e) {
- // We should always be able to remove the Account, but it's Android --
- // is one ever confident? We log, but crash for non-release builds.
- // We want to know if we see problems in the wild.
- if (AppConstants.RELEASE_BUILD) {
- Logger.error(LOG_TAG, "Failed to remove account; ignoring and leaving old Account.", e);
- } else {
- Logger.error(LOG_TAG, "Failed to remove account; crashing.", e);
- throw e;
- }
- }
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/syncadapter/SyncService.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.sync.syncadapter;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.IBinder;
-
-/**
- * Service to handle Account sync. This is invoked with an intent with action
- * ACTION_AUTHENTICATOR_INTENT. It instantiates the SyncAdaptor and returns its
- * IBinder.
- */
-public class SyncService extends Service {
-
- private static final Object sSyncAdapterLock = new Object();
-
- private static SyncAdapter sSyncAdapter = null;
-
- @Override
- public void onCreate() {
- synchronized (sSyncAdapterLock) {
- if (sSyncAdapter == null) {
- sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
- }
- }
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return sSyncAdapter.getSyncAdapterBinder();
- }
-}
--- a/mobile/android/tests/background/junit3/background_junit3_sources.mozbuild
+++ b/mobile/android/tests/background/junit3/background_junit3_sources.mozbuild
@@ -61,25 +61,23 @@ background_junit3_sources = [
'src/org/mozilla/gecko/background/sync/helpers/SessionTestHelper.java',
'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessBeginDelegate.java',
'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessCreationDelegate.java',
'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFetchDelegate.java',
'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessFinishDelegate.java',
'src/org/mozilla/gecko/background/sync/helpers/SimpleSuccessStoreDelegate.java',
'src/org/mozilla/gecko/background/sync/TestClientsStage.java',
'src/org/mozilla/gecko/background/sync/TestResetting.java',
- 'src/org/mozilla/gecko/background/sync/TestSendTabData.java',
'src/org/mozilla/gecko/background/sync/TestStoreTracking.java',
'src/org/mozilla/gecko/background/sync/TestSyncConfiguration.java',
'src/org/mozilla/gecko/background/sync/TestTabsRecord.java',
'src/org/mozilla/gecko/background/sync/TestWebURLFinder.java',
'src/org/mozilla/gecko/background/testhelpers/BaseMockServerSyncStage.java',
'src/org/mozilla/gecko/background/testhelpers/CommandHelpers.java',
'src/org/mozilla/gecko/background/testhelpers/DefaultGlobalSessionCallback.java',
- 'src/org/mozilla/gecko/background/testhelpers/JPakeNumGeneratorFixed.java',
'src/org/mozilla/gecko/background/testhelpers/MockAbstractNonRepositorySyncStage.java',
'src/org/mozilla/gecko/background/testhelpers/MockClientsDatabaseAccessor.java',
'src/org/mozilla/gecko/background/testhelpers/MockClientsDataDelegate.java',
'src/org/mozilla/gecko/background/testhelpers/MockGlobalSession.java',
'src/org/mozilla/gecko/background/testhelpers/MockPrefsGlobalSession.java',
'src/org/mozilla/gecko/background/testhelpers/MockRecord.java',
'src/org/mozilla/gecko/background/testhelpers/MockServerSyncStage.java',
'src/org/mozilla/gecko/background/testhelpers/MockSharedPreferences.java',
--- a/mobile/android/tests/background/junit3/instrumentation.ini
+++ b/mobile/android/tests/background/junit3/instrumentation.ini
@@ -17,13 +17,12 @@ subsuite = background
[src/org/mozilla/gecko/background/db/TestFennecTabsStorage.java]
[src/org/mozilla/gecko/background/db/TestFormHistoryRepositorySession.java]
[src/org/mozilla/gecko/background/db/TestPasswordsRepository.java]
[src/org/mozilla/gecko/background/fxa/TestBrowserIDKeyPairGeneration.java]
[src/org/mozilla/gecko/background/fxa/authenticator/TestAccountPickler.java]
[src/org/mozilla/gecko/background/nativecode/test/TestNativeCrypto.java]
[src/org/mozilla/gecko/background/sync/TestClientsStage.java]
[src/org/mozilla/gecko/background/sync/TestResetting.java]
-[src/org/mozilla/gecko/background/sync/TestSendTabData.java]
[src/org/mozilla/gecko/background/sync/TestStoreTracking.java]
[src/org/mozilla/gecko/background/sync/TestSyncConfiguration.java]
[src/org/mozilla/gecko/background/sync/TestTabsRecord.java]
[src/org/mozilla/gecko/background/sync/TestWebURLFinder.java]
deleted file mode 100644
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/sync/TestSendTabData.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.sync;
-
-import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
-import org.mozilla.gecko.sync.setup.activities.SendTabData;
-
-import android.content.Intent;
-
-/**
- * These tests are on device because the Intent, Pattern, and Matcher APIs are
- * stubs on desktop.
- */
-public class TestSendTabData extends AndroidSyncTestCase {
- protected static Intent makeShareIntent(String text, String subject, String title) {
- Intent intent = new Intent();
-
- intent.putExtra(Intent.EXTRA_TEXT, text);
- intent.putExtra(Intent.EXTRA_SUBJECT, subject);
- intent.putExtra(Intent.EXTRA_TITLE, title);
-
- return intent;
- }
-
- // From Fennec:
- //
- // I/FxSync ( 7420): fennec :: SendTabActivity :: Send was clicked.
- // I/FxSync ( 7420): fennec :: SendTabActivity :: android.intent.extra.TEXT -> http://www.reddit.com/
- // I/FxSync ( 7420): fennec :: SendTabActivity :: android.intent.extra.SUBJECT -> reddit: the front page of the internet
- public void testFennecBrowser() {
- Intent shareIntent = makeShareIntent("http://www.reddit.com/",
- "reddit: the front page of the internet",
- null);
- SendTabData fromIntent = SendTabData.fromIntent(shareIntent);
-
- assertEquals("reddit: the front page of the internet", fromIntent.title);
- assertEquals("http://www.reddit.com/", fromIntent.uri);
- }
-
- // From Android Browser:
- //
- // I/FxSync ( 7420): fennec :: SendTabActivity :: Send was clicked.
- // I/FxSync ( 7420): fennec :: SendTabActivity :: android.intent.extra.TEXT -> http://bl176w.blu176.mail.live.com/m/messages.m/?mid=m95277577-e5a5-11e1-bfeb-00237de49bb0&mts=2012-08-14T00%3a18%3a44.390Z&fid=00000000-0000-0000-0000-000000000001&iru=%2fm%2ffolders.m%2f&pmid=m173216c1-e5ea-11e1-bac7-002264c17c66&pmts=2012-08-14T08%3a29%3a01.057Z&nmid=m0e0a4a3a-e511-11e1-bfe5-00237de3362a&nmts=2012-08-13T06%3a44%3a51.910Z
- // I/FxSync ( 7420): fennec :: SendTabActivity :: android.intent.extra.SUBJECT -> Hotmail: ONLY SIX PERFORMANCES LEFT! SPECIAL SECOND SHOW OFFER - GET $
- public void testAndroidBrowser() {
- Intent shareIntent = makeShareIntent("http://www.reddit.com/",
- "reddit: the front page of the internet",
- null);
- SendTabData fromIntent = SendTabData.fromIntent(shareIntent);
-
- assertEquals("reddit: the front page of the internet", fromIntent.title);
- assertEquals("http://www.reddit.com/", fromIntent.uri);
- }
-
- // From Pocket:
- //
- // I/FxSync ( 7420): fennec :: SendTabActivity :: Send was clicked.
- // I/FxSync ( 7420): fennec :: SendTabActivity :: android.intent.extra.TEXT -> http://t.co/bfsbM2oV
- // I/FxSync ( 7420): fennec :: SendTabActivity :: android.intent.extra.SUBJECT -> Launching the Canadian OGP Civil Society Discussion Group
- // I/FxSync ( 7420): fennec :: SendTabActivity :: android.intent.extra.TITLE -> Launching the Canadian OGP Civil Society Discussion Group
- public void testPocket() {
- Intent shareIntent = makeShareIntent("http://t.co/bfsbM2oV",
- "Launching the Canadian OGP Civil Society Discussion Group",
- "Launching the Canadian OGP Civil Society Discussion Group");
- SendTabData fromIntent = SendTabData.fromIntent(shareIntent);
-
- assertEquals("Launching the Canadian OGP Civil Society Discussion Group", fromIntent.title);
- assertEquals("http://t.co/bfsbM2oV", fromIntent.uri);
- }
-
- // A couple of examples from Twitter App:
- //
- // I/FxSync ( 7420): fennec :: SendTabActivity :: Send was clicked.
- // I/FxSync (17610): fennec :: SendTabActivity :: android.intent.extra.TEXT = Cory Doctorow (@doctorow) tweeted at 11:21 AM on Sat, Jan 12, 2013:
- // I/FxSync (17610): Pls RT: @lessig on the DoJ's vindictive prosecution of Aaron Swartz http://t.co/qNalE70n #aaronsw
- // I/FxSync (17610): (https://twitter.com/doctorow/status/290176681065451520)
- // I/FxSync (17610):
- // I/FxSync (17610): Get the official Twitter app at https://twitter.com/download
- // I/FxSync (17610): fennec :: SendTabActivity :: android.intent.extra.SUBJECT = Tweet from Cory Doctorow (@doctorow)
- //
- // I/FxSync ( 7420): fennec :: SendTabActivity :: Send was clicked.
- // I/FxSync ( 7420): fennec :: SendTabActivity :: android.intent.extra.TEXT -> David Eaves (@daeaves) tweeted at 0:08 PM on Fri, Jan 11, 2013:
- // I/FxSync ( 7420): New on eaves.ca: Launching the Canadian OGP Civil Society Discussion Group http://t.co/bfsbM2oV
- // I/FxSync ( 7420): (https://twitter.com/daeaves/status/289826143723466752)
- // I/FxSync ( 7420):
- // I/FxSync ( 7420): Get the official Twitter app at https://twitter.com/download
- // I/FxSync ( 7420): fennec :: SendTabActivity :: android.intent.extra.SUBJECT -> Tweet from David Eaves (@daeaves)
- public void testTwitter() {
- Intent shareIntent1 = makeShareIntent("Cory Doctorow (@doctorow) tweeted at 11:21 AM on Sat, Jan 12, 2013:\n" +
- "Pls RT: @lessig on the DoJ's vindictive prosecution of Aaron Swartz http://t.co/qNalE70n #aaronsw\n" +
- "(https://twitter.com/doctorow/status/290176681065451520)\n" +
- "\n" +
- "Get the official Twitter app at https://twitter.com/download",
- "Tweet from Cory Doctorow (@doctorow)",
- null);
- SendTabData fromIntent1 = SendTabData.fromIntent(shareIntent1);
-
- assertEquals("Tweet from Cory Doctorow (@doctorow)", fromIntent1.title);
- assertEquals("http://t.co/qNalE70n", fromIntent1.uri);
-
- Intent shareIntent2 = makeShareIntent("David Eaves (@daeaves) tweeted at 0:08 PM on Fri, Jan 11, 2013:\n" +
- "New on eaves.ca: Launching the Canadian OGP Civil Society Discussion Group http://t.co/bfsbM2oV\n" +
- "(https://twitter.com/daeaves/status/289826143723466752)\n" +
- "\n" +
- "Get the official Twitter app at https://twitter.com/download",
- "Tweet from David Eaves (@daeaves)",
- null);
- SendTabData fromIntent2 = SendTabData.fromIntent(shareIntent2);
-
- assertEquals("Tweet from David Eaves (@daeaves)", fromIntent2.title);
- assertEquals("http://t.co/bfsbM2oV", fromIntent2.uri);
- }
-}
deleted file mode 100644
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/testhelpers/JPakeNumGeneratorFixed.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import java.math.BigInteger;
-
-import org.mozilla.gecko.sync.jpake.JPakeNumGenerator;
-
-public class JPakeNumGeneratorFixed implements JPakeNumGenerator {
- private String[] values;
- private int index = 0;
-
- public JPakeNumGeneratorFixed(String[] values) {
- this.values = values;
- }
-
- @Override
- public BigInteger generateFromRange(BigInteger r) {
- BigInteger ret = new BigInteger(values[index], 16).mod(r);
- index = (++index) % values.length;
- return ret;
- }
-}
deleted file mode 100644
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/net/test/TestAccountAuthenticatorStage.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.android.sync.net.test;
-
-import ch.boye.httpclientandroidlib.HttpResponse;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.android.sync.test.helpers.HTTPServerTestHelper;
-import org.mozilla.android.sync.test.helpers.MockServer;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.background.testhelpers.WaitHelper;
-import org.mozilla.gecko.sync.setup.auth.AuthenticateAccountStage;
-import org.mozilla.gecko.sync.setup.auth.AuthenticateAccountStage.AuthenticateAccountStageDelegate;
-import org.simpleframework.http.Request;
-import org.simpleframework.http.Response;
-
-import java.io.IOException;
-import java.io.PrintStream;
-import java.net.URISyntaxException;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-/**
- * Tests the authentication request stage of manual Account setup.
- * @author liuche
- *
- */
-@RunWith(TestRunner.class)
-public class TestAccountAuthenticatorStage {
- private static final int TEST_PORT = HTTPServerTestHelper.getTestPort();
- private static final String TEST_SERVER = "http://localhost:" + TEST_PORT;
-
- private static final String USERNAME = "john-hashed";
- private static final String PASSWORD = "password";
-
- private MockServer authServer;
- private HTTPServerTestHelper serverHelper = new HTTPServerTestHelper();
- private AuthenticateAccountStage authStage = new AuthenticateAccountStage();
- private AuthenticateAccountStageDelegate testCallback;
-
- @Before
- public void setup() {
- // Make mock server to check authentication header.
- authServer = new MockServer() {
- @Override
- protected void handle(Request request, Response response, int code, String body) {
- try {
- final int c;
- String responseAuth = request.getValue("Authorization");
- // Trim whitespace, HttpResponse has an extra space?
- if (expectedBasicAuthHeader.equals(responseAuth.trim())) {
- c = 200;
- } else {
- c = 401;
- }
-
- Logger.debug(LOG_TAG, "Handling request...");
- PrintStream bodyStream = this.handleBasicHeaders(request, response, c, "application/json");
- bodyStream.println(body);
- bodyStream.close();
- } catch (IOException e) {
- Logger.error(LOG_TAG, "Oops.", e);
- }
- }
- };
- authServer.expectedBasicAuthHeader = authStage.makeAuthHeader(USERNAME, PASSWORD);
-
- // Authentication delegate to handle HTTP responses.
- testCallback = new AuthenticateAccountStageDelegate() {
- protected int numFailedTries = 0;
-
- @Override
- public void handleSuccess(boolean isSuccess) {
- if (isSuccess) {
- // Succeed on retry (after failing first attempt).
- assertEquals(1, numFailedTries);
- testWaiter().performNotify();
- } else {
- numFailedTries++;
- // Fail only once.
- if (numFailedTries != 1) {
- testWaiter().performNotify(new Exception("Failed on retry."));
- return;
- }
- String authHeader = authStage.makeAuthHeader(USERNAME, PASSWORD);
- try {
- authStage.authenticateAccount(testCallback, TEST_SERVER, authHeader);
- } catch (URISyntaxException e) {
- fail("Malformed URI.");
- }
- }
- }
-
- @Override
- public void handleFailure(HttpResponse response) {
- fail("Unexpected response " + response.getStatusLine().getStatusCode());
- }
-
- @Override
- public void handleError(Exception e) {
- fail("Unexpected error during authentication.");
- }
- };
- assertTrue(testWaiter().isIdle());
-
- }
-
- @After
- public void cleanup() {
- serverHelper.stopHTTPServer();
- assertTrue(testWaiter().isIdle());
- }
-
- @Test
- public void testAuthenticationRetry() {
- serverHelper.startHTTPServer(authServer);
- testWaiter().performWait(new Runnable() {
- @Override
- public void run() {
- // Try auth request with incorrect password. We want to fail the first time.
- String authHeader = authStage.makeAuthHeader(USERNAME, "wrong-password");
- try {
- authStage.authenticateAccount(testCallback, TEST_SERVER, authHeader);
- } catch (URISyntaxException e) {
- fail("Malformed URI.");
- }
- }
- });
- }
-
- protected static WaitHelper testWaiter() {
- return WaitHelper.getTestWaiter();
- }
-}
deleted file mode 100644
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestJPakeSetup.java
+++ /dev/null
@@ -1,262 +0,0 @@
-package org.mozilla.android.sync.test;
-
-import org.json.simple.parser.ParseException;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mozilla.apache.commons.codec.binary.Base64;
-import org.mozilla.gecko.background.testhelpers.TestRunner;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.crypto.CryptoException;
-import org.mozilla.gecko.sync.crypto.KeyBundle;
-import org.mozilla.gecko.sync.jpake.Gx3OrGx4IsZeroOrOneException;
-import org.mozilla.gecko.sync.jpake.IncorrectZkpException;
-import org.mozilla.gecko.sync.jpake.JPakeClient;
-import org.mozilla.gecko.sync.jpake.JPakeCrypto;
-import org.mozilla.gecko.sync.jpake.JPakeNumGenerator;
-import org.mozilla.gecko.sync.jpake.JPakeNumGeneratorRandom;
-import org.mozilla.gecko.sync.jpake.JPakeParty;
-import org.mozilla.gecko.sync.jpake.stage.ComputeKeyVerificationStage;
-import org.mozilla.gecko.sync.jpake.stage.VerifyPairingStage;
-import org.mozilla.gecko.sync.setup.Constants;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.math.BigInteger;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-@RunWith(TestRunner.class)
-public class TestJPakeSetup {
- // Note: will throw NullPointerException if aborts. Only use stateless public
- // methods.
-
- @Test
- public void testGx3OrGx4ZeroOrOneThrowsException()
- throws UnsupportedEncodingException
- {
- JPakeNumGeneratorRandom gen = new JPakeNumGeneratorRandom();
- JPakeParty p = new JPakeParty("foobar");
- BigInteger secret = JPakeClient.secretAsBigInteger("secret");
-
- p.gx4 = new BigInteger("2");
- p.gx3 = new BigInteger("0");
- try {
- JPakeCrypto.round2(secret, p, gen);
- fail("round2 should fail if gx3 == 0");
- } catch (Gx3OrGx4IsZeroOrOneException e) {
- // Hurrah.
- } catch (Exception e) {
- fail("Unexpected exception " + e);
- }
-
- p.gx3 = new BigInteger("1");
- try {
- JPakeCrypto.round2(secret, p, gen);
- fail("round2 should fail if gx3 == 1");
- } catch (Gx3OrGx4IsZeroOrOneException e) {
- // Hurrah.
- } catch (Exception e) {
- fail("Unexpected exception " + e);
- }
-
- p.gx3 = new BigInteger("3");
- try {
- JPakeCrypto.round2(secret, p, gen);
- } catch (Gx3OrGx4IsZeroOrOneException e) {
- fail("Unexpected exception " + e);
- } catch (Exception e) {
- // There are plenty of other reasons this should fail.
- }
-
- p.gx3 = new BigInteger("2");
- p.gx4 = new BigInteger("0");
- try {
- JPakeCrypto.round2(secret, p, gen);
- fail("round2 should fail if gx4 == 0");
- } catch (Gx3OrGx4IsZeroOrOneException e) {
- // Hurrah.
- } catch (Exception e) {
- fail("Unexpected exception " + e);
- }
-
- p.gx4 = new BigInteger("1");
- try {
- JPakeCrypto.round2(secret, p, gen);
- fail("round2 should fail if gx4 == 1");
- } catch (Gx3OrGx4IsZeroOrOneException e) {
- // Hurrah.
- } catch (Exception e) {
- fail("Unexpected exception " + e);
- }
-
- p.gx4 = new BigInteger("3");
- try {
- JPakeCrypto.round2(secret, p, gen);
- } catch (Gx3OrGx4IsZeroOrOneException e) {
- fail("Unexpected exception " + e);
- } catch (Exception e) {
- // There are plenty of other reasons this should fail.
- }
- }
-
- /*
- * Tests encryption key and hmac generation from a derived key, using values
- * taken from a successful run of J-PAKE.
- */
- @Test
- public void testKeyDerivation() throws UnsupportedEncodingException {
- String keyChars16 = "811565455b22c857a3e303d1f48ff72ae9ef42d9c3fe3740ce7772cb5bfe23491dd5b7ee5af4828ab9b7d5844866f378b4cf0156810aff0504ef2947402e8e40be1179cf7f37b231bc0db9e4e1bb239c849aa5c12ed2b0b4413017599270aae71ee993dd755ee8c045c5fe03d713894692bf72158d9835ad905442edfd8235e1d0c915053debfc49d8248e4dae16608743aef5dab061f49fd6edd0b93ecdf9feafcbe47eb7e6c3678356d96e9bcd87814b13b9eb1a791fd446d69cb040ec7d7194031267e26f266ee3decbc1a85c5203427361997adf9823fbffe16af9946f1347c5354956356732e436ef5f8307e96554cf69a54e4e8a78552e3f506e9310a1c4438d3ddce44a37482270533e47fc40dc84abfe39c1f95328d0d2540074f6301d4f121c2f0eac49c47a2c430614234ca26dede2a429e2fdb6d282a85174886c3a68c3cf5edc87ccb82af4ae4a9a26fffadc7f4d8ded4ff47b3d2d171f374b230e52e6b45963d3a0a6b20cbe6a440fd4a932279d52a6fd7694b4cbc0cb67ff3c";
- String expectedEncKey64 = "3TXwVlWf6YbuIPcg8m/2U4UXYV4a8RNu6pE2GOVkJJo=";
- String expectedHmac64 = "L49fnEPAD31G5uEKy5e4bGZ6IF3G/62qW6Ua/1NvBeQ=";
-
- byte[] encKeyBytes = new byte[32];
- byte[] hmacBytes = new byte[32];
-
- try {
- JPakeCrypto.generateKeyAndHmac(new BigInteger(keyChars16, 16), encKeyBytes, hmacBytes);
- } catch (Exception e) {
- fail("Unexpected exception " + e);
- }
- String encKey64 = new String(Base64.encodeBase64(encKeyBytes));
- String hmac64 = new String(Base64.encodeBase64(hmacBytes));
-
- assertTrue(expectedEncKey64.equals(encKey64));
- assertTrue(expectedHmac64.equals(hmac64));
- }
-
- /*
- * Test correct key derivation when both parties share a secret.
- */
- @Test
- public void testJPakeCorrectSecret() throws Gx3OrGx4IsZeroOrOneException,
- IncorrectZkpException, IOException, ParseException,
- NonObjectJSONException, CryptoException, NoSuchAlgorithmException, InvalidKeyException {
- BigInteger secret = JPakeClient.secretAsBigInteger("byubd7u75qmq");
- JPakeNumGenerator gen = new JPakeNumGeneratorRandom();
- // Keys derived should be the same.
- assertTrue(jPakeDeriveSameKey(gen, gen, secret, secret));
- }
-
- /*
- * Test incorrect key derivation when parties do not share the same secret.
- */
- @Test
- public void testJPakeIncorrectSecret() throws Gx3OrGx4IsZeroOrOneException,
- IncorrectZkpException, IOException, ParseException,
- NonObjectJSONException, CryptoException, NoSuchAlgorithmException, InvalidKeyException {
- BigInteger secret1 = JPakeClient.secretAsBigInteger("shareSecret1");
- BigInteger secret2 = JPakeClient.secretAsBigInteger("shareSecret2");
- JPakeNumGenerator gen = new JPakeNumGeneratorRandom();
- // Unsuccessful key derivation.
- assertFalse(jPakeDeriveSameKey(gen, gen, secret1, secret2));
- }
-
- /*
- * Helper simulation of a J-PAKE key derivation between two parties, with
- * secret1 and secret2. Both parties are assumed to be communicating on the
- * same channel; otherwise, J-PAKE would have failed immediately.
- */
- public boolean jPakeDeriveSameKey(JPakeNumGenerator gen1,
- JPakeNumGenerator gen2, BigInteger secret1, BigInteger secret2)
- throws IncorrectZkpException, Gx3OrGx4IsZeroOrOneException, IOException,
- ParseException, NonObjectJSONException, CryptoException, NoSuchAlgorithmException, InvalidKeyException {
-
- // Communicating parties.
- JPakeParty party1 = new JPakeParty("party1");
- JPakeParty party2 = new JPakeParty("party2");
-
- JPakeCrypto.round1(party1, gen1);
- // After party1 round 1, these values should no longer be null.
- assertNotNull(party1.signerId);
- assertNotNull(party1.x2);
- assertNotNull(party1.gx1);
- assertNotNull(party1.gx2);
- assertNotNull(party1.zkp1);
- assertNotNull(party1.zkp2);
- assertNotNull(party1.zkp1.b);
- assertNotNull(party1.zkp1.gr);
- assertNotNull(party1.zkp1.id);
- assertNotNull(party1.zkp2.b);
- assertNotNull(party1.zkp2.gr);
- assertNotNull(party1.zkp2.id);
-
- // party2 receives the following values from party1.
- party2.gx3 = party1.gx1;
- party2.gx4 = party1.gx2;
- party2.zkp3 = party1.zkp1;
- party2.zkp4 = party1.zkp2;
- // TODO Run JPakeClient checks.
-
- JPakeCrypto.round1(party2, gen2);
- // After party2 round 1, these values should no longer be null.
- assertNotNull(party2.signerId);
- assertNotNull(party2.x2);
- assertNotNull(party2.gx1);
- assertNotNull(party2.gx2);
- assertNotNull(party2.zkp1);
- assertNotNull(party2.zkp2);
- assertNotNull(party2.zkp1.b);
- assertNotNull(party2.zkp1.gr);
- assertNotNull(party2.zkp1.id);
- assertNotNull(party2.zkp2.b);
- assertNotNull(party2.zkp2.gr);
- assertNotNull(party2.zkp2.id);
-
- // Pass relevant values to party1.
- party1.gx3 = party2.gx1;
- party1.gx4 = party2.gx2;
- party1.zkp3 = party2.zkp1;
- party1.zkp4 = party2.zkp2;
- // TODO Run JPakeClient checks.
-
- JPakeCrypto.round2(secret1, party1, gen1);
- // After party1 round 2, these values should no longer be null.
- assertNotNull(party1.thisA);
- assertNotNull(party1.thisZkpA);
- assertNotNull(party1.thisZkpA.b);
- assertNotNull(party1.thisZkpA.gr);
- assertNotNull(party1.thisZkpA.id);
-
- // Pass relevant values to party2.
- party2.otherA = party1.thisA;
- party2.otherZkpA = party1.thisZkpA;
-
- JPakeCrypto.round2(secret2, party2, gen2);
- // Check for nulls.
- assertNotNull(party2.thisA);
- assertNotNull(party2.thisZkpA);
- assertNotNull(party2.thisZkpA.b);
- assertNotNull(party2.thisZkpA.gr);
- assertNotNull(party2.thisZkpA.id);
-
- // Pass values to party1.
- party1.otherA = party2.thisA;
- party1.otherZkpA = party2.thisZkpA;
-
- KeyBundle keyBundle1 = JPakeCrypto.finalRound(secret1, party1);
- assertNotNull(keyBundle1);
-
- // party1 computes the shared key, generates an encrypted message to party2.
- ExtendedJSONObject verificationMsg = new ComputeKeyVerificationStage()
- .computeKeyVerification(keyBundle1, party1.signerId);
- ExtendedJSONObject payload = verificationMsg
- .getObject(Constants.JSON_KEY_PAYLOAD);
- String ciphertext1 = (String) payload.get(Constants.JSON_KEY_CIPHERTEXT);
- String iv1 = (String) payload.get(Constants.JSON_KEY_IV);
-
- // party2 computes the key as well, using its copy of the secret.
- KeyBundle keyBundle2 = JPakeCrypto.finalRound(secret2, party2);
- // party2 fetches the encrypted message and verifies the pairing against its
- // own derived key.
-
- boolean isSuccess = new VerifyPairingStage().verifyCiphertext(ciphertext1, iv1,
- keyBundle2);
- return isSuccess;
- }
-}
deleted file mode 100644
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/JPakeNumGeneratorFixed.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-package org.mozilla.gecko.background.testhelpers;
-
-import org.mozilla.gecko.sync.jpake.JPakeNumGenerator;
-
-import java.math.BigInteger;
-
-public class JPakeNumGeneratorFixed implements JPakeNumGenerator {
- private String[] values;
- private int index = 0;
-
- public JPakeNumGeneratorFixed(String[] values) {
- this.values = values;
- }
-
- @Override
- public BigInteger generateFromRange(BigInteger r) {
- BigInteger ret = new BigInteger(values[index], 16).mod(r);
- index = (++index) % values.length;
- return ret;
- }
-}