--- a/mobile/android/base/android-services.mozbuild
+++ b/mobile/android/base/android-services.mozbuild
@@ -865,18 +865,16 @@ sync_java_files = [TOPSRCDIR + '/mobile/
'fxa/sync/SchedulePolicy.java',
'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/ClientRecordTerminator.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',
@@ -1020,17 +1018,16 @@ sync_java_files = [TOPSRCDIR + '/mobile/
'sync/repositories/StoreTracker.java',
'sync/repositories/StoreTrackingRepositorySession.java',
'sync/Server11PreviousPostFailedException.java',
'sync/Server11RecordPostFailedException.java',
'sync/setup/activities/ActivityUtils.java',
'sync/setup/activities/WebURLFinder.java',
'sync/setup/Constants.java',
'sync/setup/InvalidSyncKeyException.java',
- 'sync/setup/SyncAccounts.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',
--- a/mobile/android/base/java/org/mozilla/gecko/widget/ActivityChooserModel.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/ActivityChooserModel.java
@@ -26,17 +26,16 @@ import android.content.pm.PackageManager
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.db.TabsAccessor;
import org.mozilla.gecko.distribution.Distribution;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.fxa.FirefoxAccounts;
import org.mozilla.gecko.fxa.SyncStatusListener;
import org.mozilla.gecko.overlays.ui.ShareDialog;
-import org.mozilla.gecko.sync.setup.SyncAccounts;
import org.mozilla.gecko.R;
import java.io.File;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/AccountLoader.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/AccountLoader.java
@@ -1,16 +1,15 @@
/* 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.fxa;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
-import org.mozilla.gecko.sync.setup.SyncAccounts;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/SyncConstants.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/SyncConstants.java
@@ -12,48 +12,9 @@ public class SyncConstants {
public static final String SYNC_MINOR_VERSION = "0";
public static final String SYNC_VERSION_STRING = SYNC_MAJOR_VERSION + "." +
AppConstants.MOZ_APP_VERSION + "." +
SYNC_MINOR_VERSION;
public static final String USER_AGENT = "Firefox AndroidSync " +
SYNC_VERSION_STRING + " (" +
AppConstants.MOZ_APP_UA_NAME + ")";
-
- public static final String ACCOUNTTYPE_SYNC = AppConstants.MOZ_ANDROID_SHARED_ACCOUNT_TYPE;
-
- /**
- * Bug 790931: this action is broadcast when an Android Sync Account is
- * deleted. This allows each installed Firefox to delete any Sync Account
- * pickle file and to (try to) wipe its client record from the Sync server.
- * <p>
- * It is protected by signing-level permission PER_ACCOUNT_TYPE_PERMISSION and
- * can be received only by Firefox versions sharing the same Android Sync
- * Account type.
- * <p>
- * See {@link org.mozilla.gecko.sync.setup.SyncAccounts#makeSyncAccountDeletedIntent(android.content.Context, android.accounts.AccountManager, android.accounts.Account)}
- * for contents of the intent.
- */
- public static final String SYNC_ACCOUNT_DELETED_ACTION = AppConstants.MOZ_ANDROID_SHARED_ACCOUNT_TYPE + ".accounts.SYNC_ACCOUNT_DELETED_ACTION";
-
- /**
- * Bug 790931: version number of contents of SYNC_ACCOUNT_DELETED_ACTION
- * intent.
- * <p>
- * See {@link org.mozilla.gecko.sync.setup.SyncAccounts#makeSyncAccountDeletedIntent(android.content.Context, android.accounts.AccountManager, android.accounts.Account)}
- * for contents of the intent.
- */
- public static final long SYNC_ACCOUNT_DELETED_INTENT_VERSION = 1;
-
- /**
- * Bug 790931: this signing-level permission protects broadcast intents that
- * should be received only by Firefox versions sharing the same Android Sync
- * Account type.
- */
- public static final String PER_ACCOUNT_TYPE_PERMISSION = AppConstants.MOZ_ANDROID_SHARED_ACCOUNT_TYPE + ".permission.PER_ACCOUNT_TYPE";
-
- public static final String DEFAULT_AUTH_SERVER = "https://auth.services.mozilla.com/";
-
- // Used for BackoffHandler storage for Sync 1.1's SyncAdapter.
- public static final String BACKOFF_PREF_SUFFIX_11 = "sync";
-
- public static final String SYNC_ACCOUNT_DEPRECATED_ACTION = AppConstants.MOZ_ANDROID_SHARED_ACCOUNT_TYPE + ".accounts.SYNC_ACCOUNT_DEPRECATED_ACTION";
}
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/Utils.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/Utils.java
@@ -72,23 +72,16 @@ public class Utils {
*/
public static BigInteger generateBigIntegerLessThan(BigInteger r) {
int maxBytes = (int) Math.ceil(((double) r.bitLength()) / 8);
BigInteger randInt = new BigInteger(generateRandomBytes(maxBytes));
return randInt.mod(r);
}
/**
- * Helper to reseed the shared secure random number generator.
- */
- public static void reseedSharedRandom() {
- sharedSecureRandom.setSeed(sharedSecureRandom.generateSeed(8));
- }
-
- /**
* Helper to convert a byte array to a hex-encoded string
*/
public static String byte2Hex(final byte[] b) {
return byte2Hex(b, 2 * b.length);
}
public static String byte2Hex(final byte[] b, int hexLength) {
final StringBuilder hs = new StringBuilder(Math.max(2*b.length, hexLength));
@@ -560,27 +553,16 @@ public class Utils {
/**
* Replace "foo@bar.com" with "XXX@XXX.XXX".
*/
public static String obfuscateEmail(final String in) {
return in.replaceAll("[^@\\.]", "X");
}
- public static String nodeWeaveURL(String serverURL, String username) {
- String userPart = username + "/node/weave";
- if (serverURL == null) {
- return SyncConstants.DEFAULT_AUTH_SERVER + "user/1.0/" + userPart;
- }
- if (!serverURL.endsWith("/")) {
- serverURL = serverURL + "/";
- }
- return serverURL + "user/1.0/" + userPart;
- }
-
public static void throwIfNull(Object... objects) {
for (Object object : objects) {
if (object == null) {
throw new IllegalArgumentException("object must not be null");
}
}
}
@@ -610,31 +592,9 @@ public class Utils {
}
String country = locale.getCountry(); // Can be an empty string.
if (country.equals("")) {
return language;
}
return language + "-" + country;
}
-
- /**
- * Make a span with a clickable chunk of text interpolated in.
- *
- * @param context Android context.
- * @param messageId of string containing clickable chunk.
- * @param clickableId of string to make clickable.
- * @param clickableSpan to activate on click.
- * @return Spannable.
- */
- public static Spannable interpolateClickableSpan(Context context, int messageId, int clickableId, ClickableSpan clickableSpan) {
- // This horrible bit of special-casing is because we want this error message to
- // contain a clickable, extra chunk of text, but we don't want to pollute
- // the exception class with Android specifics.
- final String clickablePart = context.getString(clickableId);
- final String message = context.getString(messageId, clickablePart);
- final int clickableStart = message.lastIndexOf(clickablePart);
- final int clickableEnd = clickableStart + clickablePart.length();
- final Spannable span = Spannable.Factory.getInstance().newSpannable(message);
- span.setSpan(clickableSpan, clickableStart, clickableEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- return span;
- }
}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/config/AccountPickler.java
+++ /dev/null
@@ -1,182 +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.io.FileOutputStream;
-import java.io.PrintStream;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-import org.mozilla.gecko.sync.Utils;
-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.content.Context;
-
-/**
- * Bug 768102: Android deletes Account objects when the Authenticator that owns
- * the Account disappears. This happens when an App is installed to the SD card
- * and the SD card is un-mounted or the device is rebooted.
- * <p>
- * Bug 769745: Work around this by pickling the current Sync account data every
- * sync.
- * <p>
- * Bug 735842: Work around this by un-pickling when we check if Sync accounts
- * exist (called from Fennec).
- * <p>
- * Android just doesn't support installing Apps that define long-lived Services
- * and/or own Account types onto the SD card. The documentation says not to do
- * it. There are hordes of developers who want to do it, and have tried to
- * register for almost every "package installation changed" broadcast intent
- * that Android supports. They all explicitly state that the package that has
- * changed does *not* receive the broadcast intent, thereby preventing an App
- * from re-establishing its state.
- * <p>
- * <a href="http://developer.android.com/guide/topics/data/install-location.html">Reference.</a>
- * <p>
- * <b>Quote</b>: Your AbstractThreadedSyncAdapter and all its sync functionality
- * will not work until external storage is remounted.
- * <p>
- * <b>Quote</b>: Your running Service will be killed and will not be restarted
- * when external storage is remounted. You can, however, register for the
- * ACTION_EXTERNAL_APPLICATIONS_AVAILABLE broadcast Intent, which will notify
- * your application when applications installed on external storage have become
- * available to the system again. At which time, you can restart your Service.
- * <p>
- * Problem: <a href="http://code.google.com/p/android/issues/detail?id=8485">that intent doesn't work</a>!
- */
-public class AccountPickler {
- public static final String LOG_TAG = "AccountPickler";
-
- public static final long VERSION = 1;
-
- /**
- * Remove Sync account persisted to disk.
- *
- * @param context Android context.
- * @param filename name of persisted pickle file; must not contain path separators.
- * @return <code>true</code> if given pickle existed and was successfully deleted.
- */
- public static boolean deletePickle(final Context context, final String filename) {
- return context.deleteFile(filename);
- }
-
- /**
- * Persist Sync account to disk as a JSON object.
- * <p>
- * JSON object has keys:
- * <ul>
- * <li><code>Constants.JSON_KEY_ACCOUNT</code>: the Sync account's un-encoded username,
- * like "test@mozilla.com".</li>
- *
- * <li><code>Constants.JSON_KEY_PASSWORD</code>: the Sync account's password;</li>
- *
- * <li><code>Constants.JSON_KEY_SERVER</code>: the Sync account's server;</li>
- *
- * <li><code>Constants.JSON_KEY_SYNCKEY</code>: the Sync account's sync key;</li>
- *
- * <li><code>Constants.JSON_KEY_CLUSTER</code>: the Sync account's cluster (may be null);</li>
- *
- * <li><code>Constants.JSON_KEY_CLIENT_NAME</code>: the Sync account's client name (may be null);</li>
- *
- * <li><code>Constants.JSON_KEY_CLIENT_GUID</code>: the Sync account's client GUID (may be null);</li>
- *
- * <li><code>Constants.JSON_KEY_SYNC_AUTOMATICALLY</code>: true if the Android Account is syncing automically;</li>
- *
- * <li><code>Constants.JSON_KEY_VERSION</code>: version of this file;</li>
- *
- * <li><code>Constants.JSON_KEY_TIMESTAMP</code>: when this file was written.</li>
- * </ul>
- *
- *
- * @param context Android context.
- * @param filename name of file to persist to; must not contain path separators.
- * @param params the Sync account's parameters.
- * @param syncAutomatically whether the Android Account object is syncing automatically.
- */
- public static void pickle(final Context context, final String filename,
- final SyncAccountParameters params, final boolean syncAutomatically) {
- final ExtendedJSONObject o = params.asJSON();
- o.put(Constants.JSON_KEY_SYNC_AUTOMATICALLY, Boolean.valueOf(syncAutomatically));
- o.put(Constants.JSON_KEY_VERSION, Long.valueOf(VERSION));
- o.put(Constants.JSON_KEY_TIMESTAMP, Long.valueOf(System.currentTimeMillis()));
-
- PrintStream ps = null;
- try {
- final FileOutputStream fos = context.openFileOutput(filename, Context.MODE_PRIVATE);
- ps = new PrintStream(fos);
- ps.print(o.toJSONString());
- Logger.debug(LOG_TAG, "Persisted " + o.keySet().size() + " account settings to " + filename + ".");
- } catch (Exception e) {
- Logger.warn(LOG_TAG, "Caught exception persisting account settings to " + filename + "; ignoring.", e);
- } finally {
- if (ps != null) {
- ps.close();
- }
- }
- }
-
- /**
- * Create Android account from saved JSON object.
- *
- * @param context
- * Android context.
- * @param filename
- * name of file to read from; must not contain path separators.
- * @return created Android account, or null on error.
- */
- public static Account unpickle(final Context context, final String filename) {
- final String jsonString = Utils.readFile(context, filename);
- if (jsonString == null) {
- Logger.info(LOG_TAG, "Pickle file '" + filename + "' not found; aborting.");
- return null;
- }
-
- ExtendedJSONObject json = null;
- try {
- json = ExtendedJSONObject.parseJSONObject(jsonString);
- } catch (Exception e) {
- Logger.warn(LOG_TAG, "Got exception reading pickle file '" + filename + "'; aborting.", e);
- return null;
- }
-
- SyncAccountParameters params = null;
- try {
- // Null checking of inputs is done in constructor.
- params = new SyncAccountParameters(context, null, json);
- } catch (IllegalArgumentException e) {
- Logger.warn(LOG_TAG, "Un-pickled data included null username, password, or serverURL; aborting.", e);
- return null;
- }
-
- // Default to syncing automatically.
- boolean syncAutomatically = true;
- if (json.containsKey(Constants.JSON_KEY_SYNC_AUTOMATICALLY)) {
- if (Boolean.FALSE.equals(json.get(Constants.JSON_KEY_SYNC_AUTOMATICALLY))) {
- syncAutomatically = false;
- }
- }
-
- final Account account = SyncAccounts.createSyncAccountPreservingExistingPreferences(params, syncAutomatically);
- if (account == null) {
- Logger.warn(LOG_TAG, "Failed to add Android Account; aborting.");
- return null;
- }
-
- Integer version = json.getIntegerSafely(Constants.JSON_KEY_VERSION);
- Integer timestamp = json.getIntegerSafely(Constants.JSON_KEY_TIMESTAMP);
- if (version == null || timestamp == null) {
- Logger.warn(LOG_TAG, "Did not find version or timestamp in pickle file; ignoring.");
- version = -1;
- timestamp = -1;
- }
-
- Logger.info(LOG_TAG, "Un-pickled Android account named " + params.username + " (version " + version + ", pickled at " + timestamp + ").");
-
- return account;
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/config/ClientRecordTerminator.java
+++ /dev/null
@@ -1,76 +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.net.URI;
-
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.SyncConfiguration;
-import org.mozilla.gecko.sync.net.AuthHeaderProvider;
-import org.mozilla.gecko.sync.net.BaseResource;
-import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
-import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
-import org.mozilla.gecko.sync.net.SyncStorageResponse;
-
-/**
- * Bug 770785: when an Android Account is deleted, we need to (try to) delete
- * the associated client GUID from the server's clients table.
- * <p>
- * This class provides a static method to do that.
- */
-public class ClientRecordTerminator {
- public static final String LOG_TAG = "ClientRecTerminator";
-
- protected ClientRecordTerminator() {
- super(); // Stop this class from being instantiated.
- }
-
- public static void deleteClientRecord(final SyncConfiguration config, final String clientGUID)
- throws Exception {
-
- final String collection = "clients";
- final URI wboURI = config.wboURI(collection, clientGUID);
-
- // Would prefer to break this out into a self-contained client library.
- final SyncStorageRecordRequest r = new SyncStorageRecordRequest(wboURI);
- r.delegate = new SyncStorageRequestDelegate() {
- @Override
- public AuthHeaderProvider getAuthHeaderProvider() {
- return config.getAuthHeaderProvider();
- }
-
- @Override
- public String ifUnmodifiedSince() {
- return null;
- }
-
- @Override
- public void handleRequestSuccess(SyncStorageResponse response) {
- Logger.info(LOG_TAG, "Deleted client record with GUID " + clientGUID + " from server.");
- BaseResource.consumeEntity(response);
- }
-
- @Override
- public void handleRequestFailure(SyncStorageResponse response) {
- Logger.warn(LOG_TAG, "Failed to delete client record with GUID " + clientGUID + " from server.");
- try {
- Logger.warn(LOG_TAG, "Server error message was: " + response.getErrorMessage());
- } catch (Exception e) {
- // Do nothing.
- }
- BaseResource.consumeEntity(response);
- }
-
- @Override
- public void handleRequestError(Exception ex) {
- // It could be that we don't have network access when trying
- // to remove an Account; not much to be done in this situation.
- Logger.error(LOG_TAG, "Got exception trying to delete client record with GUID " + clientGUID + " from server; ignoring.", ex);
- }
- };
-
- r.delete();
- }
-}
deleted file mode 100644
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/setup/SyncAccounts.java
+++ /dev/null
@@ -1,602 +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.File;
-import java.io.UnsupportedEncodingException;
-import java.security.NoSuchAlgorithmException;
-
-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.sync.CredentialException;
-import org.mozilla.gecko.sync.ExtendedJSONObject;
-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.AccountPickler;
-import org.mozilla.gecko.sync.repositories.android.RepoUtils;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.content.ActivityNotFoundException;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.util.Log;
-
-/**
- * This class contains utilities that are of use to Fennec
- * and Sync setup activities.
- * <p>
- * Do not break these APIs without correcting upstream code!
- */
-public class SyncAccounts {
- private static final String LOG_TAG = "SyncAccounts";
-
- private static final String MOTO_BLUR_SETTINGS_ACTIVITY = "com.motorola.blur.settings.AccountsAndServicesPreferenceActivity";
- private static final String MOTO_BLUR_PACKAGE = "com.motorola.blur.setup";
-
- /**
- * Return Sync accounts.
- *
- * @param c
- * Android context.
- * @return Sync accounts.
- */
- public static Account[] syncAccounts(final Context c) {
- return AccountManager.get(c).getAccountsByType(SyncConstants.ACCOUNTTYPE_SYNC);
- }
-
- /**
- * Returns true if a Sync account is set up, or we have a pickled Sync account
- * on disk that should be un-pickled (Bug 769745). If we have a pickled Sync
- * account, try to un-pickle it and create the corresponding Sync account.
- * <p>
- * Do not call this method from the main thread.
- */
- public static boolean syncAccountsExist(Context c) {
- final boolean accountsExist = AccountManager.get(c).getAccountsByType(SyncConstants.ACCOUNTTYPE_SYNC).length > 0;
- if (accountsExist) {
- return true;
- }
-
- final File file = c.getFileStreamPath(Constants.ACCOUNT_PICKLE_FILENAME);
- if (!file.exists()) {
- return false;
- }
-
- // There is a small race window here: if the user creates a new Sync account
- // between our checks, this could erroneously report that no Sync accounts
- // exist.
- final Account account = AccountPickler.unpickle(c, Constants.ACCOUNT_PICKLE_FILENAME);
- return (account != null);
- }
-
- /**
- * This class encapsulates the parameters needed to create a new Firefox Sync
- * account.
- */
- public static class SyncAccountParameters {
- public final Context context;
- public final AccountManager accountManager;
-
-
- public final String username; // services.sync.account
- public final String syncKey; // in password manager: "chrome://weave (Mozilla Services Encryption Passphrase)"
- public final String password; // in password manager: "chrome://weave (Mozilla Services Password)"
- public final String serverURL; // services.sync.serverURL
- public final String clusterURL; // services.sync.clusterURL
- public final String clientName; // services.sync.client.name
- public final String clientGuid; // services.sync.client.GUID
-
- /**
- * Encapsulate the parameters needed to create a new Firefox Sync account.
- *
- * @param context
- * the current <code>Context</code>; cannot be null.
- * @param accountManager
- * an <code>AccountManager</code> instance to use; if null, get it
- * from <code>context</code>.
- * @param username
- * the desired username; cannot be null.
- * @param syncKey
- * the desired sync key; cannot be null.
- * @param password
- * the desired password; cannot be null.
- * @param serverURL
- * the server URL to use; if null, use the default.
- * @param clusterURL
- * the cluster URL to use; if null, a fresh cluster URL will be
- * retrieved from the server during the next sync.
- * @param clientName
- * the client name; if null, a fresh client record will be uploaded
- * to the server during the next sync.
- * @param clientGuid
- * the client GUID; if null, a fresh client record will be uploaded
- * to the server during the next sync.
- */
- public SyncAccountParameters(Context context, AccountManager accountManager,
- String username, String syncKey, String password,
- String serverURL, String clusterURL,
- String clientName, String clientGuid) {
- if (context == null) {
- throw new IllegalArgumentException("Null context passed to SyncAccountParameters constructor.");
- }
- if (username == null) {
- throw new IllegalArgumentException("Null username passed to SyncAccountParameters constructor.");
- }
- if (syncKey == null) {
- throw new IllegalArgumentException("Null syncKey passed to SyncAccountParameters constructor.");
- }
- if (password == null) {
- throw new IllegalArgumentException("Null password passed to SyncAccountParameters constructor.");
- }
- this.context = context;
- this.accountManager = accountManager;
- this.username = username;
- this.syncKey = syncKey;
- this.password = password;
- this.serverURL = serverURL;
- this.clusterURL = clusterURL;
- this.clientName = clientName;
- this.clientGuid = clientGuid;
- }
-
- public SyncAccountParameters(Context context, AccountManager accountManager,
- String username, String syncKey, String password, String serverURL) {
- this(context, accountManager, username, syncKey, password, serverURL, null, null, null);
- }
-
- public SyncAccountParameters(final Context context, final AccountManager accountManager, final ExtendedJSONObject o) {
- this(context, accountManager,
- o.getString(Constants.JSON_KEY_ACCOUNT),
- o.getString(Constants.JSON_KEY_SYNCKEY),
- o.getString(Constants.JSON_KEY_PASSWORD),
- o.getString(Constants.JSON_KEY_SERVER),
- o.getString(Constants.JSON_KEY_CLUSTER),
- o.getString(Constants.JSON_KEY_CLIENT_NAME),
- o.getString(Constants.JSON_KEY_CLIENT_GUID));
- }
-
- public ExtendedJSONObject asJSON() {
- final ExtendedJSONObject o = new ExtendedJSONObject();
- o.put(Constants.JSON_KEY_ACCOUNT, username);
- o.put(Constants.JSON_KEY_PASSWORD, password);
- o.put(Constants.JSON_KEY_SERVER, serverURL);
- o.put(Constants.JSON_KEY_SYNCKEY, syncKey);
- o.put(Constants.JSON_KEY_CLUSTER, clusterURL);
- o.put(Constants.JSON_KEY_CLIENT_NAME, clientName);
- o.put(Constants.JSON_KEY_CLIENT_GUID, clientGuid);
- return o;
- }
- }
-
- /**
- * Create a sync account, clearing any existing preferences, and set it to
- * sync automatically.
- * <p>
- * Do not call this method from the main thread.
- *
- * @param syncAccount
- * parameters of the account to be created.
- * @return created <code>Account</code>, or null if an error occurred and the
- * account could not be added.
- */
- public static Account createSyncAccount(SyncAccountParameters syncAccount) {
- return createSyncAccount(syncAccount, true, true);
- }
-
- /**
- * Create a sync account, clearing any existing preferences.
- * <p>
- * Do not call this method from the main thread.
- * <p>
- * Intended for testing; use
- * <code>createSyncAccount(SyncAccountParameters)</code> instead.
- *
- * @param syncAccount
- * parameters of the account to be created.
- * @param syncAutomatically
- * whether to start syncing this Account automatically (
- * <code>false</code> for test accounts).
- * @return created Android <code>Account</code>, or null if an error occurred
- * and the account could not be added.
- */
- public static Account createSyncAccount(SyncAccountParameters syncAccount,
- boolean syncAutomatically) {
- return createSyncAccount(syncAccount, syncAutomatically, true);
- }
-
- public static Account createSyncAccountPreservingExistingPreferences(SyncAccountParameters syncAccount,
- boolean syncAutomatically) {
- return createSyncAccount(syncAccount, syncAutomatically, false);
- }
-
- /**
- * Create a sync account.
- * <p>
- * Do not call this method from the main thread.
- * <p>
- * Intended for testing; use
- * <code>createSyncAccount(SyncAccountParameters)</code> instead.
- *
- * @param syncAccount
- * parameters of the account to be created.
- * @param syncAutomatically
- * whether to start syncing this Account automatically (
- * <code>false</code> for test accounts).
- * @param clearPreferences
- * <code>true</code> to clear existing preferences before creating.
- * @return created Android <code>Account</code>, or null if an error occurred
- * and the account could not be added.
- */
- protected static Account createSyncAccount(SyncAccountParameters syncAccount,
- boolean syncAutomatically, boolean clearPreferences) {
- final Context context = syncAccount.context;
- final AccountManager accountManager = (syncAccount.accountManager == null) ?
- AccountManager.get(syncAccount.context) : syncAccount.accountManager;
- final String username = syncAccount.username;
- final String syncKey = syncAccount.syncKey;
- final String password = syncAccount.password;
- final String serverURL = (syncAccount.serverURL == null) ?
- SyncConstants.DEFAULT_AUTH_SERVER : syncAccount.serverURL;
-
- Logger.debug(LOG_TAG, "Using account manager " + accountManager);
- if (!RepoUtils.stringsEqual(syncAccount.serverURL, SyncConstants.DEFAULT_AUTH_SERVER)) {
- Logger.info(LOG_TAG, "Setting explicit server URL: " + serverURL);
- }
-
- final Account account = new Account(username, SyncConstants.ACCOUNTTYPE_SYNC);
- final Bundle userbundle = new Bundle();
-
- // Add sync key and server URL.
- userbundle.putString(Constants.OPTION_SYNCKEY, syncKey);
- userbundle.putString(Constants.OPTION_SERVER, serverURL);
- Logger.debug(LOG_TAG, "Adding account for " + SyncConstants.ACCOUNTTYPE_SYNC);
- boolean result = false;
- try {
- result = accountManager.addAccountExplicitly(account, password, userbundle);
- } catch (SecurityException e) {
- // We use Log rather than Logger here to avoid possibly hiding these errors.
- final String message = e.getMessage();
- if (message != null && (message.indexOf("is different than the authenticator's uid") > 0)) {
- Log.wtf(SyncConstants.GLOBAL_LOG_TAG,
- "Unable to create account. " +
- "If you have more than one version of " +
- "Firefox/Beta/Aurora/Nightly/Fennec installed, that's why.",
- e);
- } else {
- Log.e(SyncConstants.GLOBAL_LOG_TAG, "Unable to create account.", e);
- }
- }
-
- if (!result) {
- Logger.error(LOG_TAG, "Failed to add account " + account + "!");
- return null;
- }
- Logger.debug(LOG_TAG, "Account " + account + " added successfully.");
-
- setSyncAutomatically(account, syncAutomatically);
- setIsSyncable(account, true);
- Logger.debug(LOG_TAG, "Set account to sync automatically? " + syncAutomatically + ".");
-
- try {
- final String product = GlobalConstants.BROWSER_INTENT_PACKAGE;
- final String profile = Constants.DEFAULT_PROFILE;
- final long version = SyncConfiguration.CURRENT_PREFS_VERSION;
-
- final SharedPreferences.Editor editor = Utils.getSharedPreferences(context, product, username, serverURL, profile, version).edit();
- if (clearPreferences) {
- final String prefsPath = Utils.getPrefsPath(product, username, serverURL, profile, version);
- Logger.info(LOG_TAG, "Clearing preferences path " + prefsPath + " for this account.");
- editor.clear();
- }
-
- if (syncAccount.clusterURL != null) {
- editor.putString(SyncConfiguration.PREF_CLUSTER_URL, syncAccount.clusterURL);
- }
-
- if (syncAccount.clientName != null && syncAccount.clientGuid != null) {
- Logger.debug(LOG_TAG, "Setting client name to " + syncAccount.clientName + " and client GUID to " + syncAccount.clientGuid + ".");
- editor.putString(SyncConfiguration.PREF_CLIENT_NAME, syncAccount.clientName);
- editor.putString(SyncConfiguration.PREF_ACCOUNT_GUID, syncAccount.clientGuid);
- } else {
- Logger.debug(LOG_TAG, "Client name and guid not both non-null, so not setting client data.");
- }
-
- editor.commit();
- } catch (Exception e) {
- Logger.error(LOG_TAG, "Could not clear prefs path!", e);
- }
- return account;
- }
-
- public static void setIsSyncable(Account account, boolean isSyncable) {
- String authority = BrowserContract.AUTHORITY;
- ContentResolver.setIsSyncable(account, authority, isSyncable ? 1 : 0);
- }
-
- public static void setSyncAutomatically(Account account, boolean syncAutomatically) {
- if (syncAutomatically) {
- ContentResolver.setMasterSyncAutomatically(true);
- }
-
- String authority = BrowserContract.AUTHORITY;
- Logger.debug(LOG_TAG, "Setting authority " + authority + " to " +
- (syncAutomatically ? "" : "not ") + "sync automatically.");
- ContentResolver.setSyncAutomatically(account, authority, syncAutomatically);
- }
-
- public static void backgroundSetSyncAutomatically(final Account account, final boolean syncAutomatically) {
- ThreadPool.run(new Runnable() {
- @Override
- public void run() {
- setSyncAutomatically(account, syncAutomatically);
- }
- });
- }
- /**
- * Bug 721760: try to start a vendor-specific Accounts & Sync activity on Moto
- * Blur devices.
- * <p>
- * Bug 773562: actually start and catch <code>ActivityNotFoundException</code>,
- * rather than just returning the <code>Intent</code> only, because some
- * Moto devices fail to start the activity.
- *
- * @param context
- * current Android context.
- * @param vendorPackage
- * vendor specific package name.
- * @param vendorClass
- * vendor specific class name.
- * @return null on failure, otherwise the <code>Intent</code> started.
- */
- protected static Intent openVendorSyncSettings(Context context, final String vendorPackage, final String vendorClass) {
- try {
- final int contextFlags = Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY;
- Context foreignContext = context.createPackageContext(vendorPackage, contextFlags);
- Class<?> klass = foreignContext.getClassLoader().loadClass(vendorClass);
-
- final Intent intent = new Intent(foreignContext, klass);
- context.startActivity(intent);
- Logger.info(LOG_TAG, "Vendor package " + vendorPackage + " and class " +
- vendorClass + " found, and activity launched.");
- return intent;
- } catch (NameNotFoundException e) {
- Logger.debug(LOG_TAG, "Vendor package " + vendorPackage + " not found. Skipping.");
- } catch (ClassNotFoundException e) {
- Logger.debug(LOG_TAG, "Vendor package " + vendorPackage + " found but class " +
- vendorClass + " not found. Skipping.", e);
- } catch (ActivityNotFoundException e) {
- // Bug 773562 - android.content.ActivityNotFoundException on Motorola devices.
- Logger.warn(LOG_TAG, "Vendor package " + vendorPackage + " and class " +
- vendorClass + " found, but activity not launched. Skipping.", e);
- } catch (Exception e) {
- // Just in case.
- Logger.warn(LOG_TAG, "Caught exception launching activity from vendor package " + vendorPackage +
- " and class " + vendorClass + ". Ignoring.", e);
- }
- return null;
- }
-
- /**
- * Start Sync settings activity.
- *
- * @param context
- * current Android context.
- * @return the <code>Intent</code> started, or null if we couldn't start settings.
- */
- public static Intent openSyncSettings(Context context) {
- // Bug 721760 - opening Sync settings takes user to Battery & Data Manager
- // on a variety of Motorola devices. This work around tries to load the
- // correct Intent by hand. Oh, Android.
- Intent intent = openVendorSyncSettings(context, MOTO_BLUR_PACKAGE, MOTO_BLUR_SETTINGS_ACTIVITY);
- if (intent != null) {
- return intent;
- }
-
- // Open default Sync settings activity.
- intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
- // Bug 774233: do not start activity as a new task (second run fails on some HTC devices).
- try {
- context.startActivity(intent); // We should always find this Activity.
- } catch (ActivityNotFoundException ex) {
- // We're probably on a Kindle, and the user hasn't installed the Android
- // settings app. See Bug 945341.
- // We simply mute the error.
- return null;
- }
- return intent;
- }
-
- /**
- * Synchronously extract Sync account parameters from Android account version
- * 0, using plain auth token type.
- * <p>
- * Safe to call from main thread.
- *
- * @param context
- * Android context.
- * @param accountManager
- * Android account manager.
- * @param account
- * Android Account.
- * @return Sync account parameters, always non-null; fields username,
- * password, serverURL, and syncKey always non-null.
- */
- public static SyncAccountParameters blockingFromAndroidAccountV0(final Context context, final AccountManager accountManager, final Account account)
- throws CredentialException {
- String username;
- try {
- username = Utils.usernameFromAccount(account.name);
- } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
- throw new CredentialException.MissingCredentialException("username");
- }
-
- /*
- * If we are accessing an Account that we don't own, Android will throw an
- * unchecked <code>SecurityException</code> saying
- * "W FxSync(XXXX) java.lang.SecurityException: caller uid XXXXX is different than the authenticator's uid".
- * We catch that error and throw accordingly.
- */
- String password;
- String syncKey;
- String serverURL;
- try {
- password = accountManager.getPassword(account);
- syncKey = accountManager.getUserData(account, Constants.OPTION_SYNCKEY);
- serverURL = accountManager.getUserData(account, Constants.OPTION_SERVER);
- } catch (SecurityException e) {
- Logger.warn(LOG_TAG, "Got security exception fetching Sync account parameters; throwing.");
- throw new CredentialException.MissingAllCredentialsException(e);
- }
-
- if (password == null &&
- username == null &&
- syncKey == null &&
- serverURL == null) {
- throw new CredentialException.MissingAllCredentialsException();
- }
-
- if (password == null) {
- throw new CredentialException.MissingCredentialException("password");
- }
-
- if (syncKey == null) {
- throw new CredentialException.MissingCredentialException("syncKey");
- }
-
- if (serverURL == null) {
- throw new CredentialException.MissingCredentialException("serverURL");
- }
-
- try {
- // SyncAccountParameters constructor throws on null inputs. This shouldn't
- // happen, but let's be safe.
- return new SyncAccountParameters(context, accountManager, username, syncKey, password, serverURL);
- } catch (Exception e) {
- Logger.warn(LOG_TAG, "Got exception fetching Sync account parameters; throwing.");
- throw new CredentialException.MissingAllCredentialsException(e);
- }
- }
-
- /**
- * Bug 790931: create an intent announcing that a Sync account will be
- * deleted.
- * <p>
- * This intent <b>must</b> be broadcast with secure permissions, because it
- * contains sensitive user information including the Sync account password and
- * Sync key.
- * <p>
- * Version 1 of the created intent includes extras with keys
- * <code>Constants.JSON_KEY_VERSION</code>,
- * <code>Constants.JSON_KEY_TIMESTAMP</code>, and
- * <code>Constants.JSON_KEY_ACCOUNT</code> (which is the Android Account name,
- * not the encoded Sync Account name).
- * <p>
- * If possible, it contains the key <code>Constants.JSON_KEY_PAYLOAD</code>
- * with value the Sync account parameters as JSON, <b>except the Sync key has
- * been replaced with the empty string</b>. (We replace, rather than remove,
- * the Sync key because SyncAccountParameters expects a non-null Sync key.)
- *
- * @see SyncAccountParameters#asJSON
- *
- * @param context
- * Android context.
- * @param accountManager
- * Android account manager.
- * @param account
- * Android account being removed.
- * @return <code>Intent</code> to broadcast.
- */
- public static Intent makeSyncAccountDeletedIntent(final Context context, final AccountManager accountManager, final Account account) {
- final Intent intent = new Intent(SyncConstants.SYNC_ACCOUNT_DELETED_ACTION);
-
- intent.putExtra(Constants.JSON_KEY_VERSION, Long.valueOf(SyncConstants.SYNC_ACCOUNT_DELETED_INTENT_VERSION));
- intent.putExtra(Constants.JSON_KEY_TIMESTAMP, Long.valueOf(System.currentTimeMillis()));
- intent.putExtra(Constants.JSON_KEY_ACCOUNT, account.name);
-
- SyncAccountParameters accountParameters = null;
- try {
- accountParameters = SyncAccounts.blockingFromAndroidAccountV0(context, accountManager, account);
- } catch (Exception e) {
- Logger.warn(LOG_TAG, "Caught exception fetching account parameters.", e);
- }
-
- if (accountParameters != null) {
- ExtendedJSONObject json = accountParameters.asJSON();
- json.put(Constants.JSON_KEY_SYNCKEY, ""); // Reduce attack surface area by removing Sync key.
- intent.putExtra(Constants.JSON_KEY_PAYLOAD, json.toJSONString());
- }
-
- return intent;
- }
-
- /**
- * Synchronously fetch SharedPreferences of a profile associated with a Sync
- * account.
- * <p>
- * Safe to call from main thread.
- *
- * @param context
- * Android context.
- * @param accountManager
- * Android account manager.
- * @param account
- * Android Account.
- * @param product
- * package.
- * @param profile
- * of account.
- * @param version
- * number.
- * @return SharedPreferences associated with Sync account.
- * @throws CredentialException
- * @throws NoSuchAlgorithmException
- * @throws UnsupportedEncodingException
- */
- public static SharedPreferences blockingPrefsFromAndroidAccountV0(final Context context, final AccountManager accountManager, final Account account,
- final String product, final String profile, final long version)
- throws CredentialException, NoSuchAlgorithmException, UnsupportedEncodingException {
- SyncAccountParameters params = SyncAccounts.blockingFromAndroidAccountV0(context, accountManager, account);
- String prefsPath = Utils.getPrefsPath(product, params.username, params.serverURL, profile, version);
-
- return context.getSharedPreferences(prefsPath, Utils.SHARED_PREFERENCES_MODE);
- }
-
- /**
- * Synchronously fetch SharedPreferences of a profile associated with the
- * default Firefox profile of a Sync Account.
- * <p>
- * Uses the default package, default profile, and current version.
- * <p>
- * Safe to call from main thread.
- *
- * @param context
- * Android context.
- * @param accountManager
- * Android account manager.
- * @param account
- * Android Account.
- * @return SharedPreferences associated with Sync account.
- * @throws CredentialException
- * @throws NoSuchAlgorithmException
- * @throws UnsupportedEncodingException
- */
- public static SharedPreferences blockingPrefsFromDefaultProfileV0(final Context context, final AccountManager accountManager, final Account account)
- throws CredentialException, NoSuchAlgorithmException, UnsupportedEncodingException {
- final String product = GlobalConstants.BROWSER_INTENT_PACKAGE;
- final String profile = Constants.DEFAULT_PROFILE;
- final long version = SyncConfiguration.CURRENT_PREFS_VERSION;
-
- return blockingPrefsFromAndroidAccountV0(context, accountManager, account, product, profile, version);
- }
-}
--- a/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestUtils.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/android/sync/test/TestUtils.java
@@ -146,17 +146,9 @@ public class TestUtils extends Utils {
assertEquals("sync.prefs.org!mozilla!firefox.ore7dlrwqi6xr7honxdtpvmh6tly4r7k.profile.3", Utils.getPrefsPath("org.mozilla.firefox", "xee7ffonluzpdp66l6xgpyh2v2w6ojkc", "test.url.com", "profile", 3));
}
@Test
public void testObfuscateEmail() {
assertEquals("XXX@XXX.XXX", Utils.obfuscateEmail("foo@bar.com"));
assertEquals("XXXX@XXX.XXXX.XX", Utils.obfuscateEmail("foot@bar.test.ca"));
}
-
- @Test
- public void testNodeWeaveURL() throws Exception {
- Assert.assertEquals("http://userapi.com/endpoint/user/1.0/username/node/weave", Utils.nodeWeaveURL("http://userapi.com/endpoint", "username"));
- Assert.assertEquals("http://userapi.com/endpoint/user/1.0/username/node/weave", Utils.nodeWeaveURL("http://userapi.com/endpoint/", "username"));
- Assert.assertEquals(SyncConstants.DEFAULT_AUTH_SERVER + "user/1.0/username/node/weave", Utils.nodeWeaveURL(null, "username"));
- Assert.assertEquals(SyncConstants.DEFAULT_AUTH_SERVER + "user/1.0/username2/node/weave", Utils.nodeWeaveURL(null, "username2"));
- }
}