nextcloud-android/src/main/java/com/nextcloud/client/account/UserAccountManagerImpl.java

206 lines
8.5 KiB
Java

/*
* Nextcloud Android client application
*
* @author Chris Narkiewicz
* Copyright (C) 2019 Chris Narkiewicz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.client.account;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.net.Uri;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.authentication.AccountUtils;
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.UserInfo;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.users.GetRemoteUserInfoOperation;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class UserAccountManagerImpl implements UserAccountManager {
private static final String TAG = AccountUtils.class.getSimpleName();
private static final String PREF_SELECT_OC_ACCOUNT = "select_oc_account";
private Context context;
private AccountManager accountManager;
@Inject
public UserAccountManagerImpl(
Context context,
AccountManager accountManager
) {
this.context = context;
this.accountManager = accountManager;
}
@Override
@NonNull
public Account[] getAccounts() {
return accountManager.getAccountsByType(getAccountType());
}
@Nullable
public Account getCurrentAccount() {
return AccountUtils.getCurrentOwnCloudAccount(context);
}
public void updateAccountVersion() {
Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(context);
if (currentAccount == null) {
return;
}
final String currentAccountVersion = accountManager.getUserData(currentAccount, com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_OC_ACCOUNT_VERSION);
final boolean needsUpdate = !String.valueOf(ACCOUNT_VERSION_WITH_PROPER_ID).equalsIgnoreCase(currentAccountVersion);
if (!needsUpdate) {
return;
}
Log_OC.i(TAG, "Upgrading accounts to account version #" + ACCOUNT_VERSION_WITH_PROPER_ID);
Account[] ocAccounts = accountManager.getAccountsByType(MainApp.getAccountType(context));
String serverUrl;
String username;
String displayName;
String newAccountName;
Account newAccount;
GetRemoteUserInfoOperation remoteUserNameOperation = new GetRemoteUserInfoOperation();
for (Account account : ocAccounts) {
// build new account name
serverUrl = accountManager.getUserData(account, com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_OC_BASE_URL);
// update user name
try {
OwnCloudAccount ocAccount = new OwnCloudAccount(account, context);
OwnCloudClient client = OwnCloudClientManagerFactory.getDefaultSingleton()
.getClientFor(ocAccount, context);
RemoteOperationResult result = remoteUserNameOperation.execute(client);
if (result.isSuccess()) {
UserInfo userInfo = (UserInfo) result.getData().get(0);
username = userInfo.id;
displayName = userInfo.displayName;
} else {
// skip account, try it next time
Log_OC.e(TAG, "Error while getting username for account: " + account.name);
continue;
}
} catch (Exception e) {
Log_OC.e(TAG, "Error while getting username: " + e.getMessage());
continue;
}
newAccountName = com.owncloud.android.lib.common.accounts.AccountUtils.
buildAccountName(Uri.parse(serverUrl), username);
// migrate to a new account, if needed
if (!newAccountName.equals(account.name)) {
newAccount = migrateAccount(context, currentAccount, accountManager, serverUrl, newAccountName,
account);
} else {
// servers which base URL is in the root of their domain need no change
Log_OC.d(TAG, account.name + " needs no upgrade ");
newAccount = account;
}
accountManager.setUserData(newAccount, com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_DISPLAY_NAME, displayName);
accountManager.setUserData(newAccount, com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_USER_ID, username);
// at least, upgrade account version
Log_OC.d(TAG, "Setting version " + ACCOUNT_VERSION_WITH_PROPER_ID + " to " + newAccountName);
accountManager.setUserData(newAccount, com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_OC_ACCOUNT_VERSION,
Integer.toString(ACCOUNT_VERSION_WITH_PROPER_ID));
}
}
@NonNull
private Account migrateAccount(Context context, Account currentAccount, AccountManager accountMgr,
String serverUrl, String newAccountName, Account account) {
Log_OC.d(TAG, "Upgrading " + account.name + " to " + newAccountName);
// create the new account
Account newAccount = new Account(newAccountName, MainApp.getAccountType(context));
String password = accountMgr.getPassword(account);
accountMgr.addAccountExplicitly(newAccount, (password != null) ? password : "", null);
// copy base URL
accountMgr.setUserData(newAccount, com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_OC_BASE_URL, serverUrl);
// copy server version
accountMgr.setUserData(
newAccount,
com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_OC_VERSION,
accountMgr.getUserData(account, com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_OC_VERSION)
);
// copy cookies
accountMgr.setUserData(
newAccount,
com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_COOKIES,
accountMgr.getUserData(account, com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_COOKIES)
);
// copy type of authentication
final String isSamlStr = accountMgr.getUserData(account, com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO);
if (Boolean.parseBoolean(isSamlStr)) {
accountMgr.setUserData(newAccount, com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_SUPPORTS_SAML_WEB_SSO, "TRUE");
}
final String isOauthStr = accountMgr.getUserData(account, com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_SUPPORTS_OAUTH2);
if (Boolean.parseBoolean(isOauthStr)) {
accountMgr.setUserData(newAccount, com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_SUPPORTS_OAUTH2, "TRUE");
}
/* TODO - study if it's possible to run this method in a background thread to copy the authToken
if (isOAuth || isSaml) {
accountMgr.setAuthToken(newAccount, mAuthTokenType, mAuthToken);
}
*/
// don't forget the account saved in preferences as the current one
if (currentAccount.name.equals(account.name)) {
AccountUtils.setCurrentOwnCloudAccount(context, newAccountName);
}
// remove the old account
accountMgr.removeAccount(account, null, null);
// will assume it succeeds, not a big deal otherwise
return newAccount;
}
private String getAccountType() {
return context.getString(R.string.account_type);
}
}