Cloud sync: activate

This commit is contained in:
M66B 2023-01-22 12:43:33 +01:00
parent f731796480
commit 0ccc27d55c
6 changed files with 96 additions and 22 deletions

View File

@ -170,6 +170,7 @@ android {
buildConfigField "String", "BITBUCKET_DOWNLOADS_URI", "\"https://bitbucket.org/M66B/fairemail-test/downloads/\""
buildConfigField "String", "ANNOUNCEMENT_URI", "\"https://gist.githubusercontent.com/M66B/d544192ca56224839d6ba0f2f6314c1f/raw/\""
buildConfigField "String", "CLOUD_URI", "\"https://api.fairemail.net/sync\""
buildConfigField "String", "CLOUD_EMAIL", "\"cloud@in.faircode.eu\""
buildConfigField "String", "TX_URI", localProperties.getProperty("paypal.uri", "\"\"")
buildConfigField "String", "GPA_URI", localProperties.getProperty("gpa.uri", "\"\"")
buildConfigField "String", "INFO_URI", localProperties.getProperty("info.uri", "\"\"")
@ -191,6 +192,7 @@ android {
buildConfigField "String", "BITBUCKET_DOWNLOADS_URI", "\"https://bitbucket.org/M66B/fairemail-test/downloads/\""
buildConfigField "String", "ANNOUNCEMENT_URI", "\"https://gist.githubusercontent.com/M66B/d544192ca56224839d6ba0f2f6314c1f/raw/\""
buildConfigField "String", "CLOUD_URI", "\"https://api.fairemail.net/sync\""
buildConfigField "String", "CLOUD_EMAIL", "\"cloud@in.faircode.eu\""
buildConfigField "String", "TX_URI", "\"\""
buildConfigField "String", "GPA_URI", "\"\""
buildConfigField "String", "INFO_URI", "\"\""
@ -213,6 +215,7 @@ android {
buildConfigField "String", "BITBUCKET_DOWNLOADS_URI", "\"\""
buildConfigField "String", "ANNOUNCEMENT_URI", "\"\""
buildConfigField "String", "CLOUD_URI", "\"\""
buildConfigField "String", "CLOUD_EMAIL", "\"\""
buildConfigField "String", "TX_URI", "\"\""
buildConfigField "String", "GPA_URI", "\"\""
buildConfigField "String", "INFO_URI", "\"\""
@ -235,6 +238,7 @@ android {
buildConfigField "String", "BITBUCKET_DOWNLOADS_URI", "\"\""
buildConfigField "String", "ANNOUNCEMENT_URI", "\"\""
buildConfigField "String", "CLOUD_URI", "\"\""
buildConfigField "String", "CLOUD_EMAIL", "\"\""
buildConfigField "String", "TX_URI", "\"\""
buildConfigField "String", "GPA_URI", "\"\""
buildConfigField "String", "INFO_URI", "\"\""

View File

@ -71,9 +71,21 @@ public class ActivityCompose extends ActivityBase implements FragmentManager.OnB
@Override
public void onBackStackChanged() {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
String action = getIntent().getAction();
if (!isShared(action) &&
(action == null || !action.startsWith("widget:"))) {
Intent intent = getIntent();
String action = intent.getAction();
boolean widget = (action != null && action.startsWith("widget:"));
String[] tos = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
boolean cloud = (tos != null && tos.length == 1 && BuildConfig.CLOUD_EMAIL.equals(tos[0]));
if (cloud) {
Intent setup = new Intent(this, ActivitySetup.class)
.setAction("misc")
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
.putExtra("tab", "backup");
startActivity(setup);
} else if (!isShared(action) && !widget) {
Intent parent = getParentActivityIntent();
if (parent != null)
if (shouldUpRecreateTask(parent))

View File

@ -576,12 +576,24 @@ public class CloudSync {
}
}
private static JSONObject _call(Context context, String user, String password, JSONObject jrequest)
throws GeneralSecurityException, JSONException, IOException, InvalidCipherTextException {
byte[] salt = MessageDigest.getInstance("SHA256").digest(user.getBytes());
private static byte[] getSalt(String user) throws NoSuchAlgorithmException {
return MessageDigest.getInstance("SHA256").digest(user.getBytes());
}
static String getCloudUser(String user) throws NoSuchAlgorithmException {
return getCloudUser(getSalt(user));
}
private static String getCloudUser(byte[] salt) throws NoSuchAlgorithmException {
byte[] huser = MessageDigest.getInstance("SHA256").digest(salt);
byte[] userid = Arrays.copyOfRange(huser, 0, 8);
String cloudUser = Base64.encodeToString(userid, Base64.NO_PADDING | Base64.NO_WRAP);
return Base64.encodeToString(userid, Base64.NO_PADDING | Base64.NO_WRAP);
}
private static JSONObject _call(Context context, String user, String password, JSONObject jrequest)
throws GeneralSecurityException, JSONException, IOException, InvalidCipherTextException {
byte[] salt = getSalt(user);
String cloudUser = getCloudUser(salt);
Pair<byte[], byte[]> key;
String lookup = Helper.hex(salt) + ":" + password;

View File

@ -128,6 +128,7 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
private Button btnLogout;
private CheckBox cbDelete;
private Group grpLogin;
private Group grpActivate;
private Group grpLogout;
private DateFormat DTF;
@ -171,6 +172,7 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
btnLogout = view.findViewById(R.id.btnLogout);
cbDelete = view.findViewById(R.id.cbDelete);
grpLogin = view.findViewById(R.id.grpLogin);
grpActivate = view.findViewById(R.id.grpActivate);
grpLogout = view.findViewById(R.id.grpLogout);
// Wire controls
@ -215,7 +217,18 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
btnActivate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO
try {
String user = prefs.getString("cloud_user", null);
Intent intent = new Intent(Intent.ACTION_SEND)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setType("text/plain")
.putExtra(Intent.EXTRA_EMAIL, new String[]{BuildConfig.CLOUD_EMAIL})
.putExtra(Intent.EXTRA_SUBJECT, CloudSync.getCloudUser(user))
.putExtra(Intent.EXTRA_TEXT, "Activate");
v.getContext().startActivity(intent);
} catch (Throwable ex) {
Log.e(ex);
}
}
});
@ -256,7 +269,6 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
!TextUtils.isEmpty(BuildConfig.CLOUD_URI)
? View.VISIBLE : View.GONE);
Helper.linkPro(tvCloudPro);
btnActivate.setVisibility(View.GONE);
cbSend.setChecked(prefs.getBoolean("cloud_send", true));
cbReceive.setChecked(prefs.getBoolean("cloud_receive", false));
@ -278,10 +290,14 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
if (key == null ||
"cloud_user".equals(key) ||
"cloud_password".equals(key) ||
"cloud_activated".equals(key) ||
"cloud_busy".equals(key) ||
"cloud_last_sync".equals(key)) {
String user = prefs.getString("cloud_user", null);
String password = prefs.getString("cloud_password", null);
boolean auth = !(TextUtils.isEmpty(user) || TextUtils.isEmpty(password));
boolean activated = prefs.getBoolean("cloud_activated", false);
boolean busy = prefs.getBoolean("cloud_busy", false);
long last_sync = prefs.getLong("cloud_last_sync", 0);
etUser.setText(user);
@ -291,6 +307,7 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
last_sync == 0 ? "-" : DTF.format(last_sync)));
cbDelete.setChecked(false);
grpLogin.setVisibility(auth ? View.GONE : View.VISIBLE);
grpActivate.setVisibility(auth && !activated && !busy ? View.VISIBLE : View.GONE);
grpLogout.setVisibility(auth ? View.VISIBLE : View.GONE);
}
}
@ -1522,15 +1539,19 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
}
private void cloud(Bundle args) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
new SimpleTask<Void>() {
@Override
protected void onPreExecute(Bundle args) {
Helper.setViewsEnabled(cardCloud, false);
prefs.edit().putBoolean("cloud_busy", true).apply();
}
@Override
protected void onPostExecute(Bundle args) {
Helper.setViewsEnabled(cardCloud, true);
prefs.edit().putBoolean("cloud_busy", false).apply();
WorkerSync.init(getContext());
}
@ -1566,7 +1587,8 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
@Override
protected void onExecuted(Bundle args, Void data) {
btnActivate.setVisibility(View.GONE);
prefs.edit().putBoolean("cloud_activated", true).apply();
view.post(new Runnable() {
@Override
public void run() {
@ -1577,8 +1599,9 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
@Override
protected void onException(Bundle args, Throwable ex) {
btnActivate.setVisibility(ex instanceof OperationCanceledException ? View.VISIBLE : View.GONE);
if (ex instanceof SecurityException) {
if (ex instanceof OperationCanceledException)
prefs.edit().putBoolean("cloud_activated", false).apply();
else 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))
@ -1587,7 +1610,7 @@ public class FragmentOptionsBackup extends FragmentBase implements SharedPrefere
if (!TextUtils.isEmpty(message))
builder.setMessage(message);
builder.show();
} else if (!(ex instanceof OperationCanceledException))
} else
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(FragmentOptionsBackup.this, args, "cloud");

View File

@ -324,11 +324,22 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnLogin" />
<TextView
android:id="@+id/tvLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="username"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvRegister" />
<Button
android:id="@+id/btnActivate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginTop="12dp"
android:backgroundTint="?attr/colorInfoBackground"
android:drawableEnd="@drawable/twotone_redeem_24"
android:drawablePadding="6dp"
@ -340,16 +351,17 @@
android:textStyle="bold"
app:drawableTint="?attr/colorInfoForeground"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvRegister" />
app:layout_constraintTop_toBottomOf="@id/tvLogin" />
<TextView
android:id="@+id/tvLogin"
android:layout_width="wrap_content"
android:id="@+id/tvActivateRemark"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="username"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textStyle="bold"
android:layout_marginTop="6dp"
android:text="@string/title_advanced_cloud_activate_remark"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="italic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnActivate" />
@ -363,7 +375,7 @@
android:textStyle="italic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvLogin" />
app:layout_constraintTop_toBottomOf="@id/tvActivateRemark" />
<CheckBox
android:id="@+id/cbSend"
@ -436,6 +448,13 @@
tvUser,etUser,tvPassword,tilPassword,tvPasswordRemark,
btnLogin,tvRegister" />
<androidx.constraintlayout.widget.Group
android:id="@+id/grpActivate"
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="
btnActivate,tvActivateRemark" />
<androidx.constraintlayout.widget.Group
android:id="@+id/grpLogout"
android:layout_width="0dp"

View File

@ -989,6 +989,10 @@
<string name="title_advanced_cloud_password_remark" translatable="false">You can change the password by wiping the data and logging in again</string>
<string name="title_advanced_cloud_invalid" translatable="false">Invalid username or password</string>
<string name="title_advanced_cloud_activate" translatable="false">Activate</string>
<string name="title_advanced_cloud_activate_remark" translatable="false">
Please use the same email address you used to activate the pro features.
The cloud account and the email address will not be linked.
</string>
<string name="title_advanced_cloud_account_remark" translatable="false">
Only enabled accounts and identities will be synchronized.
Folder properties will not be synchronized.