mirror of
https://github.com/TeamVanced/VancedMicroG
synced 2024-12-22 18:47:46 +01:00
Update auth
This commit is contained in:
parent
14379f607e
commit
8a964300d1
@ -113,6 +113,14 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="org.microg.gms.feeds.SubscribedFeedsProvider"
|
||||
android:authorities="subscribedfeeds"
|
||||
android:exported="true"
|
||||
android:multiprocess="false"
|
||||
android:readPermission="android.permission.SUBSCRIBED_FEEDS_READ"
|
||||
android:writePermission="android.permission.SUBSCRIBED_FEEDS_WRITE" />
|
||||
|
||||
<service
|
||||
android:name=".auth.GetToken"
|
||||
android:exported="true" />
|
||||
|
@ -16,9 +16,13 @@
|
||||
|
||||
package org.microg.gms.auth;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import org.microg.gms.auth.loginservice.GoogleLoginService;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -49,6 +53,7 @@ public class AuthClient {
|
||||
content.append("&");
|
||||
content.append(Uri.encode(key)).append("=").append(Uri.encode(formContent.get(key)));
|
||||
}
|
||||
Log.d(TAG, "-- Request --\n" + content);
|
||||
OutputStream os = connection.getOutputStream();
|
||||
os.write(content.toString().getBytes());
|
||||
os.close();
|
||||
@ -56,6 +61,7 @@ public class AuthClient {
|
||||
throw new IOException(connection.getResponseMessage());
|
||||
}
|
||||
String result = new String(readStreamToEnd(connection.getInputStream()));
|
||||
Log.d(TAG, "-- Response --\n" + result);
|
||||
return AuthResponse.parse(result);
|
||||
}
|
||||
|
||||
|
74
src/org/microg/gms/auth/AuthManager.java
Normal file
74
src/org/microg/gms/auth/AuthManager.java
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2013-2015 µg 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 android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
public class AuthManager {
|
||||
|
||||
private static final String TAG = "GmsAuthManager";
|
||||
|
||||
public static void storeResponse(Context context, Account account, String packageName,
|
||||
String sig, String service, AuthResponse response) {
|
||||
AccountManager accountManager = AccountManager.get(context);
|
||||
if (response.accountId != null)
|
||||
accountManager.setUserData(account, "GoogleUserId", response.accountId);
|
||||
if (response.Sid != null)
|
||||
accountManager.setAuthToken(account, buildTokenKey(packageName, sig, "SID"), response.Sid);
|
||||
if (response.LSid != null)
|
||||
accountManager.setAuthToken(account, buildTokenKey(packageName, sig, "LSID"), response.LSid);
|
||||
if (response.expiry > 0)
|
||||
accountManager.setUserData(account, buildExpireKey(packageName, sig, service), Long.toString(response.expiry));
|
||||
if (response.auth != null && response.expiry != 0) {
|
||||
accountManager.setAuthToken(account, buildTokenKey(packageName, sig, service), response.auth);
|
||||
accountManager.setUserData(account, buildPermKey(packageName, sig, service), "1");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static boolean isPermitted(Context context, Account account, String packageName,
|
||||
String sig, String service) {
|
||||
AccountManager accountManager = AccountManager.get(context);
|
||||
String perm = accountManager.getUserData(account, buildPermKey(packageName, sig, service));
|
||||
if (!"1".equals(perm))
|
||||
return false;
|
||||
String exp = accountManager.getUserData(account, buildExpireKey(packageName, sig, service));
|
||||
if (exp != null) {
|
||||
long expLong = Long.parseLong(exp);
|
||||
if (expLong < System.currentTimeMillis() / 1000L) {
|
||||
Log.d(TAG, "Permission for " + packageName + " / " + service + " present, but expired");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String buildTokenKey(String packageName, String sig, String service) {
|
||||
return packageName + ":" + sig + ":" + service;
|
||||
}
|
||||
|
||||
private static String buildPermKey(String packageName, String sig, String service) {
|
||||
return "perm." + packageName + ":" + sig + ":" + service;
|
||||
}
|
||||
|
||||
private static String buildExpireKey(String packageName, String sig, String service) {
|
||||
return "EXP." + packageName + ":" + sig + ":" + service;
|
||||
}
|
||||
}
|
@ -26,9 +26,10 @@ import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.auth.IAuthManagerService;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.microg.gms.common.Utils;
|
||||
|
||||
public class AuthManagerServiceImpl extends IAuthManagerService.Stub {
|
||||
public static final String GOOGLE_ACCOUNT_TYPE = "com.google";
|
||||
@ -62,23 +63,34 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub {
|
||||
public Bundle getToken(String accountName, String scope, Bundle extras) throws RemoteException {
|
||||
String packageName = extras.getString(KEY_ANDROID_PACKAGE_NAME, extras.getString(KEY_CLIENT_PACKAGE_NAME, null));
|
||||
int callerUid = extras.getInt(KEY_CALLER_UID, 0);
|
||||
checkPackage(packageName, callerUid, getCallingUid());
|
||||
Utils.checkPackage(context, packageName, callerUid, getCallingUid());
|
||||
boolean notify = extras.getBoolean(KEY_HANDLE_NOTIFICATION, false);
|
||||
|
||||
Log.d("AuthManagerService", "getToken: account:" + accountName + " scope:" + scope + " extras:" + extras);
|
||||
AccountManagerFuture<Bundle> authToken = AccountManager.get(context).getAuthToken(new Account(accountName, GOOGLE_ACCOUNT_TYPE), scope, extras, notify, null, new Handler(Looper.getMainLooper()));
|
||||
|
||||
//AccountManagerFuture<Bundle> authToken = AccountManager.get(context).getAuthToken(new Account(accountName, GOOGLE_ACCOUNT_TYPE), scope, extras, notify, null, new Handler(Looper.getMainLooper()));
|
||||
try {
|
||||
Bundle requestResult = authToken.getResult();
|
||||
if (!requestResult.containsKey(AccountManager.KEY_AUTHTOKEN) && requestResult.containsKey(AccountManager.KEY_INTENT)) {
|
||||
Account account = new Account(accountName, GOOGLE_ACCOUNT_TYPE);
|
||||
String sig = Utils.getFirstPackageSignatureDigest(context, packageName);
|
||||
AuthResponse response = new AuthRequest().fromContext(context)
|
||||
.app(packageName, sig)
|
||||
.callerIsApp()
|
||||
.email(accountName)
|
||||
.token(AccountManager.get(context).getPassword(account))
|
||||
.service(scope)
|
||||
.getResponse();
|
||||
AuthManager.storeResponse(context, account, packageName, sig, scope, response);
|
||||
//Bundle requestResult = authToken.getResult();
|
||||
/*if (!requestResult.containsKey(AccountManager.KEY_AUTHTOKEN) && requestResult.containsKey(AccountManager.KEY_INTENT)) {
|
||||
Intent intent = requestResult.getParcelable(AccountManager.KEY_INTENT);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
Log.d("getToken", requestResult.toString());
|
||||
}*/
|
||||
Log.d("getToken", response.auth);
|
||||
Bundle result = new Bundle();
|
||||
result.putString(KEY_AUTH_TOKEN, requestResult.getString(AccountManager.KEY_AUTHTOKEN));
|
||||
result.putString(KEY_AUTH_TOKEN, response.auth);
|
||||
result.putString(KEY_ERROR, "Unknown");
|
||||
result.putParcelable(KEY_USER_RECOVERY_INTENT, requestResult.getParcelable(AccountManager.KEY_INTENT));
|
||||
//result.putParcelable(KEY_USER_RECOVERY_INTENT, requestResult.getParcelable(AccountManager.KEY_INTENT));
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
Log.w("AuthManagerService", e);
|
||||
@ -86,16 +98,6 @@ public class AuthManagerServiceImpl extends IAuthManagerService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPackage(String packageName, int callerUid, int callingUid) {
|
||||
if (callerUid != 0 && callerUid != callingUid) {
|
||||
throw new SecurityException("callerUid [" + callerUid + "] and real calling uid [" + callingUid + "] mismatch!");
|
||||
}
|
||||
String[] packagesForUid = context.getPackageManager().getPackagesForUid(callingUid);
|
||||
if (packagesForUid != null && !Arrays.asList(packagesForUid).contains(packageName)) {
|
||||
throw new SecurityException("callingUid [" + callingUid + "] is not related to packageName [" + packageName + "]");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle clearToken(String token, Bundle extras) throws RemoteException {
|
||||
return null;
|
||||
|
@ -16,7 +16,15 @@
|
||||
|
||||
package org.microg.gms.auth;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.microg.gms.common.Build;
|
||||
import org.microg.gms.common.Constants;
|
||||
import org.microg.gms.common.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class AuthRequest {
|
||||
@ -33,20 +41,49 @@ public class AuthRequest {
|
||||
public String countryCode;
|
||||
public String operatorCountryCode;
|
||||
public String locale;
|
||||
public int gmsVersion;
|
||||
public int gmsVersion = Constants.MAX_REFERENCE_VERSION;
|
||||
public String accountType = "HOSTED_OR_GOOGLE";
|
||||
public String email;
|
||||
public String service;
|
||||
public String source = "android";
|
||||
public boolean isCalledFromAccountManager;
|
||||
public String token;
|
||||
public boolean isSystemPartition;
|
||||
public boolean systemPartition;
|
||||
public boolean getAccountId;
|
||||
public boolean isAccessToken;
|
||||
public String droidguardResults;
|
||||
public boolean hasPermission;
|
||||
public boolean addAccount;
|
||||
|
||||
public AuthRequest() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
public AuthRequest(Context context, String token) {
|
||||
this(Utils.getLocale(context), Utils.getBuild(context), Utils.getAndroidIdHex(context), token);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public AuthRequest(Locale locale, Build build, String androidIdHex, String token) {
|
||||
this(locale, build.sdk, Constants.MAX_REFERENCE_VERSION, build.device, build.id, androidIdHex, token);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public AuthRequest(Locale locale, int sdkVersion, int gmsVersion, String deviceName,
|
||||
String buildVersion, String androidIdHex, String token) {
|
||||
this.androidIdHex = androidIdHex;
|
||||
this.deviceName = deviceName;
|
||||
this.buildVersion = buildVersion;
|
||||
this.countryCode = locale.getCountry();
|
||||
this.gmsVersion = gmsVersion;
|
||||
this.operatorCountryCode = locale.getCountry();
|
||||
this.locale = locale.toString();
|
||||
this.sdkVersion = sdkVersion;
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
|
||||
public Map<String, String> getHttpHeaders() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
@ -65,7 +102,7 @@ public class AuthRequest {
|
||||
map.put("sdk_version", Integer.toString(sdkVersion));
|
||||
map.put("google_play_services_version", Integer.toString(gmsVersion));
|
||||
map.put("accountType", accountType);
|
||||
if (isSystemPartition) map.put("system_partition", "1");
|
||||
if (systemPartition) map.put("system_partition", "1");
|
||||
if (hasPermission) map.put("has_permission", "1");
|
||||
if (addAccount) map.put("add_account", "1");
|
||||
if (email != null) map.put("Email", email);
|
||||
@ -88,4 +125,107 @@ public class AuthRequest {
|
||||
if (droidguardResults != null) map.put("droidguard_results", droidguardResults);
|
||||
return map;
|
||||
}
|
||||
|
||||
public AuthRequest build(Build build) {
|
||||
sdkVersion = build.sdk;
|
||||
deviceName = build.device;
|
||||
buildVersion = build.id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest locale(Locale locale) {
|
||||
this.locale = locale.toString();
|
||||
this.countryCode = locale.getCountry();
|
||||
this.operatorCountryCode = locale.getCountry();
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest fromContext(Context context) {
|
||||
build(Utils.getBuild(context));
|
||||
locale(Utils.getLocale(context));
|
||||
androidIdHex = Utils.getAndroidIdHex(context);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest email(String email) {
|
||||
this.email = email;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest token(String token) {
|
||||
this.token = token;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest service(String service) {
|
||||
this.service = service;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest app(String app, String appSignature) {
|
||||
this.app = app;
|
||||
this.appSignature = appSignature;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest appIsGms() {
|
||||
return app(Constants.GMS_PACKAGE_NAME, Constants.GMS_PACKAGE_SIGNATURE_SHA1);
|
||||
}
|
||||
|
||||
public AuthRequest callerIsGms() {
|
||||
return caller(Constants.GMS_PACKAGE_NAME, Constants.GMS_PACKAGE_SIGNATURE_SHA1);
|
||||
}
|
||||
|
||||
public AuthRequest callerIsApp() {
|
||||
return caller(app, appSignature);
|
||||
}
|
||||
|
||||
public AuthRequest caller(String caller, String callerSignature) {
|
||||
this.caller = caller;
|
||||
this.callerSignature = callerSignature;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest calledFromAccountManager() {
|
||||
isCalledFromAccountManager = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest addAccount() {
|
||||
addAccount = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest systemPartition() {
|
||||
systemPartition = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest hasPermission() {
|
||||
hasPermission = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest getAccountId() {
|
||||
getAccountId = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest isAccessToken() {
|
||||
isAccessToken = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthRequest droidguardResults(String droidguardResults) {
|
||||
this.droidguardResults = droidguardResults;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AuthResponse getResponse() throws IOException {
|
||||
return AuthClient.request(this);
|
||||
}
|
||||
|
||||
public void getResponseAsync(AuthClient.GmsAuthCallback callback) {
|
||||
AuthClient.request(this, callback);
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ public class AuthResponse {
|
||||
@ResponseField("Email")
|
||||
public String email;
|
||||
@ResponseField("services")
|
||||
public Set<String> services = new HashSet<>();
|
||||
public String services;
|
||||
@ResponseField("GooglePlusUpgrade")
|
||||
public boolean isGooglePlusUpgrade;
|
||||
@ResponseField("PicasaUser")
|
||||
@ -56,12 +56,18 @@ public class AuthResponse {
|
||||
public String lastName;
|
||||
@ResponseField("issueAdvice")
|
||||
public String issueAdvice;
|
||||
@ResponseField("accountId")
|
||||
public String accountId;
|
||||
@ResponseField("Expiry")
|
||||
public long expiry = -1;
|
||||
@ResponseField("storeConsentRemotely")
|
||||
public boolean storeConsentRemotely;
|
||||
|
||||
public static AuthResponse parse(String result) {
|
||||
AuthResponse response = new AuthResponse();
|
||||
String[] entries = result.split("\n");
|
||||
for (String s : entries) {
|
||||
String[] keyValuePair = s.split("=");
|
||||
String[] keyValuePair = s.split("=", 2);
|
||||
String key = keyValuePair[0].trim();
|
||||
String value = keyValuePair[1].trim();
|
||||
try {
|
||||
@ -72,11 +78,10 @@ public class AuthResponse {
|
||||
field.set(response, value);
|
||||
} else if (field.getType().equals(boolean.class)) {
|
||||
field.setBoolean(response, value.equals("1"));
|
||||
} else if (field.getType().equals(long.class)) {
|
||||
field.setLong(response, Long.parseLong(value));
|
||||
} else if (field.getType().equals(int.class)) {
|
||||
field.setInt(response, Integer.parseInt(value));
|
||||
} else if (field.getType().isAssignableFrom(Set.class)) {
|
||||
//noinspection unchecked
|
||||
((Set)field.get(response)).addAll(Arrays.asList(value.split(",")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2015 µg 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 android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
import org.microg.gms.common.Constants;
|
||||
import org.microg.gms.common.Utils;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class GmsAddAccountRequest extends AuthRequest {
|
||||
|
||||
public GmsAddAccountRequest(Context context, String token) {
|
||||
this(Locale.getDefault(), Build.VERSION.SDK_INT, Constants.MAX_REFERENCE_VERSION,
|
||||
Build.DEVICE, Build.ID, Utils.getAndroidIdHex(context), token);
|
||||
}
|
||||
|
||||
public GmsAddAccountRequest(Locale locale, int sdkVersion, int gmsVersion, String deviceName,
|
||||
String buildVersion, String androidIdHex, String token) {
|
||||
this.service = "ac2dm";
|
||||
this.addAccount = true;
|
||||
this.isSystemPartition = true;
|
||||
this.hasPermission = true;
|
||||
this.getAccountId = true;
|
||||
this.app = "com.google.android.gms";
|
||||
this.appSignature = "38918a453d07199354f8b19af05ec6562ced5788";
|
||||
|
||||
this.androidIdHex = androidIdHex;
|
||||
this.deviceName = deviceName;
|
||||
this.buildVersion = buildVersion;
|
||||
this.countryCode = locale.getCountry();
|
||||
this.gmsVersion = gmsVersion;
|
||||
this.operatorCountryCode = locale.getCountry();
|
||||
this.locale = locale.toString();
|
||||
this.sdkVersion = sdkVersion;
|
||||
this.token = token;
|
||||
}
|
||||
}
|
57
src/org/microg/gms/auth/login/BaseActivity.java
Normal file
57
src/org/microg/gms/auth/login/BaseActivity.java
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2013-2015 µg 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.login;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
import com.google.android.gms.R;
|
||||
|
||||
public abstract class BaseActivity extends Activity {
|
||||
private static final int TITLE_MIN_HEIGHT = 64;
|
||||
private static final double TITLE_WIDTH_FACTOR = (8.0 / 18.0);
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.login_base);
|
||||
formatTitle();
|
||||
}
|
||||
|
||||
private void formatTitle() {
|
||||
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
double widthPixels = (double) (getResources().getDisplayMetrics().widthPixels);
|
||||
findViewById(R.id.title_container).getLayoutParams().height =
|
||||
(int) (dpToPx(TITLE_MIN_HEIGHT) + (TITLE_WIDTH_FACTOR * widthPixels));
|
||||
} else {
|
||||
findViewById(R.id.title_container).getLayoutParams().height = dpToPx(TITLE_MIN_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
formatTitle();
|
||||
}
|
||||
|
||||
public int dpToPx(int dp) {
|
||||
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
|
||||
return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
|
||||
}
|
||||
}
|
@ -18,14 +18,11 @@ package org.microg.gms.auth.login;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
@ -41,30 +38,30 @@ import android.widget.RelativeLayout;
|
||||
import com.google.android.gms.R;
|
||||
|
||||
import org.microg.gms.auth.AuthClient;
|
||||
import org.microg.gms.auth.AuthManager;
|
||||
import org.microg.gms.auth.AuthRequest;
|
||||
import org.microg.gms.auth.AuthResponse;
|
||||
import org.microg.gms.auth.GmsAddAccountRequest;
|
||||
import org.microg.gms.auth.RetrieveRtTokenRequest;
|
||||
import org.microg.gms.common.Constants;
|
||||
import org.microg.gms.common.Utils;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class LoginActivity extends Activity {
|
||||
public class LoginActivity extends BaseActivity {
|
||||
public static final String TMPL_NEW_ACCOUNT = "new_account";
|
||||
public static final String EXTRA_TMPL = "tmpl";
|
||||
public static final String EXTRA_EMAIL = "email";
|
||||
public static final String EXTRA_TOKEN = "masterToken";
|
||||
|
||||
private static final String TAG = "GmsAuthLoginBrowser";
|
||||
private static final String EMBEDDED_SETUP_URL = "https://accounts.google.com/EmbeddedSetup";
|
||||
private static final String MAGIC_USER_AGENT = " MinuteMaid";
|
||||
private static final String COOKIE_OAUTH_TOKEN = "oauth_token";
|
||||
private static final int TITLE_MIN_HEIGHT = 64;
|
||||
public static final double TITLE_WIDTH_FACTOR = (8.0 / 18.0);
|
||||
|
||||
private WebView webView;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.login_base);
|
||||
formatTitle();
|
||||
webView = createWebView(this);
|
||||
webView.addJavascriptInterface(new JsBridge(), "mm");
|
||||
((ViewGroup) findViewById(R.id.auth_root)).addView(webView);
|
||||
@ -75,18 +72,29 @@ public class LoginActivity extends Activity {
|
||||
closeWeb();
|
||||
}
|
||||
});
|
||||
CookieManager.getInstance().setAcceptCookie(true);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
CookieManager.getInstance().removeAllCookies(new ValueCallback<Boolean>() {
|
||||
@Override
|
||||
public void onReceiveValue(Boolean value) {
|
||||
load();
|
||||
}
|
||||
});
|
||||
if (getIntent().hasExtra(EXTRA_TOKEN)) {
|
||||
if (getIntent().hasExtra(EXTRA_EMAIL)) {
|
||||
AccountManager accountManager = AccountManager.get(LoginActivity.this);
|
||||
Account account = new Account(getIntent().getStringExtra(EXTRA_EMAIL), "com.google");
|
||||
accountManager.addAccountExplicitly(account, getIntent().getStringExtra(EXTRA_TOKEN), null);
|
||||
retrieveGmsToken(account);
|
||||
} else {
|
||||
retrieveRtToken(getIntent().getStringExtra(EXTRA_TOKEN));
|
||||
}
|
||||
} else {
|
||||
//noinspection deprecation
|
||||
CookieManager.getInstance().removeAllCookie();
|
||||
load();
|
||||
CookieManager.getInstance().setAcceptCookie(true);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
CookieManager.getInstance().removeAllCookies(new ValueCallback<Boolean>() {
|
||||
@Override
|
||||
public void onReceiveValue(Boolean value) {
|
||||
load();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
//noinspection deprecation
|
||||
CookieManager.getInstance().removeAllCookie();
|
||||
load();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,24 +127,9 @@ public class LoginActivity extends Activity {
|
||||
settings.setJavaScriptCanOpenWindowsAutomatically(false);
|
||||
}
|
||||
|
||||
private void formatTitle() {
|
||||
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
double widthPixels = (double) (getResources().getDisplayMetrics().widthPixels);
|
||||
findViewById(R.id.title_container).getLayoutParams().height =
|
||||
(int) (dpToPx(TITLE_MIN_HEIGHT) + (TITLE_WIDTH_FACTOR * widthPixels));
|
||||
} else {
|
||||
findViewById(R.id.title_container).getLayoutParams().height = dpToPx(TITLE_MIN_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
formatTitle();
|
||||
}
|
||||
|
||||
private void load() {
|
||||
webView.loadUrl(buildUrl(getIntent().hasExtra(EXTRA_TMPL) ? getIntent().getStringExtra(EXTRA_TMPL) : TMPL_NEW_ACCOUNT, Locale.getDefault()));
|
||||
String tmpl = getIntent().hasExtra(EXTRA_TMPL) ? getIntent().getStringExtra(EXTRA_TMPL) : TMPL_NEW_ACCOUNT;
|
||||
webView.loadUrl(buildUrl(tmpl, Utils.getLocale(this)));
|
||||
}
|
||||
|
||||
private void closeWeb() {
|
||||
@ -151,15 +144,23 @@ public class LoginActivity extends Activity {
|
||||
for (String ar1 : temp) {
|
||||
if (ar1.trim().startsWith(COOKIE_OAUTH_TOKEN + "=")) {
|
||||
String[] temp1 = ar1.split("=");
|
||||
sendRetrieveRtToken(temp1[1]);
|
||||
retrieveRtToken(temp1[1]);
|
||||
}
|
||||
}
|
||||
// TODO: Error message
|
||||
}
|
||||
|
||||
private void sendRetrieveRtToken(String oAuthToken) {
|
||||
AuthClient.request(new RetrieveRtTokenRequest(this, oAuthToken),
|
||||
new AuthClient.GmsAuthCallback() {
|
||||
private void retrieveRtToken(String oAuthToken) {
|
||||
new AuthRequest().fromContext(this)
|
||||
.appIsGms()
|
||||
.service("ac2dm")
|
||||
.token(oAuthToken).isAccessToken()
|
||||
.addAccount()
|
||||
.getAccountId()
|
||||
.systemPartition()
|
||||
.hasPermission()
|
||||
.droidguardResults(null /*TODO*/)
|
||||
.getResponseAsync(new AuthClient.GmsAuthCallback() {
|
||||
@Override
|
||||
public void onResponse(AuthResponse response) {
|
||||
AccountManager accountManager = AccountManager.get(LoginActivity.this);
|
||||
@ -167,9 +168,14 @@ public class LoginActivity extends Activity {
|
||||
if (accountManager.addAccountExplicitly(account, response.token, null)) {
|
||||
accountManager.setAuthToken(account, "SID", response.Sid);
|
||||
accountManager.setAuthToken(account, "LSID", response.LSid);
|
||||
accountManager.setUserData(account, "flags", "1");
|
||||
accountManager.setUserData(account, "services", response.services);
|
||||
accountManager.setUserData(account, "oauthAccessToken", "1");
|
||||
accountManager.setUserData(account, "firstName", response.firstName);
|
||||
accountManager.setUserData(account, "lastName", response.lastName);
|
||||
|
||||
retrieveGmsToken(account);
|
||||
setResult(RESULT_OK);
|
||||
// TODO: hand over to account setup
|
||||
finish();
|
||||
} else {
|
||||
// TODO: Error message
|
||||
Log.w(TAG, "Account NOT created!");
|
||||
@ -184,14 +190,62 @@ public class LoginActivity extends Activity {
|
||||
});
|
||||
}
|
||||
|
||||
public int dpToPx(int dp) {
|
||||
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
|
||||
return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
|
||||
private void retrieveGmsToken(final Account account) {
|
||||
final String service = "ac2dm";
|
||||
new AuthRequest().fromContext(this)
|
||||
.appIsGms()
|
||||
.service(service)
|
||||
.email(account.name)
|
||||
.token(AccountManager.get(this).getPassword(account))
|
||||
.systemPartition()
|
||||
.hasPermission()
|
||||
.addAccount()
|
||||
.getAccountId()
|
||||
.getResponseAsync(new AuthClient.GmsAuthCallback() {
|
||||
@Override
|
||||
public void onResponse(AuthResponse response) {
|
||||
AuthManager.storeResponse(LoginActivity.this, account,
|
||||
Constants.GMS_PACKAGE_NAME, Constants.GMS_PACKAGE_SIGNATURE_SHA1,
|
||||
service, response);
|
||||
retrieveGmsKeyUserinfoProfile(account);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Exception exception) {
|
||||
Log.w(TAG, "onException: " + exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void retrieveGmsKeyUserinfoProfile(final Account account) {
|
||||
final String service = "oauth2:https://www.googleapis.com/auth/userinfo.profile";
|
||||
new AuthRequest().fromContext(this)
|
||||
.appIsGms().callerIsGms()
|
||||
.service(service)
|
||||
.email(account.name)
|
||||
.token(AccountManager.get(this).getPassword(account))
|
||||
.systemPartition()
|
||||
.hasPermission()
|
||||
.getAccountId()
|
||||
.getResponseAsync(new AuthClient.GmsAuthCallback() {
|
||||
@Override
|
||||
public void onResponse(AuthResponse response) {
|
||||
AuthManager.storeResponse(LoginActivity.this, account,
|
||||
Constants.GMS_PACKAGE_NAME, Constants.GMS_PACKAGE_SIGNATURE_SHA1,
|
||||
service, response);
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Exception exception) {
|
||||
Log.w(TAG, "onException: " + exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack()) {
|
||||
if ((keyCode == KeyEvent.KEYCODE_BACK) && webView.canGoBack() && webView.getVisibility() == View.VISIBLE) {
|
||||
webView.goBack();
|
||||
return true;
|
||||
}
|
||||
|
@ -19,39 +19,69 @@ package org.microg.gms.auth.loginservice;
|
||||
import android.accounts.AbstractAccountAuthenticator;
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountAuthenticatorResponse;
|
||||
import android.accounts.AccountManager;
|
||||
import android.accounts.NetworkErrorException;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.R;
|
||||
|
||||
import org.microg.gms.auth.AuthClient;
|
||||
import org.microg.gms.auth.AuthManager;
|
||||
import org.microg.gms.auth.AuthRequest;
|
||||
import org.microg.gms.auth.AuthResponse;
|
||||
import org.microg.gms.auth.login.LoginActivity;
|
||||
import org.microg.gms.common.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class GoogleLoginService extends Service {
|
||||
private static final String TAG = "GmsLoginService";
|
||||
|
||||
private String accountType;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
accountType = getString(R.string.google_account_type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
if (intent.getAction().equals(android.accounts.AccountManager.ACTION_AUTHENTICATOR_INTENT)) {
|
||||
return new AbstractAccountAuthenticator(this) {
|
||||
@Override
|
||||
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
|
||||
Log.d(TAG, "editProperties: " + accountType);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
|
||||
if (accountType.equals(GoogleLoginService.this.accountType)) {
|
||||
return GoogleLoginService.this.addAccount(response, authTokenType, requiredFeatures, options);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
|
||||
Log.d(TAG, "confirmCredentials: " + account + ", " + options);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
|
||||
return null;
|
||||
return GoogleLoginService.this.getAuthToken(response, account, authTokenType, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthTokenLabel(String authTokenType) {
|
||||
Log.d(TAG, "getAuthTokenLabel: " + authTokenType);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -62,10 +92,55 @@ public class GoogleLoginService extends Service {
|
||||
|
||||
@Override
|
||||
public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
|
||||
return null;
|
||||
Log.d(TAG, "hasFeatures: " + account + ", " + Arrays.toString(features));
|
||||
Bundle b = new Bundle();
|
||||
b.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
|
||||
return b;
|
||||
}
|
||||
}.getIBinder();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) {
|
||||
options.keySet();
|
||||
Log.d(TAG, "getAuthToken: " + account + ", " + authTokenType + ", " + options);
|
||||
String app = options.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
|
||||
Utils.checkPackage(this, app, options.getInt(AccountManager.KEY_CALLER_UID), options.getInt(AccountManager.KEY_CALLER_UID));
|
||||
String appSignature = Utils.getFirstPackageSignatureDigest(this, app);
|
||||
try {
|
||||
AuthRequest request = new AuthRequest().fromContext(this)
|
||||
.email(account.name)
|
||||
.token(AccountManager.get(this).getPassword(account))
|
||||
.service(authTokenType)
|
||||
.app(app, appSignature)
|
||||
.callerIsGms()
|
||||
.calledFromAccountManager();
|
||||
if (AuthManager.isPermitted(this, account, app, appSignature, authTokenType)) {
|
||||
request.hasPermission();
|
||||
}
|
||||
AuthResponse r = request.getResponse();
|
||||
AuthManager.storeResponse(this, account, app, appSignature, authTokenType, r);
|
||||
if (r.expiry == 0)
|
||||
Log.d(TAG, "Auth: " + r.auth);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
|
||||
bundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
|
||||
bundle.putString(AccountManager.KEY_AUTHTOKEN, r.auth);
|
||||
return bundle;
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Bundle addAccount(AccountAuthenticatorResponse response, String authTokenType, String[] requiredFeatures, Bundle options) {
|
||||
final Intent i = new Intent(GoogleLoginService.this, LoginActivity.class);
|
||||
i.putExtras(options);
|
||||
i.putExtra(LoginActivity.EXTRA_TMPL, LoginActivity.TMPL_NEW_ACCOUNT);
|
||||
i.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
|
||||
final Bundle result = new Bundle();
|
||||
result.putParcelable(AccountManager.KEY_INTENT, i);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -14,18 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.auth;
|
||||
package org.microg.gms.common;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* This request will retrieve a rt token (oauth2rt) from an access token (oauth2)
|
||||
*/
|
||||
public class RetrieveRtTokenRequest extends GmsAddAccountRequest {
|
||||
|
||||
public RetrieveRtTokenRequest(Context context, String token) {
|
||||
super(context, token);
|
||||
this.isAccessToken = true;
|
||||
this.droidguardResults = null; // TODO
|
||||
}
|
||||
public class Build {
|
||||
public int sdk = android.os.Build.VERSION.SDK_INT;
|
||||
public String id = android.os.Build.ID;
|
||||
public String device = android.os.Build.DEVICE;
|
||||
}
|
@ -17,10 +17,78 @@
|
||||
package org.microg.gms.common;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
public class Utils {
|
||||
public static String getAndroidIdHex(Context context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Locale getLocale(Context context) {
|
||||
return Locale.getDefault(); // TODO
|
||||
}
|
||||
|
||||
public static Build getBuild(Context context) {
|
||||
return new Build();
|
||||
}
|
||||
|
||||
public static void checkPackage(Context context, String packageName,int callingUid) {
|
||||
String[] packagesForUid = context.getPackageManager().getPackagesForUid(callingUid);
|
||||
if (packagesForUid != null && !Arrays.asList(packagesForUid).contains(packageName)) {
|
||||
throw new SecurityException("callingUid [" + callingUid + "] is not related to packageName [" + packageName + "]");
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkPackage(Context context, String packageName, int callerUid, int callingUid) {
|
||||
if (callerUid != 0 && callerUid != callingUid) {
|
||||
throw new SecurityException("callerUid [" + callerUid + "] and real calling uid [" + callingUid + "] mismatch!");
|
||||
}
|
||||
checkPackage(context, packageName, callingUid);
|
||||
}
|
||||
|
||||
public static String getFirstPackageSignatureDigest(Context context, String packageName) {
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
final PackageInfo info;
|
||||
try {
|
||||
info = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (info != null && info.signatures != null && info.signatures.length > 0) {
|
||||
for (Signature sig : info.signatures) {
|
||||
String digest = sha1sum(sig.toByteArray());
|
||||
if (digest != null) {
|
||||
return digest;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String sha1sum(byte[] bytes) {
|
||||
MessageDigest md;
|
||||
try {
|
||||
md = MessageDigest.getInstance("SHA1");
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
return null;
|
||||
}
|
||||
if (md != null) {
|
||||
bytes = md.digest(bytes);
|
||||
if (bytes != null) {
|
||||
StringBuilder sb = new StringBuilder(2 * bytes.length);
|
||||
for (byte b : bytes) {
|
||||
sb.append(String.format("%02x", b));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
56
src/org/microg/gms/feeds/SubscribedFeedsProvider.java
Normal file
56
src/org/microg/gms/feeds/SubscribedFeedsProvider.java
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2013-2015 µg 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.feeds;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.MatrixCursor;
|
||||
import android.net.Uri;
|
||||
|
||||
public class SubscribedFeedsProvider extends ContentProvider{
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||
return new MatrixCursor(new String[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType(Uri uri) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(Uri uri, ContentValues values) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
||||
return 0;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user