VancedMicroG/play-services-core/src/main/java/org/microg/gms/auth/AuthManager.java

246 lines
8.7 KiB
Java

/*
* Copyright (C) 2013-2017 microG Project Team
*
* 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 static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
import static org.microg.gms.auth.AuthPrefs.isTrustGooglePermitted;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;
import org.microg.gms.common.PackageUtils;
import org.microg.mgms.settings.SettingsContract;
import java.io.IOException;
public class AuthManager {
private static final String TAG = "GmsAuthManager";
public static final String PERMISSION_TREE_BASE = "com.mgoogle.android.googleapps.permission.GOOGLE_AUTH.";
public static final String PREF_AUTH_VISIBLE = SettingsContract.Auth.VISIBLE;
public static final int ONE_HOUR_IN_SECONDS = 60 * 60;
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;
private String accountType;
public AuthManager(Context context, String accountName, String packageName, String service) {
this.context = context;
this.accountName = accountName;
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";
}
this.packageName = packageName;
this.service = service;
}
public String getAccountType() {
if (accountType == null)
accountType = AuthConstants.DEFAULT_ACCOUNT_TYPE;
return accountType;
}
public AccountManager getAccountManager() {
if (accountManager == null)
accountManager = AccountManager.get(context);
return accountManager;
}
public Account getAccount() {
if (account == null)
account = new Account(accountName, getAccountType());
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");
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);
}
}
public boolean isPermitted() {
if (!service.startsWith("oauth")) {
if (context.getPackageManager().checkPermission(PERMISSION_TREE_BASE + service, packageName) == PackageManager.PERMISSION_GRANTED) {
return true;
}
}
String perm = getUserData(buildPermKey());
return "1".equals(perm);
}
public void setExpiry(long expiry) {
setUserData(buildExpireKey(), Long.toString(expiry));
}
public String getUserData(String key) {
return getAccountManager().getUserData(getAccount(), key);
}
public void setUserData(String key, String value) {
getAccountManager().setUserData(getAccount(), key, value);
}
public boolean accountExists() {
for (Account refAccount : getAccountManager().getAccountsByType(accountType)) {
if (refAccount.name.equalsIgnoreCase(accountName)) return true;
}
return false;
}
public String peekAuthToken() {
Log.d(TAG, "peekAuthToken: " + buildTokenKey());
return getAccountManager().peekAuthToken(getAccount(), buildTokenKey());
}
public String getAuthToken() {
if (service.startsWith("weblogin:")) return null;
if (getExpiry() < System.currentTimeMillis() / 1000L) {
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);
}
public void setAuthToken(String auth) {
setAuthToken(service, auth);
}
public void setAuthToken(String service, String auth) {
getAccountManager().setAuthToken(getAccount(), buildTokenKey(service), auth);
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);
}
}
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);
if (response.auth != null && (response.expiry != 0 || response.storeConsentRemotely)) {
setAuthToken(response.auth);
if (response.expiry > 0) {
setExpiry(response.expiry);
} else {
setExpiry(System.currentTimeMillis() / 1000 + ONE_HOUR_IN_SECONDS); // make valid for one hour by default
}
}
}
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 {
if (service.equals(AuthConstants.SCOPE_GET_ACCOUNT_ID)) {
AuthResponse response = new AuthResponse();
response.accountId = response.auth = getAccountManager().getUserData(getAccount(), "GoogleUserId");
return response;
}
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)
.source("android")
.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;
}
public String getService() {
return service;
}
}