diff --git a/src/org/microg/gms/auth/AuthClient.java b/src/org/microg/gms/auth/AuthClient.java deleted file mode 100644 index 312d2c63..00000000 --- a/src/org/microg/gms/auth/AuthClient.java +++ /dev/null @@ -1,84 +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.net.Uri; -import android.util.Log; - -import org.microg.gms.common.Utils; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.Map; - -public class AuthClient { - private static final String TAG = "GmsAuthClient"; - private static final String SERVICE_URL = "https://android.clients.google.com/auth"; - - public static AuthResponse request(AuthRequest request) throws IOException { - HttpURLConnection connection = (HttpURLConnection) new URL(SERVICE_URL).openConnection(); - connection.setRequestMethod("POST"); - connection.setDoInput(true); - connection.setDoOutput(true); - connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - Map httpHeaders = request.getHttpHeaders(); - for (String key : httpHeaders.keySet()) { - connection.setRequestProperty(key, httpHeaders.get(key)); - } - StringBuilder content = new StringBuilder(); - Map formContent = request.getFormContent(); - for (String key : formContent.keySet()) { - if (content.length() > 0) - 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(); - - if (connection.getResponseCode() != 200) { - throw new IOException(connection.getResponseMessage()); - } - - String result = new String(Utils.readStreamToEnd(connection.getInputStream())); - Log.d(TAG, "-- Response --\n" + result); - return AuthResponse.parse(result); - } - - public static void request(final AuthRequest request, final GmsAuthCallback callback) { - new Thread(new Runnable() { - @Override - public void run() { - try { - callback.onResponse(request(request)); - } catch (Exception e) { - callback.onException(e); - } - } - }).start(); - } - - public static interface GmsAuthCallback { - void onResponse(AuthResponse response); - - void onException(Exception exception); - } -} diff --git a/src/org/microg/gms/auth/AuthRequest.java b/src/org/microg/gms/auth/AuthRequest.java index 971a8724..ec1b17b8 100644 --- a/src/org/microg/gms/auth/AuthRequest.java +++ b/src/org/microg/gms/auth/AuthRequest.java @@ -20,110 +20,74 @@ import android.content.Context; import org.microg.gms.common.Build; import org.microg.gms.common.Constants; +import org.microg.gms.common.HttpFormClient; 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 { +import static org.microg.gms.common.HttpFormClient.RequestContent; +import static org.microg.gms.common.HttpFormClient.RequestHeader; + +public class AuthRequest extends HttpFormClient.Request { + private static final String SERVICE_URL = "https://android.clients.google.com/auth"; private static final String USER_AGENT = "GoogleAuth/1.4 (%s %s)"; + @RequestHeader("User-Agent") + private String userAgent; + + @RequestHeader("app") + @RequestContent("app") public String app; + @RequestContent("client_sig") public String appSignature; + @RequestContent("callerPkg") public String caller; + @RequestContent("callerSig") public String callerSignature; + @RequestHeader(value = "device", nullPresent = true) + @RequestContent(value = "androidId", nullPresent = true) public String androidIdHex; + @RequestContent("sdk_version") + public int sdkVersion; + @RequestContent("device_country") + public String countryCode; + @RequestContent("operatorCountry") + public String operatorCountryCode; + @RequestContent("lang") + public String locale; + @RequestContent("google_play_services_version") + public int gmsVersion = Constants.MAX_REFERENCE_VERSION; + @RequestContent("accountType") + public String accountType = "HOSTED_OR_GOOGLE"; + @RequestContent("Email") + public String email; + @RequestContent("service") + public String service; + @RequestContent("source") + public String source = "android"; + @RequestContent({"is_called_from_account_manager", "_opt_is_called_from_account_manager"}) + public boolean isCalledFromAccountManager; + @RequestContent("Token") + public String token; + @RequestContent("system_partition") + public boolean systemPartition; + @RequestContent("get_accountid") + public boolean getAccountId; + @RequestContent("ACCESS_TOKEN") + public boolean isAccessToken; + @RequestContent("droidguard_results") + public String droidguardResults; + @RequestContent("has_permission") + public boolean hasPermission; + @RequestContent("add_account") + public boolean addAccount; public String deviceName; public String buildVersion; - public int sdkVersion; - public String countryCode; - public String operatorCountryCode; - public String locale; - 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 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 getHttpHeaders() { - Map map = new HashMap<>(); - map.put("app", app); - map.put("device", androidIdHex); - map.put("User-Agent", String.format(USER_AGENT, deviceName, buildVersion)); - map.put("Content-Type", "application/x-www-form-urlencoded"); - return map; - } - - public Map getFormContent() { - Map map = new HashMap<>(); - map.put("device_country", countryCode); - map.put("operatorCountry", operatorCountryCode); - map.put("lang", locale); - map.put("sdk_version", Integer.toString(sdkVersion)); - map.put("google_play_services_version", Integer.toString(gmsVersion)); - map.put("accountType", accountType); - 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); - map.put("service", service); - map.put("source", source); - map.put("androidId", androidIdHex); - if (getAccountId) map.put("get_accountid", "1"); - map.put("app", app); - map.put("client_sig", appSignature); - if (caller != null) { - map.put("callerPkg", caller); - map.put("callerSig", callerSignature); - } - if (isCalledFromAccountManager) { - map.put("is_called_from_account_manager", "1"); - map.put("_opt_is_called_from_account_manager", "1"); - } - if (isAccessToken) map.put("ACCESS_TOKEN", "1"); - map.put("Token", token); - if (droidguardResults != null) map.put("droidguard_results", droidguardResults); - return map; + @Override + protected void prepare() { + userAgent = String.format(USER_AGENT, deviceName, buildVersion); } public AuthRequest build(Build build) { @@ -222,10 +186,10 @@ public class AuthRequest { } public AuthResponse getResponse() throws IOException { - return AuthClient.request(this); + return HttpFormClient.request(SERVICE_URL, this, AuthResponse.class); } - public void getResponseAsync(AuthClient.GmsAuthCallback callback) { - AuthClient.request(this, callback); + public void getResponseAsync(HttpFormClient.Callback callback) { + HttpFormClient.requestAsync(SERVICE_URL, this, AuthResponse.class, callback); } } diff --git a/src/org/microg/gms/auth/AuthResponse.java b/src/org/microg/gms/auth/AuthResponse.java index c6279383..82c604ce 100644 --- a/src/org/microg/gms/auth/AuthResponse.java +++ b/src/org/microg/gms/auth/AuthResponse.java @@ -18,14 +18,9 @@ package org.microg.gms.auth; import android.util.Log; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; + +import static org.microg.gms.common.HttpFormClient.ResponseField; public class AuthResponse { private static final String TAG = "GmsAuthResponse"; @@ -91,12 +86,4 @@ public class AuthResponse { } return response; } - - - - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.FIELD) - private @interface ResponseField { - public String value(); - } } diff --git a/src/org/microg/gms/auth/login/LoginActivity.java b/src/org/microg/gms/auth/login/LoginActivity.java index b13efd49..92ed3d3a 100644 --- a/src/org/microg/gms/auth/login/LoginActivity.java +++ b/src/org/microg/gms/auth/login/LoginActivity.java @@ -37,11 +37,11 @@ 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.common.Constants; +import org.microg.gms.common.HttpFormClient; import org.microg.gms.common.Utils; import org.microg.gms.userinfo.ProfileManager; @@ -161,7 +161,7 @@ public class LoginActivity extends AssistantActivity { .systemPartition() .hasPermission() .droidguardResults(null /*TODO*/) - .getResponseAsync(new AuthClient.GmsAuthCallback() { + .getResponseAsync(new HttpFormClient.Callback() { @Override public void onResponse(AuthResponse response) { AccountManager accountManager = AccountManager.get(LoginActivity.this); @@ -202,7 +202,7 @@ public class LoginActivity extends AssistantActivity { .hasPermission() .addAccount() .getAccountId() - .getResponseAsync(new AuthClient.GmsAuthCallback() { + .getResponseAsync(new HttpFormClient.Callback() { @Override public void onResponse(AuthResponse response) { AuthManager.storeResponse(LoginActivity.this, account, @@ -220,7 +220,7 @@ public class LoginActivity extends AssistantActivity { private void retrieveGmsKeyUserinfoProfile(final Account account) { ProfileManager.getAuthKeyRequest(this, account) - .getResponseAsync(new AuthClient.GmsAuthCallback() { + .getResponseAsync(new HttpFormClient.Callback() { @Override public void onResponse(AuthResponse response) { AuthManager.storeResponse(LoginActivity.this, account, diff --git a/src/org/microg/gms/common/HttpFormClient.java b/src/org/microg/gms/common/HttpFormClient.java index 58e57f77..4f932fcb 100644 --- a/src/org/microg/gms/common/HttpFormClient.java +++ b/src/org/microg/gms/common/HttpFormClient.java @@ -43,16 +43,30 @@ public class HttpFormClient { for (Field field : request.getClass().getDeclaredFields()) { try { field.setAccessible(true); - String value = String.valueOf(field.get(request)); + Object objVal = field.get(request); + String value = objVal != null ? String.valueOf(objVal) : null; + Boolean boolVal = null; + if (field.getType().equals(boolean.class)) { + boolVal = field.getBoolean(request); + } if (field.isAnnotationPresent(RequestHeader.class)) { - for (String key : field.getAnnotation(RequestHeader.class).value()) { - connection.setRequestProperty(key, value); + RequestHeader annotation = field.getAnnotation(RequestHeader.class); + value = valueFromBoolVal(value, boolVal, annotation.truePresent(), annotation.falsePresent()); + if (value != null || annotation.nullPresent()) { + for (String key : annotation.value()) { + connection.setRequestProperty(key, String.valueOf(value)); + } } - } else if (field.isAnnotationPresent(RequestContent.class)) { - for (String key : field.getAnnotation(RequestHeader.class).value()) { - if (content.length() > 0) - content.append("&"); - content.append(Uri.encode(key)).append("=").append(Uri.encode(value)); + } + if (field.isAnnotationPresent(RequestContent.class)) { + RequestContent annotation = field.getAnnotation(RequestContent.class); + value = valueFromBoolVal(value, boolVal, annotation.truePresent(), annotation.falsePresent()); + if (value != null || annotation.nullPresent()) { + for (String key : annotation.value()) { + if (content.length() > 0) + content.append("&"); + content.append(Uri.encode(key)).append("=").append(Uri.encode(String.valueOf(value))); + } } } } catch (Exception ignored) { @@ -73,6 +87,20 @@ public class HttpFormClient { return parseResponse(tClass, result); } + private static String valueFromBoolVal(String value, Boolean boolVal, boolean truePresent, boolean falsePresent) { + if (boolVal != null) { + if (boolVal && truePresent) { + return "1"; + } else if (!boolVal && falsePresent) { + return "0"; + } else { + return null; + } + } else { + return value; + } + } + private static T parseResponse(Class tClass, String result) { T response; try { @@ -136,12 +164,24 @@ public class HttpFormClient { @Target(ElementType.FIELD) public @interface RequestHeader { public String[] value(); + + public boolean truePresent() default true; + + public boolean falsePresent() default false; + + public boolean nullPresent() default false; } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface RequestContent { public String[] value(); + + public boolean truePresent() default true; + + public boolean falsePresent() default false; + + public boolean nullPresent() default false; } @Retention(RetentionPolicy.RUNTIME) diff --git a/src/org/microg/gms/gcm/Constants.java b/src/org/microg/gms/gcm/Constants.java deleted file mode 100644 index 03e8670a..00000000 --- a/src/org/microg/gms/gcm/Constants.java +++ /dev/null @@ -1,22 +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.gcm; - -public class Constants { - public static final String REGISTER_URL = "https://android.clients.google.com/c2dm/register3"; - -} diff --git a/src/org/microg/gms/gcm/RegisterRequest.java b/src/org/microg/gms/gcm/RegisterRequest.java index 4b6261cf..aea450d6 100644 --- a/src/org/microg/gms/gcm/RegisterRequest.java +++ b/src/org/microg/gms/gcm/RegisterRequest.java @@ -26,6 +26,7 @@ import static org.microg.gms.common.HttpFormClient.RequestContent; import static org.microg.gms.common.HttpFormClient.RequestHeader; public class RegisterRequest extends HttpFormClient.Request { + private static final String SERVICE_URL = "https://android.clients.google.com/c2dm/register3"; private static final String USER_AGENT = "Android-GCM/1.3 (%s %s)"; @RequestHeader("Authorization") @@ -86,10 +87,10 @@ public class RegisterRequest extends HttpFormClient.Request { } public RegisterResponse getResponse() throws IOException { - return HttpFormClient.request(Constants.REGISTER_URL, this, RegisterResponse.class); + return HttpFormClient.request(SERVICE_URL, this, RegisterResponse.class); } public void getResponseAsync(HttpFormClient.Callback callback) { - HttpFormClient.requestAsync(Constants.REGISTER_URL, this, RegisterResponse.class, callback); + HttpFormClient.requestAsync(SERVICE_URL, this, RegisterResponse.class, callback); } }