2015-02-03 23:08:55 +01:00
|
|
|
/*
|
2017-06-13 00:30:41 +02:00
|
|
|
* Copyright (C) 2013-2017 microG Project Team
|
2015-02-03 23:08:55 +01:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package org.microg.gms.auth;
|
|
|
|
|
|
|
|
import android.accounts.Account;
|
|
|
|
import android.accounts.AccountManager;
|
|
|
|
import android.content.Context;
|
2015-02-10 03:33:30 +01:00
|
|
|
import android.content.pm.PackageManager;
|
2019-05-28 18:45:54 +02:00
|
|
|
import android.os.Build;
|
2015-02-03 23:08:55 +01:00
|
|
|
import android.util.Log;
|
|
|
|
|
2020-09-01 01:19:34 +02:00
|
|
|
import androidx.preference.PreferenceManager;
|
|
|
|
|
2015-03-06 20:08:47 +01:00
|
|
|
import org.microg.gms.common.PackageUtils;
|
2015-02-09 23:16:37 +01:00
|
|
|
|
2015-03-10 00:06:49 +01:00
|
|
|
import java.io.IOException;
|
|
|
|
|
|
|
|
import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
|
|
|
|
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
|
|
|
|
2015-02-03 23:08:55 +01:00
|
|
|
public class AuthManager {
|
|
|
|
|
|
|
|
private static final String TAG = "GmsAuthManager";
|
2020-07-16 04:41:09 +02:00
|
|
|
public static final String PERMISSION_TREE_BASE = "com.mgoogle.android.googleapps.permission.GOOGLE_AUTH.";
|
2015-04-03 23:54:41 +02:00
|
|
|
private static final String PREF_AUTH_TRUST_GOOGLE = "auth_manager_trust_google";
|
2019-05-28 18:45:54 +02:00
|
|
|
public static final String PREF_AUTH_VISIBLE = "auth_manager_visible";
|
2016-12-23 18:59:29 +01:00
|
|
|
public static final int ONE_HOUR_IN_SECONDS = 60 * 60;
|
2015-02-03 23:08:55 +01:00
|
|
|
|
2015-03-10 00:06:49 +01:00
|
|
|
private final Context context;
|
|
|
|
private final String accountName;
|
|
|
|
private final String packageName;
|
|
|
|
private final String service;
|
|
|
|
private AccountManager accountManager;
|
|
|
|
private Account account;
|
|
|
|
private String packageSignature;
|
2015-03-12 16:49:25 +01:00
|
|
|
private String accountType;
|
2015-03-10 00:06:49 +01:00
|
|
|
|
|
|
|
public AuthManager(Context context, String accountName, String packageName, String service) {
|
|
|
|
this.context = context;
|
|
|
|
this.accountName = accountName;
|
2020-07-16 02:24:57 +02:00
|
|
|
if (packageName.contains("youtube.music")) {
|
|
|
|
packageName = "com.google.android.apps.youtube.music";
|
|
|
|
} else if (packageName.contains("youtube.unplugged")) {
|
|
|
|
packageName = "com.google.android.apps.youtube.unplugged";
|
|
|
|
} else if (packageName.contains("youtube.tv")) {
|
|
|
|
packageName = "com.google.android.youtube.tv";
|
|
|
|
} else if (packageName.contains("youtube")) {
|
|
|
|
packageName = "com.google.android.youtube";
|
|
|
|
} else if (packageName.contains("apps.photos")) {
|
|
|
|
packageName = "com.google.android.apps.photos";
|
|
|
|
}
|
2015-03-10 00:06:49 +01:00
|
|
|
this.packageName = packageName;
|
|
|
|
this.service = service;
|
2015-02-03 23:08:55 +01:00
|
|
|
}
|
|
|
|
|
2015-03-12 16:49:25 +01:00
|
|
|
public String getAccountType() {
|
|
|
|
if (accountType == null)
|
2016-11-16 00:52:49 +01:00
|
|
|
accountType = AuthConstants.DEFAULT_ACCOUNT_TYPE;
|
2015-03-12 16:49:25 +01:00
|
|
|
return accountType;
|
|
|
|
}
|
|
|
|
|
2015-03-10 00:06:49 +01:00
|
|
|
public AccountManager getAccountManager() {
|
|
|
|
if (accountManager == null)
|
|
|
|
accountManager = AccountManager.get(context);
|
|
|
|
return accountManager;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Account getAccount() {
|
|
|
|
if (account == null)
|
2015-03-12 16:49:25 +01:00
|
|
|
account = new Account(accountName, getAccountType());
|
2015-03-10 00:06:49 +01:00
|
|
|
return account;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getPackageSignature() {
|
|
|
|
if (packageSignature == null)
|
|
|
|
packageSignature = PackageUtils.firstSignatureDigest(context, packageName);
|
|
|
|
return packageSignature;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String buildTokenKey(String service) {
|
|
|
|
return packageName + ":" + getPackageSignature() + ":" + service;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String buildTokenKey() {
|
|
|
|
return buildTokenKey(service);
|
|
|
|
}
|
|
|
|
|
|
|
|
public String buildPermKey() {
|
|
|
|
return "perm." + buildTokenKey();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setPermitted(boolean value) {
|
|
|
|
setUserData(buildPermKey(), value ? "1" : "0");
|
2019-05-28 18:45:54 +02:00
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && value && packageName != null) {
|
|
|
|
// Make account persistently visible as we already granted access
|
|
|
|
accountManager.setAccountVisibility(getAccount(), packageName, AccountManager.VISIBILITY_VISIBLE);
|
|
|
|
}
|
2015-03-10 00:06:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isPermitted() {
|
|
|
|
if (!service.startsWith("oauth")) {
|
2015-02-10 03:33:30 +01:00
|
|
|
if (context.getPackageManager().checkPermission(PERMISSION_TREE_BASE + service, packageName) == PackageManager.PERMISSION_GRANTED) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2015-03-10 00:06:49 +01:00
|
|
|
String perm = getUserData(buildPermKey());
|
2020-09-01 01:34:24 +02:00
|
|
|
return "1".equals(perm);
|
2015-02-03 23:08:55 +01:00
|
|
|
}
|
|
|
|
|
2015-03-10 00:06:49 +01:00
|
|
|
public void setExpiry(long expiry) {
|
|
|
|
setUserData(buildExpireKey(), Long.toString(expiry));
|
2015-02-09 23:16:37 +01:00
|
|
|
}
|
|
|
|
|
2015-03-10 00:06:49 +01:00
|
|
|
public String getUserData(String key) {
|
|
|
|
return getAccountManager().getUserData(getAccount(), key);
|
2015-02-07 20:56:49 +01:00
|
|
|
}
|
|
|
|
|
2015-03-10 00:06:49 +01:00
|
|
|
public void setUserData(String key, String value) {
|
|
|
|
getAccountManager().setUserData(getAccount(), key, value);
|
|
|
|
}
|
|
|
|
|
2020-12-09 14:36:34 +01:00
|
|
|
public boolean accountExists() {
|
|
|
|
for (Account refAccount : getAccountManager().getAccountsByType(accountType)) {
|
|
|
|
if (refAccount.name.equalsIgnoreCase(accountName)) return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-03-10 00:06:49 +01:00
|
|
|
public String peekAuthToken() {
|
2015-12-03 08:55:47 +01:00
|
|
|
Log.d(TAG, "peekAuthToken: " + buildTokenKey());
|
2015-03-10 00:06:49 +01:00
|
|
|
return getAccountManager().peekAuthToken(getAccount(), buildTokenKey());
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getAuthToken() {
|
2015-02-10 15:31:13 +01:00
|
|
|
if (service.startsWith("weblogin:")) return null;
|
2015-12-03 08:55:47 +01:00
|
|
|
if (getExpiry() < System.currentTimeMillis() / 1000L) {
|
2015-03-10 00:06:49 +01:00
|
|
|
Log.d(TAG, "token present, but expired");
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
return peekAuthToken();
|
|
|
|
}
|
|
|
|
|
|
|
|
public String buildExpireKey() {
|
|
|
|
return "EXP." + buildTokenKey();
|
|
|
|
}
|
|
|
|
|
|
|
|
public long getExpiry() {
|
|
|
|
String exp = getUserData(buildExpireKey());
|
|
|
|
if (exp == null) return -1;
|
|
|
|
return Long.parseLong(exp);
|
2015-02-03 23:08:55 +01:00
|
|
|
}
|
|
|
|
|
2015-03-10 00:06:49 +01:00
|
|
|
public void setAuthToken(String auth) {
|
|
|
|
setAuthToken(service, auth);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setAuthToken(String service, String auth) {
|
|
|
|
getAccountManager().setAuthToken(getAccount(), buildTokenKey(service), auth);
|
2019-05-28 18:45:54 +02:00
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && packageName != null && auth != null) {
|
|
|
|
// Make account persistently visible as we already granted access
|
|
|
|
accountManager.setAccountVisibility(getAccount(), packageName, AccountManager.VISIBILITY_VISIBLE);
|
|
|
|
}
|
2015-03-10 00:06:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public void storeResponse(AuthResponse response) {
|
|
|
|
if (service.startsWith("weblogin:")) return;
|
|
|
|
if (response.accountId != null)
|
|
|
|
setUserData("GoogleUserId", response.accountId);
|
|
|
|
if (response.Sid != null)
|
|
|
|
setAuthToken("SID", response.Sid);
|
|
|
|
if (response.LSid != null)
|
|
|
|
setAuthToken("LSID", response.LSid);
|
2016-12-23 18:59:29 +01:00
|
|
|
if (response.auth != null && (response.expiry != 0 || response.storeConsentRemotely)) {
|
2015-03-10 00:06:49 +01:00
|
|
|
setAuthToken(response.auth);
|
2016-12-23 18:59:29 +01:00
|
|
|
if (response.expiry > 0) {
|
|
|
|
setExpiry(response.expiry);
|
|
|
|
} else {
|
|
|
|
setExpiry(System.currentTimeMillis() / 1000 + ONE_HOUR_IN_SECONDS); // make valid for one hour by default
|
|
|
|
}
|
|
|
|
}
|
2015-03-10 00:06:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean isTrustGooglePermitted(Context context) {
|
2015-04-03 23:54:41 +02:00
|
|
|
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PREF_AUTH_TRUST_GOOGLE, true);
|
2015-03-10 00:06:49 +01:00
|
|
|
}
|
|
|
|
|
2019-05-28 18:45:54 +02:00
|
|
|
public static boolean isAuthVisible(Context context) {
|
|
|
|
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PREF_AUTH_VISIBLE, false);
|
|
|
|
}
|
|
|
|
|
2015-03-10 00:06:49 +01:00
|
|
|
private boolean isSystemApp() {
|
|
|
|
try {
|
|
|
|
int flags = context.getPackageManager().getApplicationInfo(packageName, 0).flags;
|
|
|
|
return (flags & FLAG_SYSTEM) > 0 || (flags & FLAG_UPDATED_SYSTEM_APP) > 0;
|
|
|
|
} catch (PackageManager.NameNotFoundException e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public AuthResponse requestAuth(boolean legacy) throws IOException {
|
2016-01-12 23:27:43 +01:00
|
|
|
if (service.equals(AuthConstants.SCOPE_GET_ACCOUNT_ID)) {
|
2015-12-03 08:55:47 +01:00
|
|
|
AuthResponse response = new AuthResponse();
|
|
|
|
response.accountId = response.auth = getAccountManager().getUserData(getAccount(), "GoogleUserId");
|
|
|
|
return response;
|
|
|
|
}
|
2015-03-10 00:06:49 +01:00
|
|
|
if (isPermitted() || isTrustGooglePermitted(context)) {
|
|
|
|
String token = getAuthToken();
|
|
|
|
if (token != null) {
|
|
|
|
AuthResponse response = new AuthResponse();
|
|
|
|
response.issueAdvice = "stored";
|
|
|
|
response.auth = token;
|
|
|
|
return response;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AuthRequest request = new AuthRequest().fromContext(context)
|
2019-05-25 15:52:26 +02:00
|
|
|
.source("android")
|
2015-03-10 00:06:49 +01:00
|
|
|
.app(packageName, getPackageSignature())
|
|
|
|
.email(accountName)
|
|
|
|
.token(getAccountManager().getPassword(account))
|
|
|
|
.service(service);
|
|
|
|
if (isSystemApp()) request.systemPartition();
|
|
|
|
if (isPermitted()) request.hasPermission();
|
|
|
|
if (legacy) {
|
|
|
|
request.callerIsGms().calledFromAccountManager();
|
|
|
|
} else {
|
|
|
|
request.callerIsApp();
|
|
|
|
}
|
|
|
|
AuthResponse response = request.getResponse();
|
|
|
|
if (!isPermitted() && !isTrustGooglePermitted(context)) {
|
|
|
|
response.auth = null;
|
|
|
|
} else {
|
|
|
|
storeResponse(response);
|
|
|
|
}
|
|
|
|
return response;
|
2015-02-03 23:08:55 +01:00
|
|
|
}
|
|
|
|
|
2015-03-10 00:06:49 +01:00
|
|
|
public String getService() {
|
|
|
|
return service;
|
2015-02-03 23:08:55 +01:00
|
|
|
}
|
|
|
|
}
|