Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stable-3.8] Remote wipe #4457

Merged
merged 1 commit into from
Sep 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -2268,15 +2268,15 @@ public List<OCFile> getVirtualFolderContent(VirtualFolderType type, boolean only
}

public void deleteAllFiles() {
String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "=?";
String[] whereArgs = new String[]{account.name};
String where = ProviderTableMeta.FILE_ACCOUNT_OWNER + "= ? AND " +
ProviderTableMeta.FILE_PATH + "= ?";
String[] whereArgs = new String[]{account.name, OCFile.ROOT_PATH};

if (getContentResolver() != null) {
getContentResolver().delete(ProviderTableMeta.CONTENT_URI_FILE, where, whereArgs);

getContentResolver().delete(ProviderTableMeta.CONTENT_URI_DIR, where, whereArgs);
} else {
try {
getContentProviderClient().delete(ProviderTableMeta.CONTENT_URI_FILE, where, whereArgs);
getContentProviderClient().delete(ProviderTableMeta.CONTENT_URI_DIR, where, whereArgs);
} catch (RemoteException e) {
Log_OC.e(TAG, "Exception in deleteAllFiles for account " + account.name + ": " + e.getMessage(), e);
}
Expand Down
81 changes: 72 additions & 9 deletions src/main/java/com/owncloud/android/jobs/AccountRemovalJob.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,26 +28,38 @@
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.content.ContentResolver;
import android.content.Context;
import android.text.TextUtils;

import com.evernote.android.job.Job;
import com.evernote.android.job.util.support.PersistableBundleCompat;
import com.google.gson.Gson;
import com.nextcloud.client.account.UserAccountManager;
import com.nextcloud.client.preferences.AppPreferencesImpl;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.datamodel.ArbitraryDataProvider;
import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.FilesystemDataProvider;
import com.owncloud.android.datamodel.PushConfigurationState;
import com.owncloud.android.datamodel.SyncedFolder;
import com.owncloud.android.datamodel.SyncedFolderProvider;
import com.owncloud.android.datamodel.UploadsStorageManager;
import com.owncloud.android.lib.common.OwnCloudAccount;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.OwnCloudClientManagerFactory;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.users.RemoteWipeSuccessRemoteOperation;
import com.owncloud.android.ui.activity.ContactsPreferenceActivity;
import com.owncloud.android.ui.events.AccountRemovedEvent;
import com.owncloud.android.utils.EncryptionUtils;
import com.owncloud.android.utils.FileStorageUtils;
import com.owncloud.android.utils.FilesSyncHelper;
import com.owncloud.android.utils.PushUtils;

import org.greenrobot.eventbus.EventBus;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.ArrayList;
Expand All @@ -65,28 +77,48 @@
public class AccountRemovalJob extends Job implements AccountManagerCallback<Boolean> {
public static final String TAG = "AccountRemovalJob";
public static final String ACCOUNT = "account";
public static final String REMOTE_WIPE = "remote_wipe";

private UploadsStorageManager uploadsStorageManager;
private UserAccountManager accountManager;
private UserAccountManager userAccountManager;

public AccountRemovalJob(UploadsStorageManager uploadStorageManager, UserAccountManager accountManager) {
this.uploadsStorageManager = uploadStorageManager;
this.accountManager = accountManager;
this.userAccountManager = accountManager;
}

@NonNull
@Override
protected Result onRunJob(Params params) {
protected Result onRunJob(@NotNull Params params) {
Context context = MainApp.getAppContext();
PersistableBundleCompat bundle = params.getExtras();
Account account = accountManager.getAccountByName(bundle.getString(ACCOUNT, ""));
AccountManager am = (AccountManager) context.getSystemService(ACCOUNT_SERVICE);
Account account = userAccountManager.getAccountByName(bundle.getString(ACCOUNT, ""));
AccountManager accountManager = (AccountManager) context.getSystemService(ACCOUNT_SERVICE);
boolean remoteWipe = bundle.getBoolean(REMOTE_WIPE, false);

if (account != null && am != null) {
if (account != null && accountManager != null) {
// disable contact backup job
ContactsPreferenceActivity.cancelContactBackupJobForAccount(context, account);

am.removeAccount(account, this, null);
OwnCloudClient client = null;
try {
OwnCloudAccount ocAccount = new OwnCloudAccount(account, MainApp.getAppContext());
client = OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor(ocAccount,
MainApp.getAppContext());
} catch (Exception e) {
Log_OC.e(this, "Could not create client", e);
}

try {
AccountManagerFuture<Boolean> accountRemoval = accountManager.removeAccount(account, this, null);
boolean removal = accountRemoval.getResult();

if (!removal) {
Log_OC.e(this, "Account removal of " + account.name + " failed!");
}
} catch (Exception e) {
Log_OC.e(this, "Account removal of " + account.name + " failed!", e);
}

FileDataStorageManager storageManager = new FileDataStorageManager(account, context.getContentResolver());

Expand All @@ -99,8 +131,34 @@ protected Result onRunJob(Params params) {
// delete all database entries
storageManager.deleteAllFiles();

// remove contact backup job
ContactsPreferenceActivity.cancelContactBackupJobForAccount(context, account);

ContentResolver contentResolver = context.getContentResolver();

// disable daily backup
ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(contentResolver);

arbitraryDataProvider.storeOrUpdateKeyValue(account.name,
ContactsPreferenceActivity.PREFERENCE_CONTACTS_AUTOMATIC_BACKUP,
"false");

String arbitraryDataPushString;

if (!TextUtils.isEmpty(arbitraryDataPushString = arbitraryDataProvider.getValue(
account, PushUtils.KEY_PUSH)) &&
!TextUtils.isEmpty(context.getResources().getString(R.string.push_server_url))) {
Gson gson = new Gson();
PushConfigurationState pushArbitraryData = gson.fromJson(arbitraryDataPushString,
PushConfigurationState.class);
pushArbitraryData.setShouldBeDeleted(true);
arbitraryDataProvider.storeOrUpdateKeyValue(account.name, PushUtils.KEY_PUSH,
gson.toJson(pushArbitraryData));

PushUtils.pushRegistrationToServer(userAccountManager, pushArbitraryData.getPushToken());
}

// remove pending account removal
ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(context.getContentResolver());
arbitraryDataProvider.deleteKeyForAccount(account.name, PENDING_FOR_REMOVAL);

// remove synced folders set for account
Expand All @@ -113,7 +171,7 @@ protected Result onRunJob(Params params) {
for (SyncedFolder syncedFolder : syncedFolders) {
if (syncedFolder.getAccount().equals(account.name)) {
arbitraryDataProvider.deleteKeyForAccount(FilesSyncHelper.GLOBAL,
FilesSyncHelper.SYNCEDFOLDERINITIATED + syncedFolder.getId());
FilesSyncHelper.SYNCEDFOLDERINITIATED + syncedFolder.getId());
syncedFolderIds.add(syncedFolder.getId());
}
}
Expand All @@ -132,6 +190,11 @@ protected Result onRunJob(Params params) {
arbitraryDataProvider.deleteKeyForAccount(account.name, EncryptionUtils.PRIVATE_KEY);
arbitraryDataProvider.deleteKeyForAccount(account.name, EncryptionUtils.PUBLIC_KEY);

if (remoteWipe && client != null) {
String authToken = client.getCredentials().getAuthToken();
new RemoteWipeSuccessRemoteOperation(authToken).execute(client);
}

return Result.SUCCESS;
} else {
return Result.FAILURE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,11 @@ private int deleteDirectory(SQLiteDatabase db, Uri uri, String where, String...
children.close();
}

count += db.delete(ProviderTableMeta.FILE_TABLE_NAME,
ProviderTableMeta._ID + "=" + uri.getPathSegments().get(1)
+ (!TextUtils.isEmpty(where) ? " AND (" + where + ")" : ""), whereArgs);
if (uri.getPathSegments().size() > 1) {
count += db.delete(ProviderTableMeta.FILE_TABLE_NAME,
ProviderTableMeta._ID + "=" + uri.getPathSegments().get(1)
+ (!TextUtils.isEmpty(where) ? " AND (" + where + ")" : ""), whereArgs);
}

return count;
}
Expand All @@ -203,9 +205,13 @@ private int deleteSingleFile(SQLiteDatabase db, Uri uri, String where, String...
}
Log_OC.d(TAG, "Removing FILE " + remoteId);

count = db.delete(ProviderTableMeta.FILE_TABLE_NAME,
ProviderTableMeta._ID + "=" + uri.getPathSegments().get(1)
+ (!TextUtils.isEmpty(where) ? " AND (" + where + ")" : ""), whereArgs);
if (remoteId == null) {
return 0;
} else {
count = db.delete(ProviderTableMeta.FILE_TABLE_NAME,
ProviderTableMeta._ID + "=" + uri.getPathSegments().get(1)
+ (!TextUtils.isEmpty(where) ? " AND (" + where + ")" : ""), whereArgs);
}
} catch (Exception e) {
Log_OC.d(TAG, "DB-Error removing file!", e);
} finally {
Expand Down Expand Up @@ -476,7 +482,9 @@ private Cursor query(SQLiteDatabase db, Uri uri, String[] projectionArray, Strin
case ROOT_DIRECTORY:
break;
case DIRECTORY:
sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "=" + uri.getPathSegments().get(1));
if (uri.getPathSegments().size() > SINGLE_PATH_SEGMENT) {
sqlQuery.appendWhere(ProviderTableMeta.FILE_PARENT + "=" + uri.getPathSegments().get(1));
}
break;
case SINGLE_FILE:
if (uri.getPathSegments().size() > SINGLE_PATH_SEGMENT) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ private void selectNavigationItem(final MenuItem menuItem) {
case R.id.nav_logout:
mCheckedMenuItem = -1;
menuItem.setChecked(false);
UserInfoActivity.openAccountRemovalConfirmationDialog(getAccount(), getSupportFragmentManager(), true);
UserInfoActivity.openAccountRemovalConfirmationDialog(getAccount(), getSupportFragmentManager());
break;
case R.id.nav_shared:
handleSearchEvents(new SearchEvent("",
Expand Down Expand Up @@ -1427,6 +1427,8 @@ protected void onStop() {
@Subscribe(threadMode = ThreadMode.MAIN)
public void onAccountRemovedEvent(AccountRemovedEvent event) {
updateAccountList();

restart();
}

/**
Expand Down
46 changes: 27 additions & 19 deletions src/main/java/com/owncloud/android/ui/activity/FileActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import com.owncloud.android.operations.UpdateShareViaLinkOperation;
import com.owncloud.android.services.OperationsService;
import com.owncloud.android.services.OperationsService.OperationsServiceBinder;
import com.owncloud.android.ui.asynctasks.CheckRemoteWipeTask;
import com.owncloud.android.ui.asynctasks.LoadingVersionNumberTask;
import com.owncloud.android.ui.dialog.ConfirmationDialogFragment;
import com.owncloud.android.ui.dialog.LoadingDialog;
Expand All @@ -81,6 +82,8 @@
import com.owncloud.android.utils.FilesSyncHelper;
import com.owncloud.android.utils.ThemeUtils;

import java.lang.ref.WeakReference;

import javax.inject.Inject;

import androidx.fragment.app.DialogFragment;
Expand Down Expand Up @@ -394,43 +397,48 @@ protected void requestCredentialsUpdate(Context context) {
* be used.
*/
protected void requestCredentialsUpdate(Context context, Account account) {
if (account == null) {
account = getAccount();
}

boolean remoteWipeSupported = accountManager.getServerVersion(account).isRemoteWipeSupported();

if (remoteWipeSupported) {
new CheckRemoteWipeTask(account, new WeakReference<>(this)).execute();
} else {
performCredentialsUpdate(account, context);
}
}

public void performCredentialsUpdate(Account account, Context context) {
try {
/// step 1 - invalidate credentials of current account
if (account == null) {
account = getAccount();
}
OwnCloudClient client;
OwnCloudAccount ocAccount = new OwnCloudAccount(account, context);
client = OwnCloudClientManagerFactory.getDefaultSingleton().removeClientFor(ocAccount);
OwnCloudClient client = OwnCloudClientManagerFactory.getDefaultSingleton().removeClientFor(ocAccount);

if (client != null) {
OwnCloudCredentials cred = client.getCredentials();
if (cred != null) {
AccountManager am = AccountManager.get(context);
if (cred.authTokenExpires()) {
am.invalidateAuthToken(
account.type,
cred.getAuthToken()
);
OwnCloudCredentials credentials = client.getCredentials();
if (credentials != null) {
AccountManager accountManager = AccountManager.get(context);
if (credentials.authTokenExpires()) {
accountManager.invalidateAuthToken(account.type, credentials.getAuthToken());
} else {
am.clearPassword(account);
accountManager.clearPassword(account);
}
}
}

/// step 2 - request credentials to user
Intent updateAccountCredentials = new Intent(this, AuthenticatorActivity.class);
Intent updateAccountCredentials = new Intent(context, AuthenticatorActivity.class);
updateAccountCredentials.putExtra(AuthenticatorActivity.EXTRA_ACCOUNT, account);
updateAccountCredentials.putExtra(
AuthenticatorActivity.EXTRA_ACTION,
AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN);
AuthenticatorActivity.EXTRA_ACTION,
AuthenticatorActivity.ACTION_UPDATE_EXPIRED_TOKEN);
updateAccountCredentials.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivityForResult(updateAccountCredentials, REQUEST_CODE__UPDATE_CREDENTIALS);

} catch (com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException e) {
DisplayUtils.showSnackMessage(this, R.string.auth_account_does_not_exist);
}

}

/**
Expand Down
Loading