mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 709324, Bug 730643: persist crypto/keys and meta/global. r=rnewman
This commit is contained in:
parent
173372bc56
commit
d285b0ba7c
@ -1,39 +1,6 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Android Sync Client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Richard Newman <rnewman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
/* 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;
|
||||
|
||||
@ -48,8 +15,6 @@ import org.mozilla.apache.commons.codec.binary.Base64;
|
||||
import org.mozilla.gecko.sync.crypto.CryptoException;
|
||||
import org.mozilla.gecko.sync.crypto.KeyBundle;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
public class CollectionKeys {
|
||||
private static final String LOG_TAG = "CollectionKeys";
|
||||
private KeyBundle defaultKeyBundle = null;
|
||||
@ -61,7 +26,7 @@ public class CollectionKeys {
|
||||
return ck.asCryptoRecord();
|
||||
} catch (NoCollectionKeysSetException e) {
|
||||
// Cannot occur.
|
||||
Log.e(LOG_TAG, "generateCollectionKeys returned a value with no default key. Unpossible.", e);
|
||||
Logger.error(LOG_TAG, "generateCollectionKeys returned a value with no default key.", e);
|
||||
throw new IllegalStateException("CollectionKeys should not have null default key.");
|
||||
}
|
||||
}
|
||||
@ -138,7 +103,18 @@ public class CollectionKeys {
|
||||
return record;
|
||||
}
|
||||
|
||||
public static CollectionKeys fromCryptoRecord(CryptoRecord keys, KeyBundle syncKeyBundle) throws CryptoException, IOException, ParseException, NonObjectJSONException {
|
||||
/**
|
||||
* Set my key bundle and collection keys with the given key bundle and data
|
||||
* (possibly decrypted) from the given record.
|
||||
*
|
||||
* @param keys
|
||||
* A "crypto/keys" <code>CryptoRecord</code>, encrypted with
|
||||
* <code>syncKeyBundle</code> if <code>syncKeyBundle</code> is non-null.
|
||||
* @param syncKeyBundle
|
||||
* If non-null, the sync key bundle to decrypt <code>keys</code> with.
|
||||
*/
|
||||
public void setKeyPairsFromWBO(CryptoRecord keys, KeyBundle syncKeyBundle)
|
||||
throws CryptoException, IOException, ParseException, NonObjectJSONException {
|
||||
if (syncKeyBundle != null) {
|
||||
keys.keyBundle = syncKeyBundle;
|
||||
keys.decrypt();
|
||||
@ -153,33 +129,6 @@ public class CollectionKeys {
|
||||
collectionKeys.put(pair.getKey(), bundle);
|
||||
}
|
||||
|
||||
CollectionKeys ck = new CollectionKeys();
|
||||
ck.collectionKeyBundles = collectionKeys;
|
||||
ck.defaultKeyBundle = defaultKey;
|
||||
return ck;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a downloaded record, and the Sync Key, decrypting the record and
|
||||
* setting our own keys accordingly.
|
||||
*/
|
||||
public void setKeyPairsFromWBO(CryptoRecord keys, KeyBundle syncKeyBundle)
|
||||
throws CryptoException,
|
||||
IOException,
|
||||
ParseException,
|
||||
NonObjectJSONException {
|
||||
keys.keyBundle = syncKeyBundle;
|
||||
keys.decrypt();
|
||||
ExtendedJSONObject cleartext = keys.payload;
|
||||
KeyBundle defaultKey = arrayToKeyBundle((JSONArray) cleartext.get("default"));
|
||||
|
||||
ExtendedJSONObject collections = cleartext.getObject("collections");
|
||||
HashMap<String, KeyBundle> collectionKeys = new HashMap<String, KeyBundle>();
|
||||
for (Entry<String, Object> pair : collections.entryIterable()) {
|
||||
KeyBundle bundle = arrayToKeyBundle((JSONArray) pair.getValue());
|
||||
collectionKeys.put(pair.getKey(), bundle);
|
||||
}
|
||||
|
||||
this.collectionKeyBundles = collectionKeys;
|
||||
this.defaultKeyBundle = defaultKey;
|
||||
}
|
||||
|
@ -1,47 +1,9 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Android Sync Client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Richard Newman <rnewman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
/* 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;
|
||||
|
||||
import org.mozilla.gecko.sync.crypto.KeyBundle;
|
||||
|
||||
public interface CredentialsSource {
|
||||
|
||||
public abstract String credentials();
|
||||
public abstract CollectionKeys getCollectionKeys();
|
||||
public abstract KeyBundle keyForCollection(String collection) throws NoCollectionKeysSetException;
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ import org.mozilla.gecko.sync.stage.PasswordsServerSyncStage;
|
||||
import org.mozilla.gecko.sync.stage.CheckPreconditionsStage;
|
||||
import org.mozilla.gecko.sync.stage.CompletedStage;
|
||||
import org.mozilla.gecko.sync.stage.EnsureClusterURLStage;
|
||||
import org.mozilla.gecko.sync.stage.EnsureKeysStage;
|
||||
import org.mozilla.gecko.sync.stage.EnsureCrypto5KeysStage;
|
||||
import org.mozilla.gecko.sync.stage.FennecTabsServerSyncStage;
|
||||
import org.mozilla.gecko.sync.stage.FetchInfoCollectionsStage;
|
||||
import org.mozilla.gecko.sync.stage.FetchMetaGlobalStage;
|
||||
@ -70,16 +70,8 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
||||
/*
|
||||
* Key accessors.
|
||||
*/
|
||||
public void setCollectionKeys(CollectionKeys k) {
|
||||
config.setCollectionKeys(k);
|
||||
}
|
||||
@Override
|
||||
public CollectionKeys getCollectionKeys() {
|
||||
return config.collectionKeys;
|
||||
}
|
||||
@Override
|
||||
public KeyBundle keyForCollection(String collection) throws NoCollectionKeysSetException {
|
||||
return config.keyForCollection(collection);
|
||||
public KeyBundle keyBundleForCollection(String collection) throws NoCollectionKeysSetException {
|
||||
return config.getCollectionKeys().keyBundleForCollection(collection);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -193,7 +185,7 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
||||
stages.put(Stage.ensureClusterURL, new EnsureClusterURLStage());
|
||||
stages.put(Stage.fetchInfoCollections, new FetchInfoCollectionsStage());
|
||||
stages.put(Stage.fetchMetaGlobal, new FetchMetaGlobalStage());
|
||||
stages.put(Stage.ensureKeysStage, new EnsureKeysStage());
|
||||
stages.put(Stage.ensureKeysStage, new EnsureCrypto5KeysStage());
|
||||
stages.put(Stage.syncClientsEngine, new SyncClientsEngineStage());
|
||||
|
||||
// TODO: more stages.
|
||||
@ -273,7 +265,6 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
||||
return this.getContext().getSharedPreferences(name, mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getContext() {
|
||||
return this.context;
|
||||
}
|
||||
@ -355,13 +346,6 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
||||
}
|
||||
}
|
||||
|
||||
public void fetchMetaGlobal(MetaGlobalDelegate callback) throws URISyntaxException {
|
||||
if (this.config.metaGlobal == null) {
|
||||
this.config.metaGlobal = new MetaGlobal(config.metaURL(), credentials());
|
||||
}
|
||||
this.config.metaGlobal.fetch(callback);
|
||||
}
|
||||
|
||||
public void fetchInfoCollections(InfoCollectionsDelegate callback) throws URISyntaxException {
|
||||
if (this.config.infoCollections == null) {
|
||||
this.config.infoCollections = new InfoCollections(config.infoURL(), credentials());
|
||||
@ -429,6 +413,8 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
||||
* meta/global callbacks.
|
||||
*/
|
||||
public void processMetaGlobal(MetaGlobal global) {
|
||||
config.metaGlobal = global;
|
||||
|
||||
Long storageVersion = global.getStorageVersion();
|
||||
if (storageVersion < STORAGE_VERSION) {
|
||||
// Outdated server.
|
||||
@ -450,9 +436,7 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
||||
if (!remoteSyncID.equals(localSyncID)) {
|
||||
// Sync ID has changed. Reset timestamps and fetch new keys.
|
||||
resetClient(null);
|
||||
if (config.collectionKeys != null) {
|
||||
config.collectionKeys.clear();
|
||||
}
|
||||
config.purgeCryptoKeys();
|
||||
config.syncID = remoteSyncID;
|
||||
// TODO TODO TODO
|
||||
}
|
||||
@ -503,7 +487,7 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
||||
@Override
|
||||
public void onWiped(long timestamp) {
|
||||
session.resetClient(null);
|
||||
session.config.collectionKeys.clear(); // TODO: make sure we clear our keys timestamp.
|
||||
session.config.purgeCryptoKeys();
|
||||
session.config.persistToPrefs();
|
||||
|
||||
MetaGlobal mg = new MetaGlobal(metaURL, credentials);
|
||||
@ -565,54 +549,6 @@ public class GlobalSession implements CredentialsSource, PrefsSource, HttpRespon
|
||||
Logger.warn(LOG_TAG, "Got error uploading new meta/global.", e);
|
||||
freshStartDelegate.onFreshStartFailed(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaGlobalDelegate deferred() {
|
||||
final MetaGlobalDelegate self = this;
|
||||
return new MetaGlobalDelegate() {
|
||||
|
||||
@Override
|
||||
public void handleSuccess(final MetaGlobal global, final SyncStorageResponse response) {
|
||||
ThreadPool.run(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
self.handleSuccess(global, response);
|
||||
}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMissing(final MetaGlobal global, final SyncStorageResponse response) {
|
||||
ThreadPool.run(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
self.handleMissing(global, response);
|
||||
}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleFailure(final SyncStorageResponse response) {
|
||||
ThreadPool.run(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
self.handleFailure(response);
|
||||
}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleError(final Exception e) {
|
||||
ThreadPool.run(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
self.handleError(e);
|
||||
}});
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaGlobalDelegate deferred() {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,39 +1,6 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Android Sync Client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Richard Newman <rnewman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
/* 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;
|
||||
|
||||
@ -56,17 +23,13 @@ public class InfoCollections implements SyncStorageRequestDelegate {
|
||||
protected String infoURL;
|
||||
protected String credentials;
|
||||
|
||||
// Fetched objects.
|
||||
protected SyncStorageResponse response;
|
||||
private ExtendedJSONObject record;
|
||||
|
||||
// Fields.
|
||||
// Rather than storing decimal/double timestamps, as provided by the
|
||||
// server, we convert immediately to milliseconds since epoch.
|
||||
private HashMap<String, Long> timestamps;
|
||||
|
||||
public HashMap<String, Long> getTimestamps() {
|
||||
if (!this.wasSuccessful()) {
|
||||
if (this.timestamps == null) {
|
||||
throw new IllegalStateException("No record fetched.");
|
||||
}
|
||||
return this.timestamps;
|
||||
@ -76,9 +39,31 @@ public class InfoCollections implements SyncStorageRequestDelegate {
|
||||
return this.getTimestamps().get(collection);
|
||||
}
|
||||
|
||||
public boolean wasSuccessful() {
|
||||
return this.response.wasSuccessful() &&
|
||||
this.timestamps != null;
|
||||
/**
|
||||
* Test if a given collection needs to be updated.
|
||||
*
|
||||
* @param collection
|
||||
* The collection to test.
|
||||
* @param lastModified
|
||||
* Timestamp when local record was last modified.
|
||||
*/
|
||||
public boolean updateNeeded(String collection, long lastModified) {
|
||||
Logger.trace(LOG_TAG, "Testing " + collection + " for updateNeeded. Local last modified is " + lastModified + ".");
|
||||
|
||||
// No local record of modification time? Need an update.
|
||||
if (lastModified <= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// No meta/global on the server? We need an update. The server fetch will fail and
|
||||
// then we will upload a fresh meta/global.
|
||||
Long serverLastModified = getTimestamp(collection);
|
||||
if (serverLastModified == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, we need an update if our modification time is stale.
|
||||
return (serverLastModified.longValue() > lastModified);
|
||||
}
|
||||
|
||||
// Temporary location to store our callback.
|
||||
@ -90,7 +75,7 @@ public class InfoCollections implements SyncStorageRequestDelegate {
|
||||
}
|
||||
|
||||
public void fetch(InfoCollectionsDelegate callback) {
|
||||
if (this.response == null) {
|
||||
if (this.timestamps == null) {
|
||||
this.callback = callback;
|
||||
this.doFetch();
|
||||
return;
|
||||
@ -118,29 +103,12 @@ public class InfoCollections implements SyncStorageRequestDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
public SyncStorageResponse getResponse() {
|
||||
return this.response;
|
||||
}
|
||||
|
||||
protected ExtendedJSONObject ensureRecord() {
|
||||
if (record == null) {
|
||||
record = new ExtendedJSONObject();
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
||||
protected void setRecord(ExtendedJSONObject record) {
|
||||
this.record = record;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void unpack(SyncStorageResponse response) throws IllegalStateException, IOException, ParseException, NonObjectJSONException {
|
||||
this.response = response;
|
||||
this.setRecord(response.jsonObjectBody());
|
||||
Log.i(LOG_TAG, "info/collections is " + this.record.toJSONString());
|
||||
public void setFromRecord(ExtendedJSONObject record) throws IllegalStateException, IOException, ParseException, NonObjectJSONException {
|
||||
Log.i(LOG_TAG, "info/collections is " + record.toJSONString());
|
||||
HashMap<String, Long> map = new HashMap<String, Long>();
|
||||
|
||||
Set<Entry<String, Object>> entrySet = this.record.object.entrySet();
|
||||
Set<Entry<String, Object>> entrySet = record.object.entrySet();
|
||||
for (Entry<String, Object> entry : entrySet) {
|
||||
// These objects are most likely going to be Doubles. Regardless, we
|
||||
// want to get them in a more sane time format.
|
||||
@ -175,7 +143,7 @@ public class InfoCollections implements SyncStorageRequestDelegate {
|
||||
public void handleRequestSuccess(SyncStorageResponse response) {
|
||||
if (response.wasSuccessful()) {
|
||||
try {
|
||||
this.unpack(response);
|
||||
this.setFromRecord(response.jsonObjectBody());
|
||||
this.callback.handleSuccess(this);
|
||||
this.callback = null;
|
||||
} catch (Exception e) {
|
||||
|
@ -1,39 +1,6 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Android Sync Client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Richard Newman <rnewman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
/* 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;
|
||||
|
||||
@ -53,12 +20,6 @@ public class MetaGlobal implements SyncStorageRequestDelegate {
|
||||
protected String metaURL;
|
||||
protected String credentials;
|
||||
|
||||
public boolean isModified;
|
||||
protected boolean isNew;
|
||||
|
||||
// Fetched object.
|
||||
private CryptoRecord record;
|
||||
|
||||
// Fields.
|
||||
protected ExtendedJSONObject engines;
|
||||
protected Long storageVersion;
|
||||
@ -104,51 +65,52 @@ public class MetaGlobal implements SyncStorageRequestDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
private CryptoRecord ensureRecord() {
|
||||
if (this.record == null) {
|
||||
this.record = new CryptoRecord(new ExtendedJSONObject());
|
||||
}
|
||||
return this.record;
|
||||
protected ExtendedJSONObject asRecordContents() {
|
||||
ExtendedJSONObject json = new ExtendedJSONObject();
|
||||
json.put("storageVersion", storageVersion);
|
||||
json.put("engines", engines);
|
||||
json.put("syncID", syncID);
|
||||
return json;
|
||||
}
|
||||
|
||||
protected void setRecord(ExtendedJSONObject obj) throws IOException, ParseException, NonObjectJSONException {
|
||||
this.record = CryptoRecord.fromJSONRecord(obj);
|
||||
public CryptoRecord asCryptoRecord() {
|
||||
ExtendedJSONObject payload = this.asRecordContents();
|
||||
CryptoRecord record = new CryptoRecord(payload);
|
||||
record.collection = "meta";
|
||||
record.guid = "global";
|
||||
record.deleted = false;
|
||||
return record;
|
||||
}
|
||||
|
||||
private void unpack(SyncStorageResponse response) throws IllegalStateException, IOException, ParseException, NonObjectJSONException {
|
||||
this.setRecord(response.jsonObjectBody());
|
||||
public void setFromRecord(CryptoRecord record) throws IllegalStateException, IOException, ParseException, NonObjectJSONException {
|
||||
Log.i(LOG_TAG, "meta/global is " + record.payload.toJSONString());
|
||||
this.isModified = false;
|
||||
this.storageVersion = (Long) record.payload.get("storageVersion");
|
||||
this.engines = record.payload.getObject("engines");
|
||||
this.engines = record.payload.getObject("engines");
|
||||
this.syncID = (String) record.payload.get("syncID");
|
||||
}
|
||||
|
||||
public Long getStorageVersion() {
|
||||
return this.storageVersion;
|
||||
}
|
||||
|
||||
public void setStorageVersion(Long version) {
|
||||
this.storageVersion = version;
|
||||
this.ensureRecord().payload.put("storageVersion", version);
|
||||
this.isModified = true;
|
||||
}
|
||||
|
||||
public ExtendedJSONObject getEngines() {
|
||||
return engines;
|
||||
}
|
||||
|
||||
public void setEngines(ExtendedJSONObject engines) {
|
||||
this.engines = engines;
|
||||
this.ensureRecord().payload.put("engines", engines);
|
||||
this.isModified = true;
|
||||
}
|
||||
|
||||
public String getSyncID() {
|
||||
return syncID;
|
||||
}
|
||||
|
||||
public void setSyncID(String syncID) {
|
||||
this.syncID = syncID;
|
||||
this.ensureRecord().payload.put("syncID", syncID);
|
||||
this.isModified = true;
|
||||
}
|
||||
|
||||
// SyncStorageRequestDelegate methods for fetching.
|
||||
@ -169,7 +131,6 @@ public class MetaGlobal implements SyncStorageRequestDelegate {
|
||||
}
|
||||
|
||||
private void handleUploadSuccess(SyncStorageResponse response) {
|
||||
this.isModified = false;
|
||||
this.callback.handleSuccess(this, response);
|
||||
this.callback = null;
|
||||
}
|
||||
@ -177,7 +138,8 @@ public class MetaGlobal implements SyncStorageRequestDelegate {
|
||||
private void handleDownloadSuccess(SyncStorageResponse response) {
|
||||
if (response.wasSuccessful()) {
|
||||
try {
|
||||
this.unpack(response);
|
||||
CryptoRecord record = CryptoRecord.fromJSONRecord(response.jsonObjectBody());
|
||||
this.setFromRecord(record);
|
||||
this.callback.handleSuccess(this, response);
|
||||
this.callback = null;
|
||||
} catch (Exception e) {
|
||||
|
75
mobile/android/base/sync/PersistedMetaGlobal.java
Normal file
75
mobile/android/base/sync/PersistedMetaGlobal.java
Normal file
@ -0,0 +1,75 @@
|
||||
/* 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;
|
||||
|
||||
import org.mozilla.gecko.sync.CryptoRecord;
|
||||
import org.mozilla.gecko.sync.Logger;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
public class PersistedMetaGlobal {
|
||||
public static final String LOG_TAG = "PersistedMetaGlobal";
|
||||
|
||||
public static final String META_GLOBAL_SERVER_RESPONSE_BODY = "metaGlobalServerResponseBody";
|
||||
public static final String META_GLOBAL_LAST_MODIFIED = "metaGlobalLastModified";
|
||||
|
||||
protected SharedPreferences prefs;
|
||||
|
||||
public PersistedMetaGlobal(SharedPreferences prefs) {
|
||||
this.prefs = prefs;
|
||||
}
|
||||
|
||||
public MetaGlobal metaGlobal() {
|
||||
String json = prefs.getString(META_GLOBAL_SERVER_RESPONSE_BODY, null);
|
||||
if (json == null) {
|
||||
return null;
|
||||
}
|
||||
MetaGlobal metaGlobal = null;
|
||||
try {
|
||||
CryptoRecord cryptoRecord = CryptoRecord.fromJSONRecord(json);
|
||||
MetaGlobal mg = new MetaGlobal(null, null);
|
||||
mg.setFromRecord(cryptoRecord);
|
||||
metaGlobal = mg;
|
||||
} catch (Exception e) {
|
||||
Logger.warn(LOG_TAG, "Got exception decrypting persisted meta/global.", e);
|
||||
}
|
||||
return metaGlobal;
|
||||
}
|
||||
|
||||
public void persistMetaGlobal(MetaGlobal metaGlobal) {
|
||||
if (metaGlobal == null) {
|
||||
Logger.debug(LOG_TAG, "Clearing persisted meta/global.");
|
||||
prefs.edit().remove(META_GLOBAL_SERVER_RESPONSE_BODY).commit();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
CryptoRecord cryptoRecord = metaGlobal.asCryptoRecord();
|
||||
String json = cryptoRecord.toJSONString();
|
||||
Logger.debug(LOG_TAG, "Persisting meta/global.");
|
||||
prefs.edit().putString(META_GLOBAL_SERVER_RESPONSE_BODY, json).commit();
|
||||
} catch (Exception e) {
|
||||
Logger.warn(LOG_TAG, "Got exception encrypting while persisting meta/global.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public long lastModified() {
|
||||
return prefs.getLong(META_GLOBAL_LAST_MODIFIED, -1);
|
||||
}
|
||||
|
||||
public void persistLastModified(long lastModified) {
|
||||
if (lastModified <= 0) {
|
||||
Logger.debug(LOG_TAG, "Clearing persisted meta/global last modified timestamp.");
|
||||
prefs.edit().remove(META_GLOBAL_LAST_MODIFIED).commit();
|
||||
return;
|
||||
}
|
||||
Logger.debug(LOG_TAG, "Persisting meta/global last modified timestamp " + lastModified + ".");
|
||||
prefs.edit().putLong(META_GLOBAL_LAST_MODIFIED, lastModified).commit();
|
||||
}
|
||||
|
||||
public void purge() {
|
||||
persistLastModified(-1);
|
||||
persistMetaGlobal(null);
|
||||
}
|
||||
}
|
@ -1,43 +1,9 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Android Sync Client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Richard Newman <rnewman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
/* 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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
/**
|
||||
@ -51,8 +17,6 @@ import android.content.SharedPreferences;
|
||||
*
|
||||
*/
|
||||
public interface PrefsSource {
|
||||
public Context getContext();
|
||||
|
||||
/**
|
||||
* Return a SharedPreferences instance.
|
||||
* @param name
|
||||
|
@ -10,6 +10,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mozilla.gecko.sync.crypto.KeyBundle;
|
||||
import org.mozilla.gecko.sync.crypto.PersistedCrypto5Keys;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
@ -232,7 +233,9 @@ public class SyncConfiguration implements CredentialsSource {
|
||||
syncID = prefs.getString("syncID", null);
|
||||
Logger.info(LOG_TAG, "Set syncID from bundle: " + syncID);
|
||||
}
|
||||
// TODO: MetaGlobal, password, infoCollections, collectionKeys.
|
||||
// We don't set crypto/keys here because we need the syncKeyBundle to decrypt the JSON
|
||||
// and we won't have it on construction.
|
||||
// TODO: MetaGlobal, password, infoCollections.
|
||||
}
|
||||
|
||||
public void persistToPrefs() {
|
||||
@ -258,16 +261,10 @@ public class SyncConfiguration implements CredentialsSource {
|
||||
return username + ":" + password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionKeys getCollectionKeys() {
|
||||
return collectionKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyBundle keyForCollection(String collection) throws NoCollectionKeysSetException {
|
||||
return getCollectionKeys().keyBundleForCollection(collection);
|
||||
}
|
||||
|
||||
public void setCollectionKeys(CollectionKeys k) {
|
||||
collectionKeys = k;
|
||||
}
|
||||
@ -379,4 +376,19 @@ public class SyncConfiguration implements CredentialsSource {
|
||||
public long getPersistedServerClientRecordTimestamp() {
|
||||
return getPrefs().getLong(SyncConfiguration.CLIENT_RECORD_TIMESTAMP, 0);
|
||||
}
|
||||
|
||||
public void purgeCryptoKeys() {
|
||||
if (collectionKeys != null) {
|
||||
collectionKeys.clear();
|
||||
}
|
||||
persistedCryptoKeys().purge();
|
||||
}
|
||||
|
||||
public PersistedCrypto5Keys persistedCryptoKeys() {
|
||||
return new PersistedCrypto5Keys(getPrefs(), syncKeyBundle);
|
||||
}
|
||||
|
||||
public PersistedMetaGlobal persistedMetaGlobal() {
|
||||
return new PersistedMetaGlobal(getPrefs());
|
||||
}
|
||||
}
|
||||
|
99
mobile/android/base/sync/crypto/PersistedCrypto5Keys.java
Normal file
99
mobile/android/base/sync/crypto/PersistedCrypto5Keys.java
Normal file
@ -0,0 +1,99 @@
|
||||
/* 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.crypto;
|
||||
|
||||
import org.mozilla.gecko.sync.CollectionKeys;
|
||||
import org.mozilla.gecko.sync.CryptoRecord;
|
||||
import org.mozilla.gecko.sync.Logger;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
public class PersistedCrypto5Keys {
|
||||
public static final String LOG_TAG = "PersistedC5Keys";
|
||||
|
||||
public static final String CRYPTO5_KEYS_SERVER_RESPONSE_BODY = "crypto5KeysServerResponseBody";
|
||||
public static final String CRYPTO5_KEYS_LAST_MODIFIED = "crypto5KeysLastModified";
|
||||
|
||||
protected SharedPreferences prefs;
|
||||
protected KeyBundle syncKeyBundle;
|
||||
|
||||
public PersistedCrypto5Keys(SharedPreferences prefs, KeyBundle syncKeyBundle) {
|
||||
if (syncKeyBundle == null) {
|
||||
throw new IllegalArgumentException("Null syncKeyBundle passed in to PersistedCrypto5Keys constructor.");
|
||||
}
|
||||
this.prefs = prefs;
|
||||
this.syncKeyBundle = syncKeyBundle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get persisted crypto/keys.
|
||||
* <p>
|
||||
* crypto/keys is fetched from an encrypted JSON-encoded <code>CryptoRecord</code>.
|
||||
*
|
||||
* @return A <code>CollectionKeys</code> instance or <code>null</code> if none
|
||||
* is currently persisted.
|
||||
*/
|
||||
public CollectionKeys keys() {
|
||||
String keysJSON = prefs.getString(CRYPTO5_KEYS_SERVER_RESPONSE_BODY, null);
|
||||
if (keysJSON == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
CryptoRecord cryptoRecord = CryptoRecord.fromJSONRecord(keysJSON);
|
||||
CollectionKeys keys = new CollectionKeys();
|
||||
keys.setKeyPairsFromWBO(cryptoRecord, syncKeyBundle);
|
||||
return keys;
|
||||
} catch (Exception e) {
|
||||
Logger.warn(LOG_TAG, "Got exception decrypting persisted crypto/keys.", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist crypto/keys.
|
||||
* <p>
|
||||
* crypto/keys is stored as an encrypted JSON-encoded <code>CryptoRecord</code>.
|
||||
*
|
||||
* @param keys
|
||||
* The <code>CollectionKeys</code> object to persist, which should
|
||||
* have the same default key bundle as the sync key bundle.
|
||||
*/
|
||||
public void persistKeys(CollectionKeys keys) {
|
||||
if (keys == null) {
|
||||
Logger.debug(LOG_TAG, "Clearing persisted crypto/keys.");
|
||||
prefs.edit().remove(CRYPTO5_KEYS_SERVER_RESPONSE_BODY).commit();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
CryptoRecord cryptoRecord = keys.asCryptoRecord();
|
||||
cryptoRecord.keyBundle = syncKeyBundle;
|
||||
cryptoRecord.encrypt();
|
||||
String keysJSON = cryptoRecord.toJSONString();
|
||||
Logger.debug(LOG_TAG, "Persisting crypto/keys.");
|
||||
prefs.edit().putString(CRYPTO5_KEYS_SERVER_RESPONSE_BODY, keysJSON).commit();
|
||||
} catch (Exception e) {
|
||||
Logger.warn(LOG_TAG, "Got exception encrypting while persisting crypto/keys.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public long lastModified() {
|
||||
return prefs.getLong(CRYPTO5_KEYS_LAST_MODIFIED, -1);
|
||||
}
|
||||
|
||||
public void persistLastModified(long lastModified) {
|
||||
if (lastModified <= 0) {
|
||||
Logger.debug(LOG_TAG, "Clearing persisted crypto/keys last modified timestamp.");
|
||||
prefs.edit().remove(CRYPTO5_KEYS_LAST_MODIFIED).commit();
|
||||
return;
|
||||
}
|
||||
Logger.debug(LOG_TAG, "Persisting crypto/keys last modified timestamp " + lastModified + ".");
|
||||
prefs.edit().putLong(CRYPTO5_KEYS_LAST_MODIFIED, lastModified).commit();
|
||||
}
|
||||
|
||||
public void purge() {
|
||||
persistLastModified(-1);
|
||||
persistKeys(null);
|
||||
}
|
||||
}
|
@ -1,39 +1,6 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Android Sync Client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Richard Newman <rnewman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
/* 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.delegates;
|
||||
|
||||
@ -45,5 +12,4 @@ public interface MetaGlobalDelegate {
|
||||
public void handleMissing(MetaGlobal global, SyncStorageResponse response);
|
||||
public void handleFailure(SyncStorageResponse response);
|
||||
public void handleError(Exception e);
|
||||
public MetaGlobalDelegate deferred();
|
||||
}
|
||||
|
175
mobile/android/base/sync/stage/EnsureCrypto5KeysStage.java
Normal file
175
mobile/android/base/sync/stage/EnsureCrypto5KeysStage.java
Normal file
@ -0,0 +1,175 @@
|
||||
/* 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.stage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.mozilla.gecko.sync.CollectionKeys;
|
||||
import org.mozilla.gecko.sync.CryptoRecord;
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
import org.mozilla.gecko.sync.GlobalSession;
|
||||
import org.mozilla.gecko.sync.InfoCollections;
|
||||
import org.mozilla.gecko.sync.Logger;
|
||||
import org.mozilla.gecko.sync.NonObjectJSONException;
|
||||
import org.mozilla.gecko.sync.crypto.CryptoException;
|
||||
import org.mozilla.gecko.sync.crypto.PersistedCrypto5Keys;
|
||||
import org.mozilla.gecko.sync.delegates.KeyUploadDelegate;
|
||||
import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
|
||||
import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
|
||||
import org.mozilla.gecko.sync.net.SyncStorageResponse;
|
||||
|
||||
public class EnsureCrypto5KeysStage implements GlobalSyncStage, SyncStorageRequestDelegate, KeyUploadDelegate {
|
||||
private static final String LOG_TAG = "EnsureC5KeysStage";
|
||||
private static final String CRYPTO_COLLECTION = "crypto";
|
||||
protected GlobalSession session;
|
||||
protected boolean retrying = false;
|
||||
|
||||
@Override
|
||||
public void execute(GlobalSession session) throws NoSuchStageException {
|
||||
this.session = session;
|
||||
|
||||
InfoCollections infoCollections = session.config.infoCollections;
|
||||
if (infoCollections == null) {
|
||||
session.abort(null, "No info/collections set in EnsureCrypto5KeysStage.");
|
||||
return;
|
||||
}
|
||||
|
||||
PersistedCrypto5Keys pck = session.config.persistedCryptoKeys();
|
||||
long lastModified = pck.lastModified();
|
||||
if (!infoCollections.updateNeeded(CRYPTO_COLLECTION, lastModified)) {
|
||||
// Try to use our local collection keys for this session.
|
||||
Logger.info(LOG_TAG, "Trying to use persisted collection keys for this session.");
|
||||
CollectionKeys keys = pck.keys();
|
||||
if (keys != null) {
|
||||
Logger.info(LOG_TAG, "Using persisted collection keys for this session.");
|
||||
session.config.setCollectionKeys(keys);
|
||||
session.advance();
|
||||
return;
|
||||
}
|
||||
Logger.info(LOG_TAG, "Failed to use persisted collection keys for this session.");
|
||||
}
|
||||
|
||||
// We need an update: fetch or upload keys as necessary.
|
||||
Logger.info(LOG_TAG, "Fetching fresh collection keys for this session.");
|
||||
try {
|
||||
SyncStorageRecordRequest request = new SyncStorageRecordRequest(session.wboURI(CRYPTO_COLLECTION, "keys"));
|
||||
request.delegate = this;
|
||||
request.get();
|
||||
} catch (URISyntaxException e) {
|
||||
session.abort(e, "Invalid URI.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String credentials() {
|
||||
return session.credentials();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String ifUnmodifiedSince() {
|
||||
// TODO: last key time!
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequestSuccess(SyncStorageResponse response) {
|
||||
CollectionKeys k = new CollectionKeys();
|
||||
try {
|
||||
ExtendedJSONObject body = response.jsonObjectBody();
|
||||
if (Logger.LOG_PERSONAL_INFORMATION) {
|
||||
Logger.pii(LOG_TAG, "Fetched keys: " + body.toJSONString());
|
||||
}
|
||||
k.setKeyPairsFromWBO(CryptoRecord.fromJSONRecord(body), session.config.syncKeyBundle);
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
session.abort(e, "Invalid keys WBO.");
|
||||
return;
|
||||
} catch (ParseException e) {
|
||||
session.abort(e, "Invalid keys WBO.");
|
||||
return;
|
||||
} catch (NonObjectJSONException e) {
|
||||
session.abort(e, "Invalid keys WBO.");
|
||||
return;
|
||||
} catch (IOException e) {
|
||||
// Some kind of lower-level error.
|
||||
session.abort(e, "IOException fetching keys.");
|
||||
return;
|
||||
} catch (CryptoException e) {
|
||||
session.abort(e, "CryptoException handling keys WBO.");
|
||||
return;
|
||||
}
|
||||
|
||||
// New keys! Persist keys and server timestamp.
|
||||
Logger.info(LOG_TAG, "Setting fetched keys for this session.");
|
||||
session.config.setCollectionKeys(k);
|
||||
Logger.trace(LOG_TAG, "Persisting fetched keys and last modified.");
|
||||
PersistedCrypto5Keys pck = session.config.persistedCryptoKeys();
|
||||
pck.persistKeys(k);
|
||||
// Take the timestamp from the response since it is later than the timestamp from info/collections.
|
||||
pck.persistLastModified(response.normalizedWeaveTimestamp());
|
||||
|
||||
session.advance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequestFailure(SyncStorageResponse response) {
|
||||
if (retrying) {
|
||||
session.handleHTTPError(response, "Failure in refetching uploaded keys.");
|
||||
return;
|
||||
}
|
||||
|
||||
int statusCode = response.getStatusCode();
|
||||
Logger.debug(LOG_TAG, "Got " + statusCode + " fetching keys.");
|
||||
if (statusCode == 404) {
|
||||
// No keys. Generate and upload, then refetch.
|
||||
CryptoRecord keysWBO;
|
||||
try {
|
||||
keysWBO = CollectionKeys.generateCollectionKeysRecord();
|
||||
} catch (CryptoException e) {
|
||||
session.abort(e, "Couldn't generate new key bundle.");
|
||||
return;
|
||||
}
|
||||
keysWBO.keyBundle = session.config.syncKeyBundle;
|
||||
try {
|
||||
keysWBO.encrypt();
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Shouldn't occur, so let's not waste too much time on niceties. TODO
|
||||
session.abort(e, "Couldn't encrypt new key bundle: unsupported encoding.");
|
||||
return;
|
||||
} catch (CryptoException e) {
|
||||
session.abort(e, "Couldn't encrypt new key bundle.");
|
||||
return;
|
||||
}
|
||||
session.uploadKeys(keysWBO, this);
|
||||
return;
|
||||
}
|
||||
session.handleHTTPError(response, "Failure fetching keys.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequestError(Exception ex) {
|
||||
session.abort(ex, "Failure fetching keys.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKeysUploaded() {
|
||||
Logger.debug(LOG_TAG, "New keys uploaded. Starting stage again to fetch them.");
|
||||
try {
|
||||
retrying = true;
|
||||
this.execute(this.session);
|
||||
} catch (NoSuchStageException e) {
|
||||
session.abort(e, "No such stage.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onKeyUploadFailed(Exception e) {
|
||||
Logger.warn(LOG_TAG, "Key upload failed. Aborting sync.");
|
||||
session.abort(e, "Key upload failed.");
|
||||
}
|
||||
}
|
@ -1,50 +1,20 @@
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Android Sync Client.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Richard Newman <rnewman@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
/* 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.stage;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.mozilla.gecko.sync.GlobalSession;
|
||||
import org.mozilla.gecko.sync.InfoCollections;
|
||||
import org.mozilla.gecko.sync.Logger;
|
||||
import org.mozilla.gecko.sync.MetaGlobal;
|
||||
import org.mozilla.gecko.sync.PersistedMetaGlobal;
|
||||
import org.mozilla.gecko.sync.delegates.MetaGlobalDelegate;
|
||||
import org.mozilla.gecko.sync.net.SyncStorageResponse;
|
||||
|
||||
public class FetchMetaGlobalStage implements GlobalSyncStage {
|
||||
private static final String LOG_TAG = "FetchMetaGlobalStage";
|
||||
private static final String META_COLLECTION = "meta";
|
||||
|
||||
public class StageMetaGlobalDelegate implements MetaGlobalDelegate {
|
||||
|
||||
@ -55,6 +25,12 @@ public class FetchMetaGlobalStage implements GlobalSyncStage {
|
||||
|
||||
@Override
|
||||
public void handleSuccess(MetaGlobal global, SyncStorageResponse response) {
|
||||
Logger.trace(LOG_TAG, "Persisting fetched meta/global and last modified.");
|
||||
PersistedMetaGlobal pmg = session.config.persistedMetaGlobal();
|
||||
pmg.persistMetaGlobal(global);
|
||||
// Take the timestamp from the response since it is later than the timestamp from info/collections.
|
||||
pmg.persistLastModified(response.normalizedWeaveTimestamp());
|
||||
|
||||
session.processMetaGlobal(global);
|
||||
}
|
||||
|
||||
@ -72,21 +48,32 @@ public class FetchMetaGlobalStage implements GlobalSyncStage {
|
||||
public void handleMissing(MetaGlobal global, SyncStorageResponse response) {
|
||||
session.processMissingMetaGlobal(global);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MetaGlobalDelegate deferred() {
|
||||
// TODO: defer!
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(GlobalSession session) throws NoSuchStageException {
|
||||
try {
|
||||
session.fetchMetaGlobal(new StageMetaGlobalDelegate(session));
|
||||
} catch (URISyntaxException e) {
|
||||
session.abort(e, "Invalid URI.");
|
||||
InfoCollections infoCollections = session.config.infoCollections;
|
||||
if (infoCollections == null) {
|
||||
session.abort(null, "No info/collections set in FetchMetaGlobalStage.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
long lastModified = session.config.persistedMetaGlobal().lastModified();
|
||||
if (!infoCollections.updateNeeded(META_COLLECTION, lastModified)) {
|
||||
// Try to use our local collection keys for this session.
|
||||
Logger.info(LOG_TAG, "Trying to use persisted meta/global for this session.");
|
||||
MetaGlobal global = session.config.persistedMetaGlobal().metaGlobal();
|
||||
if (global != null) {
|
||||
Logger.info(LOG_TAG, "Using persisted meta/global for this session.");
|
||||
session.processMetaGlobal(global); // Calls session.advance().
|
||||
return;
|
||||
}
|
||||
Logger.info(LOG_TAG, "Failed to use persisted meta/global for this session.");
|
||||
}
|
||||
|
||||
// We need an update: fetch or upload meta/global as necessary.
|
||||
Logger.info(LOG_TAG, "Fetching fresh meta/global for this session.");
|
||||
MetaGlobal global = new MetaGlobal(session.config.metaURL(), session.credentials());
|
||||
global.fetch(new StageMetaGlobalDelegate(session));
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ public abstract class ServerSyncStage implements
|
||||
*/
|
||||
protected Repository wrappedServerRepo() throws NoCollectionKeysSetException, URISyntaxException {
|
||||
String collection = this.getCollection();
|
||||
KeyBundle collectionKey = session.keyForCollection(collection);
|
||||
KeyBundle collectionKey = session.keyBundleForCollection(collection);
|
||||
Crypto5MiddlewareRepository cryptoRepo = new Crypto5MiddlewareRepository(getRemoteRepository(), collectionKey);
|
||||
cryptoRepo.recordFactory = getRecordFactory();
|
||||
return cryptoRepo;
|
||||
|
@ -162,7 +162,7 @@ public class SyncClientsEngineStage implements GlobalSyncStage {
|
||||
@Override
|
||||
public KeyBundle keyBundle() {
|
||||
try {
|
||||
return session.keyForCollection(COLLECTION_NAME);
|
||||
return session.keyBundleForCollection(COLLECTION_NAME);
|
||||
} catch (NoCollectionKeysSetException e) {
|
||||
session.abort(e, "No collection keys set.");
|
||||
return null;
|
||||
@ -241,7 +241,7 @@ public class SyncClientsEngineStage implements GlobalSyncStage {
|
||||
@Override
|
||||
public KeyBundle keyBundle() {
|
||||
try {
|
||||
return session.keyForCollection(COLLECTION_NAME);
|
||||
return session.keyBundleForCollection(COLLECTION_NAME);
|
||||
} catch (NoCollectionKeysSetException e) {
|
||||
session.abort(e, "No collection keys set.");
|
||||
return null;
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user