|
|
@ -83,6 +83,7 @@ import java.io.InputStream;
|
|
|
|
import java.io.InputStreamReader;
|
|
|
|
import java.io.InputStreamReader;
|
|
|
|
import java.io.OutputStream;
|
|
|
|
import java.io.OutputStream;
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
|
|
|
|
import java.security.GeneralSecurityException;
|
|
|
|
import java.security.SecureRandom;
|
|
|
|
import java.security.SecureRandom;
|
|
|
|
import java.security.spec.KeySpec;
|
|
|
|
import java.security.spec.KeySpec;
|
|
|
|
import java.text.DateFormat;
|
|
|
|
import java.text.DateFormat;
|
|
|
@ -1535,13 +1536,12 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
|
|
|
|
String command = args.getString("command");
|
|
|
|
String command = args.getString("command");
|
|
|
|
|
|
|
|
|
|
|
|
JSONObject jrequest = new JSONObject();
|
|
|
|
JSONObject jrequest = new JSONObject();
|
|
|
|
jrequest.put("command", command);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ("sync".equals(command)) {
|
|
|
|
if ("sync".equals(command)) {
|
|
|
|
DB db = DB.getInstance(context);
|
|
|
|
DB db = DB.getInstance(context);
|
|
|
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
|
|
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
|
|
|
long sync_status = prefs.getLong("sync_status", new Date().getTime());
|
|
|
|
long lrevision = prefs.getLong("sync_status", new Date().getTime());
|
|
|
|
Log.i("Cloud sync status=" + sync_status);
|
|
|
|
Log.i("Cloud sync status=" + lrevision);
|
|
|
|
|
|
|
|
|
|
|
|
for (EntitySync s : db.sync().getSync(null, null, Long.MAX_VALUE))
|
|
|
|
for (EntitySync s : db.sync().getSync(null, null, Long.MAX_VALUE))
|
|
|
|
Log.i("Cloud sync " + s.entity + ":" + s.reference + " " + s.action + " " + new Date(s.time));
|
|
|
|
Log.i("Cloud sync " + s.entity + ":" + s.reference + " " + s.action + " " + new Date(s.time));
|
|
|
@ -1549,7 +1549,7 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
|
|
|
|
|
|
|
|
|
|
|
|
JSONObject jsyncstatus = new JSONObject();
|
|
|
|
JSONObject jsyncstatus = new JSONObject();
|
|
|
|
jsyncstatus.put("key", "sync.status");
|
|
|
|
jsyncstatus.put("key", "sync.status");
|
|
|
|
jsyncstatus.put("rev", sync_status);
|
|
|
|
jsyncstatus.put("rev", lrevision);
|
|
|
|
|
|
|
|
|
|
|
|
JSONArray jitems = new JSONArray();
|
|
|
|
JSONArray jitems = new JSONArray();
|
|
|
|
jitems.put(jsyncstatus);
|
|
|
|
jitems.put(jsyncstatus);
|
|
|
@ -1561,96 +1561,151 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
|
|
|
|
|
|
|
|
|
|
|
|
if (jitems.length() == 0) {
|
|
|
|
if (jitems.length() == 0) {
|
|
|
|
Log.i("Cloud server is empty");
|
|
|
|
Log.i("Cloud server is empty");
|
|
|
|
|
|
|
|
sendLocalData(context, user, password, lrevision);
|
|
|
|
|
|
|
|
} else if (jitems.length() == 1) {
|
|
|
|
|
|
|
|
Log.i("Cloud sync check");
|
|
|
|
|
|
|
|
jsyncstatus = jitems.getJSONObject(0);
|
|
|
|
|
|
|
|
receiveRemoteData(context, user, password, lrevision, jsyncstatus);
|
|
|
|
|
|
|
|
} else
|
|
|
|
|
|
|
|
throw new IllegalArgumentException("Expected one status item");
|
|
|
|
|
|
|
|
} else
|
|
|
|
|
|
|
|
CloudSync.perform(context, user, password, command, jrequest);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
protected void onExecuted(Bundle args, Void data) {
|
|
|
|
|
|
|
|
String command = args.getString("command");
|
|
|
|
|
|
|
|
if ("logout".equals(command))
|
|
|
|
|
|
|
|
prefs.edit()
|
|
|
|
|
|
|
|
.remove("cloud_user")
|
|
|
|
|
|
|
|
.remove("cloud_password")
|
|
|
|
|
|
|
|
.apply();
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
prefs.edit()
|
|
|
|
|
|
|
|
.putString("cloud_user", args.getString("user"))
|
|
|
|
|
|
|
|
.putString("cloud_password", args.getString("password"))
|
|
|
|
|
|
|
|
.apply();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
view.post(new Runnable() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void run() {
|
|
|
|
|
|
|
|
view.scrollTo(0, cardCloud.getTop());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
protected void onException(Bundle args, Throwable ex) {
|
|
|
|
|
|
|
|
if (ex instanceof SecurityException) {
|
|
|
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(getContext())
|
|
|
|
|
|
|
|
.setIcon(R.drawable.twotone_warning_24)
|
|
|
|
|
|
|
|
.setTitle(getString(R.string.title_advanced_cloud_invalid))
|
|
|
|
|
|
|
|
.setNegativeButton(android.R.string.cancel, null);
|
|
|
|
|
|
|
|
String message = ex.getMessage();
|
|
|
|
|
|
|
|
if (!TextUtils.isEmpty(message))
|
|
|
|
|
|
|
|
builder.setMessage(message);
|
|
|
|
|
|
|
|
builder.show();
|
|
|
|
|
|
|
|
} else
|
|
|
|
|
|
|
|
Log.unexpectedError(getParentFragmentManager(), ex);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void sendLocalData(Context context, String user, String password, long lrevision) throws JSONException, GeneralSecurityException, IOException {
|
|
|
|
|
|
|
|
DB db = DB.getInstance(context);
|
|
|
|
List<EntityAccount> accounts = db.account().getSynchronizingAccounts(null);
|
|
|
|
List<EntityAccount> accounts = db.account().getSynchronizingAccounts(null);
|
|
|
|
Log.i("Cloud accounts=" + (accounts == null ? null : accounts.size()));
|
|
|
|
Log.i("Cloud accounts=" + (accounts == null ? null : accounts.size()));
|
|
|
|
if (accounts == null || accounts.size() == 0)
|
|
|
|
if (accounts == null || accounts.size() == 0)
|
|
|
|
return null; // nothing to offer
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
JSONArray jupload = new JSONArray();
|
|
|
|
JSONArray jupload = new JSONArray();
|
|
|
|
|
|
|
|
|
|
|
|
JSONArray juuids = new JSONArray();
|
|
|
|
JSONArray jaccountuuids = new JSONArray();
|
|
|
|
for (EntityAccount account : accounts)
|
|
|
|
for (EntityAccount account : accounts)
|
|
|
|
if (!TextUtils.isEmpty(account.uuid)) {
|
|
|
|
if (!TextUtils.isEmpty(account.uuid)) {
|
|
|
|
juuids.put(account.uuid);
|
|
|
|
jaccountuuids.put(account.uuid);
|
|
|
|
|
|
|
|
|
|
|
|
JSONArray jidentities = new JSONArray();
|
|
|
|
JSONArray jidentitieuuids = new JSONArray();
|
|
|
|
List<EntityIdentity> identities = db.identity().getIdentities(account.id);
|
|
|
|
List<EntityIdentity> identities = db.identity().getIdentities(account.id);
|
|
|
|
if (identities != null)
|
|
|
|
if (identities != null)
|
|
|
|
for (EntityIdentity identity : identities)
|
|
|
|
for (EntityIdentity identity : identities)
|
|
|
|
if (!TextUtils.isEmpty(identity.uuid)) {
|
|
|
|
if (!TextUtils.isEmpty(identity.uuid)) {
|
|
|
|
jidentities.put(identity.uuid);
|
|
|
|
jidentitieuuids.put(identity.uuid);
|
|
|
|
|
|
|
|
|
|
|
|
JSONObject jitem = new JSONObject();
|
|
|
|
JSONObject jidentity = new JSONObject();
|
|
|
|
jitem.put("key", "identity." + identity.uuid);
|
|
|
|
jidentity.put("key", "identity." + identity.uuid);
|
|
|
|
jitem.put("val", identity.toJSON().toString());
|
|
|
|
jidentity.put("val", identity.toJSON().toString());
|
|
|
|
jitem.put("rev", sync_status);
|
|
|
|
jidentity.put("rev", lrevision);
|
|
|
|
jupload.put(jitem);
|
|
|
|
jupload.put(jidentity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
JSONObject jaccountdata = new JSONObject();
|
|
|
|
JSONObject jaccountdata = new JSONObject();
|
|
|
|
jaccountdata.put("account", account.toJSON());
|
|
|
|
jaccountdata.put("account", account.toJSON());
|
|
|
|
jaccountdata.put("identities", jidentities);
|
|
|
|
jaccountdata.put("identities", jidentitieuuids);
|
|
|
|
|
|
|
|
|
|
|
|
JSONObject jitem = new JSONObject();
|
|
|
|
JSONObject jaccount = new JSONObject();
|
|
|
|
jitem.put("key", "account." + account.uuid);
|
|
|
|
jaccount.put("key", "account." + account.uuid);
|
|
|
|
jitem.put("val", jaccountdata.toString());
|
|
|
|
jaccount.put("val", jaccountdata.toString());
|
|
|
|
jitem.put("rev", sync_status);
|
|
|
|
jaccount.put("rev", lrevision);
|
|
|
|
jupload.put(jitem);
|
|
|
|
jupload.put(jaccount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
JSONObject jaccounts = new JSONObject();
|
|
|
|
JSONObject jaccountuuidsholder = new JSONObject();
|
|
|
|
jaccounts.put("uuids", juuids);
|
|
|
|
jaccountuuidsholder.put("uuids", jaccountuuids);
|
|
|
|
|
|
|
|
|
|
|
|
JSONObject jstatus = new JSONObject();
|
|
|
|
JSONObject jaccountstatus = new JSONObject();
|
|
|
|
jstatus.put("accounts", jaccounts);
|
|
|
|
jaccountstatus.put("accounts", jaccountuuidsholder);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JSONObject jsyncstatus = new JSONObject();
|
|
|
|
jsyncstatus.put("key", "sync.status");
|
|
|
|
jsyncstatus.put("key", "sync.status");
|
|
|
|
jsyncstatus.put("val", jstatus.toString());
|
|
|
|
jsyncstatus.put("val", jaccountstatus.toString());
|
|
|
|
jsyncstatus.put("rev", sync_status);
|
|
|
|
jsyncstatus.put("rev", lrevision);
|
|
|
|
jupload.put(jsyncstatus);
|
|
|
|
jupload.put(jsyncstatus);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JSONObject jrequest = new JSONObject();
|
|
|
|
jrequest.put("items", jupload);
|
|
|
|
jrequest.put("items", jupload);
|
|
|
|
CloudSync.perform(context, user, password, "write", jrequest);
|
|
|
|
CloudSync.perform(context, user, password, "write", jrequest);
|
|
|
|
|
|
|
|
|
|
|
|
prefs.edit().putLong("sync_status", sync_status).apply();
|
|
|
|
prefs.edit().putLong("sync_status", lrevision).apply();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void receiveRemoteData(Context context, String user, String password, long lrevision, JSONObject jsyncstatus) throws JSONException, GeneralSecurityException, IOException {
|
|
|
|
|
|
|
|
DB db = DB.getInstance(context);
|
|
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
long rrevision = jsyncstatus.getLong("rev");
|
|
|
|
} else if (jitems.length() == 1) {
|
|
|
|
Log.i("Cloud revision=" + lrevision + "/" + rrevision);
|
|
|
|
JSONObject jitem = jitems.getJSONObject(0);
|
|
|
|
|
|
|
|
long rev = jitem.getLong("rev");
|
|
|
|
|
|
|
|
Log.i("Cloud status revision=" + rev + "/" + sync_status);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (BuildConfig.DEBUG)
|
|
|
|
if (BuildConfig.DEBUG)
|
|
|
|
sync_status--;
|
|
|
|
lrevision--;
|
|
|
|
|
|
|
|
|
|
|
|
if (rev <= sync_status)
|
|
|
|
if (rrevision <= lrevision)
|
|
|
|
return null; // no changes
|
|
|
|
return; // no changes
|
|
|
|
|
|
|
|
|
|
|
|
// New revision
|
|
|
|
// New revision
|
|
|
|
JSONArray jdownload = new JSONArray();
|
|
|
|
JSONArray jdownload = new JSONArray();
|
|
|
|
|
|
|
|
|
|
|
|
// Get accounts
|
|
|
|
// Get accounts
|
|
|
|
JSONObject jstatus = new JSONObject(jitem.getString("val"));
|
|
|
|
JSONObject jstatus = new JSONObject(jsyncstatus.getString("val"));
|
|
|
|
JSONObject jaccounts = jstatus.getJSONObject("accounts");
|
|
|
|
JSONObject jaccountstatus = jstatus.getJSONObject("accounts");
|
|
|
|
JSONArray juuids = jaccounts.getJSONArray("uuids");
|
|
|
|
JSONArray jaccountuuids = jaccountstatus.getJSONArray("uuids");
|
|
|
|
for (int i = 0; i < juuids.length(); i++) {
|
|
|
|
for (int i = 0; i < jaccountuuids.length(); i++) {
|
|
|
|
String uuid = juuids.getString(i);
|
|
|
|
String uuid = jaccountuuids.getString(i);
|
|
|
|
JSONObject jaccount = new JSONObject();
|
|
|
|
JSONObject jaccount = new JSONObject();
|
|
|
|
jaccount.put("key", "account." + uuid);
|
|
|
|
jaccount.put("key", "account." + uuid);
|
|
|
|
jaccount.put("rev", sync_status);
|
|
|
|
jaccount.put("rev", lrevision);
|
|
|
|
jdownload.put(jaccount);
|
|
|
|
jdownload.put(jaccount);
|
|
|
|
Log.i("Cloud account " + uuid);
|
|
|
|
Log.i("Cloud account " + uuid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (jdownload.length() > 0) {
|
|
|
|
if (jdownload.length() > 0) {
|
|
|
|
Log.i("Cloud getting accounts");
|
|
|
|
Log.i("Cloud getting accounts");
|
|
|
|
|
|
|
|
JSONObject jrequest = new JSONObject();
|
|
|
|
jrequest.put("items", jdownload);
|
|
|
|
jrequest.put("items", jdownload);
|
|
|
|
jresponse = CloudSync.perform(context, user, password, "sync", jrequest);
|
|
|
|
JSONObject jresponse = CloudSync.perform(context, user, password, "sync", jrequest);
|
|
|
|
|
|
|
|
|
|
|
|
// Process accounts
|
|
|
|
// Process accounts
|
|
|
|
Log.i("Cloud processing accounts");
|
|
|
|
Log.i("Cloud processing accounts");
|
|
|
|
jitems = jresponse.getJSONArray("items");
|
|
|
|
JSONArray jitems = jresponse.getJSONArray("items");
|
|
|
|
jdownload = new JSONArray();
|
|
|
|
jdownload = new JSONArray();
|
|
|
|
for (int i = 0; i < jitems.length(); i++) {
|
|
|
|
for (int i = 0; i < jitems.length(); i++) {
|
|
|
|
JSONObject jaccount = jitems.getJSONObject(i);
|
|
|
|
JSONObject jaccount = jitems.getJSONObject(i);
|
|
|
@ -1670,7 +1725,7 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
|
|
|
|
for (int j = 0; j < jidentities.length(); j++) {
|
|
|
|
for (int j = 0; j < jidentities.length(); j++) {
|
|
|
|
JSONObject jidentity = new JSONObject();
|
|
|
|
JSONObject jidentity = new JSONObject();
|
|
|
|
jidentity.put("key", "identity." + jidentities.getString(j));
|
|
|
|
jidentity.put("key", "identity." + jidentities.getString(j));
|
|
|
|
jidentity.put("rev", sync_status);
|
|
|
|
jidentity.put("rev", lrevision);
|
|
|
|
jdownload.put(jidentity);
|
|
|
|
jdownload.put(jidentity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1685,9 +1740,9 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
|
|
|
|
Log.i("Cloud processing identities");
|
|
|
|
Log.i("Cloud processing identities");
|
|
|
|
jitems = jresponse.getJSONArray("items");
|
|
|
|
jitems = jresponse.getJSONArray("items");
|
|
|
|
for (int i = 0; i < jitems.length(); i++) {
|
|
|
|
for (int i = 0; i < jitems.length(); i++) {
|
|
|
|
JSONObject jaccount = jitems.getJSONObject(i);
|
|
|
|
JSONObject jidentity = jitems.getJSONObject(i);
|
|
|
|
String value = jaccount.getString("val");
|
|
|
|
String value = jidentity.getString("val");
|
|
|
|
long revision = jaccount.getLong("rev");
|
|
|
|
long revision = jidentity.getLong("rev");
|
|
|
|
EntityIdentity ridentity = EntityIdentity.fromJSON(new JSONObject(value));
|
|
|
|
EntityIdentity ridentity = EntityIdentity.fromJSON(new JSONObject(value));
|
|
|
|
EntityIdentity lidentity = db.identity().getIdentityByUUID(ridentity.uuid);
|
|
|
|
EntityIdentity lidentity = db.identity().getIdentityByUUID(ridentity.uuid);
|
|
|
|
Log.i("Cloud identity " + ridentity.uuid + "=" + (lidentity == null ? "insert" : "update") +
|
|
|
|
Log.i("Cloud identity " + ridentity.uuid + "=" + (lidentity == null ? "insert" : "update") +
|
|
|
@ -1697,50 +1752,7 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
prefs.edit().putLong("sync_status", rev).apply();
|
|
|
|
prefs.edit().putLong("sync_status", rrevision).apply();
|
|
|
|
} else
|
|
|
|
|
|
|
|
throw new IllegalArgumentException("Expected one status item");
|
|
|
|
|
|
|
|
} else
|
|
|
|
|
|
|
|
CloudSync.perform(context, user, password, command, jrequest);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
protected void onExecuted(Bundle args, Void data) {
|
|
|
|
|
|
|
|
String command = args.getString("command");
|
|
|
|
|
|
|
|
if ("logout".equals(command))
|
|
|
|
|
|
|
|
prefs.edit()
|
|
|
|
|
|
|
|
.remove("cloud_user")
|
|
|
|
|
|
|
|
.remove("cloud_password")
|
|
|
|
|
|
|
|
.apply();
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
prefs.edit()
|
|
|
|
|
|
|
|
.putString("cloud_user", args.getString("user"))
|
|
|
|
|
|
|
|
.putString("cloud_password", args.getString("password"))
|
|
|
|
|
|
|
|
.apply();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
view.post(new Runnable() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void run() {
|
|
|
|
|
|
|
|
view.scrollTo(0, cardCloud.getTop());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
protected void onException(Bundle args, Throwable ex) {
|
|
|
|
|
|
|
|
if (ex instanceof SecurityException) {
|
|
|
|
|
|
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(getContext())
|
|
|
|
|
|
|
|
.setIcon(R.drawable.twotone_warning_24)
|
|
|
|
|
|
|
|
.setTitle(getString(R.string.title_advanced_cloud_invalid))
|
|
|
|
|
|
|
|
.setNegativeButton(android.R.string.cancel, null);
|
|
|
|
|
|
|
|
String message = ex.getMessage();
|
|
|
|
|
|
|
|
if (!TextUtils.isEmpty(message))
|
|
|
|
|
|
|
|
builder.setMessage(message);
|
|
|
|
|
|
|
|
builder.show();
|
|
|
|
|
|
|
|
} else
|
|
|
|
|
|
|
|
Log.unexpectedError(getParentFragmentManager(), ex);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}.execute(FragmentOptionsBackup.this, args, "cloud");
|
|
|
|
}.execute(FragmentOptionsBackup.this, args, "cloud");
|
|
|
|
}
|
|
|
|
}
|
|
|
|