am 6ae03f34: am 4eb03f8f: Merge "Remove obsolete code for App Links IntentFilterVerifier" into mnc-dev
* commit '6ae03f34d5f8d5dd10f47c62ee291e9fc149809e': Remove obsolete code for App Links IntentFilterVerifier
This commit is contained in:
@@ -1,22 +0,0 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
# Build the IntentFilterVerifier.
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := \
|
||||
volley \
|
||||
|
||||
LOCAL_JAVA_LIBRARIES += org.apache.http.legacy
|
||||
|
||||
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||
|
||||
LOCAL_PACKAGE_NAME := IntentFilterVerifier
|
||||
|
||||
LOCAL_PRIVILEGED_MODULE := true
|
||||
|
||||
LOCAL_PROGUARD_FLAGS := $(proguard.flags)
|
||||
|
||||
include $(BUILD_PACKAGE)
|
||||
|
||||
# Build the test package.
|
||||
include $(call all-makefiles-under,$(LOCAL_PATH))
|
||||
@@ -1,44 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.verifier.intentfilter"
|
||||
coreApp="true">
|
||||
<uses-permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
|
||||
<application
|
||||
android:label="@string/service_name"
|
||||
android:allowBackup="false">
|
||||
|
||||
<receiver
|
||||
android:name="com.android.verifier.intentfilter.IntentVerificationReceiver"
|
||||
android:permission="android.permission.BIND_INTENT_FILTER_VERIFIER" >
|
||||
<intent-filter
|
||||
android:priority="-1" >
|
||||
<action android:name="android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION" />
|
||||
<data android:mimeType="application/vnd.android.package-archive" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service android:name=".IntentVerificationService"
|
||||
android:label="@string/service_name"
|
||||
android:exported="false"/>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -1,49 +0,0 @@
|
||||
# Copyright (C) 2015 The Android Open Source Project
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# If you don't need to do a full clean build but would like to touch
|
||||
# a file or delete some intermediate files, add a clean step to the end
|
||||
# of the list. These steps will only be run once, if they haven't been
|
||||
# run before.
|
||||
#
|
||||
# E.g.:
|
||||
# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
|
||||
# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
|
||||
#
|
||||
# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
|
||||
# files that are missing or have been moved.
|
||||
#
|
||||
# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
|
||||
# Use $(OUT_DIR) to refer to the "out" directory.
|
||||
#
|
||||
# If you need to re-do something that's already mentioned, just copy
|
||||
# the command and add it to the bottom of the list. E.g., if a change
|
||||
# that you made last week required touching a file and a change you
|
||||
# made today requires touching the same file, just copy the old
|
||||
# touch step and add it to the end of the list.
|
||||
#
|
||||
# *****************************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
|
||||
# *****************************************************************
|
||||
|
||||
# For example:
|
||||
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
|
||||
#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
|
||||
#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
|
||||
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
|
||||
|
||||
# ******************************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
|
||||
# ******************************************************************
|
||||
@@ -1 +0,0 @@
|
||||
-verbose
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2015 The Android Open Source Project
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<!-- Package name shown to users when they look at installed applications
|
||||
and running processes. This service verifies packages that are
|
||||
requested to be installed. [CHAR LIMIT=50] -->
|
||||
<string name="service_name">Basic Intent Filter Verification Service</string>
|
||||
|
||||
</resources>
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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 com.android.verifier.intentfilter;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class IntentVerificationReceiver extends BroadcastReceiver {
|
||||
static final String TAG = IntentVerificationReceiver.class.getName();
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
if (Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION.equals(action)) {
|
||||
Bundle extras = intent.getExtras();
|
||||
if (extras != null) {
|
||||
int verificationId = extras.getInt(
|
||||
PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_ID);
|
||||
String hosts = extras.getString(
|
||||
PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_HOSTS);
|
||||
|
||||
Log.d(TAG, "Received IntentFilter verification broadcast with verificationId: "
|
||||
+ verificationId);
|
||||
|
||||
if (canDoVerification(context)) {
|
||||
Intent serviceIntent = new Intent(context, IntentVerificationService.class);
|
||||
serviceIntent.fillIn(intent, 0);
|
||||
serviceIntent.putExtras(intent.getExtras());
|
||||
|
||||
Slog.d(TAG, "Starting Intent Verification Service.");
|
||||
|
||||
context.startService(serviceIntent);
|
||||
} else {
|
||||
sendVerificationFailure(context, verificationId, hosts);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Log.w(TAG, "Unexpected action: " + action);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendVerificationFailure(Context context, int verificationId, String hosts) {
|
||||
List<String> list = Arrays.asList(hosts.split(" "));
|
||||
context.getPackageManager().verifyIntentFilter(
|
||||
verificationId, PackageManager.INTENT_FILTER_VERIFICATION_FAILURE, list);
|
||||
|
||||
Log.d(TAG, "No network! Failing IntentFilter verification with verificationId: " +
|
||||
verificationId + " and hosts: " + hosts);
|
||||
}
|
||||
|
||||
private boolean canDoVerification(Context context) {
|
||||
return hasNetwork(context);
|
||||
}
|
||||
|
||||
public boolean hasNetwork(Context context) {
|
||||
ConnectivityManager cm =
|
||||
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
if (cm != null) {
|
||||
NetworkInfo info = cm.getActiveNetworkInfo();
|
||||
return (info != null) && info.isConnected();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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 com.android.verifier.intentfilter;
|
||||
|
||||
import com.android.volley.Response;
|
||||
import com.android.volley.toolbox.JsonArrayRequest;
|
||||
import org.json.JSONArray;
|
||||
|
||||
public class IntentVerificationRequest extends JsonArrayRequest {
|
||||
|
||||
public IntentVerificationRequest(String url, Response.Listener<JSONArray> listener,
|
||||
Response.ErrorListener errorListener) {
|
||||
super(url, listener, errorListener);
|
||||
}
|
||||
}
|
||||
@@ -1,468 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* 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 com.android.verifier.intentfilter;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.Signature;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import com.android.volley.RequestQueue;
|
||||
import com.android.volley.Response;
|
||||
import com.android.volley.VolleyError;
|
||||
import com.android.volley.toolbox.Volley;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class IntentVerificationService extends Service {
|
||||
private static final String TAG = "IntentVerificationService";
|
||||
|
||||
private static final String WELL_KNOWN_ASSOCIATIONS_JSON = "/.well-known/associations.json";
|
||||
private static final String DEFAULT_SCHEME = "https";
|
||||
|
||||
private static final String JSON_KEY_TARGET = "target";
|
||||
private static final String JSON_KEY_NAMESPACE = "namespace";
|
||||
private static final String JSON_KEY_PACKAGE_NAME = "package_name";
|
||||
private static final String JSON_KEY_CERT_FINGERPRINTS = "sha256_cert_fingerprints";
|
||||
|
||||
private static final String JSON_VAL_ANDROID_APP = "android_app";
|
||||
|
||||
private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'A', 'B', 'C', 'D', 'E', 'F' };
|
||||
|
||||
private ConnectivityManager mConnectivityManager;
|
||||
private Looper mHandlerLooper;
|
||||
private VerificationHandler mHandler;
|
||||
private RequestQueue mRequestQueue;
|
||||
|
||||
private static class VerificationState {
|
||||
public final int verificationId;
|
||||
public final String hosts;
|
||||
public final String packageName;
|
||||
public final Set<String> fingerprints;
|
||||
public int responseCode = PackageManager.INTENT_FILTER_VERIFICATION_SUCCESS;
|
||||
public int counter;
|
||||
public int numberOfHosts;
|
||||
public ArrayList<String> failedHosts = new ArrayList<>();
|
||||
|
||||
private final Object lock = new Object();
|
||||
|
||||
public VerificationState(int id, String h, String p, Set<String> fps) {
|
||||
verificationId = id;
|
||||
hosts = h;
|
||||
packageName = p;
|
||||
fingerprints = fps;
|
||||
numberOfHosts = hosts.split(" ").length;
|
||||
}
|
||||
public boolean setResponseCodeAndCheckMax(int code) {
|
||||
synchronized (lock) {
|
||||
if (code == PackageManager.INTENT_FILTER_VERIFICATION_FAILURE) {
|
||||
responseCode = code;
|
||||
counter++;
|
||||
} else if (code == PackageManager.INTENT_FILTER_VERIFICATION_SUCCESS) {
|
||||
counter++;
|
||||
}
|
||||
return (counter == numberOfHosts);
|
||||
}
|
||||
}
|
||||
|
||||
public void addFailedHost(String host) {
|
||||
synchronized (failedHosts) {
|
||||
failedHosts.add(host);
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<String> getFailedHosts() {
|
||||
return failedHosts;
|
||||
}
|
||||
}
|
||||
|
||||
private HashMap<Integer, VerificationState> mVerificationMap =
|
||||
new HashMap<Integer, VerificationState>();
|
||||
|
||||
private class VerificationHandler extends Handler {
|
||||
private static final int MSG_STOP_SERVICE = 0;
|
||||
private static final int MSG_VERIFY_INTENT_START = 1;
|
||||
private static final int MSG_VERIFY_INTENT_DONE = 2;
|
||||
|
||||
private static final long SHUTDOWN_DELAY_MILLIS = 8 * 1000;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
public VerificationHandler(Context context, Looper looper) {
|
||||
super(looper);
|
||||
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_VERIFY_INTENT_START:
|
||||
final Intent intent = (Intent) msg.obj;
|
||||
Bundle extras = intent.getExtras();
|
||||
boolean immediate = false;
|
||||
|
||||
if (extras != null) {
|
||||
immediate = doVerification(extras);
|
||||
}
|
||||
|
||||
// There was no network, so we can stop soon
|
||||
if (immediate) {
|
||||
stopDelayed();
|
||||
}
|
||||
break;
|
||||
|
||||
case MSG_VERIFY_INTENT_DONE:
|
||||
VerificationState vs = (VerificationState) msg.obj;
|
||||
processVerificationDone(mContext, vs);
|
||||
clearVerificationState(vs);
|
||||
break;
|
||||
|
||||
case MSG_STOP_SERVICE:
|
||||
stopSelf();
|
||||
break;
|
||||
|
||||
default:
|
||||
Slog.i(TAG, "Unknown message posted " + msg.toString());
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void stopDelayed() {
|
||||
removeMessages(MSG_STOP_SERVICE);
|
||||
sendEmptyMessageDelayed(MSG_STOP_SERVICE, SHUTDOWN_DELAY_MILLIS);
|
||||
}
|
||||
}
|
||||
|
||||
private VerificationState getVerificationState(int id, String hosts, String packageName,
|
||||
Set<String> fingerprints) {
|
||||
synchronized (mVerificationMap) {
|
||||
VerificationState vs = mVerificationMap.get(id);
|
||||
if (vs == null) {
|
||||
vs = new VerificationState(id, hosts, packageName, fingerprints);
|
||||
}
|
||||
return vs;
|
||||
}
|
||||
}
|
||||
|
||||
private void clearVerificationState(VerificationState vs) {
|
||||
mVerificationMap.remove(vs);
|
||||
}
|
||||
|
||||
private boolean doVerification(Bundle extras) {
|
||||
String scheme = extras.getString(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_URI_SCHEME);
|
||||
if (TextUtils.isEmpty(scheme)) {
|
||||
scheme = DEFAULT_SCHEME;
|
||||
}
|
||||
|
||||
int verificationId = extras.getInt(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_ID);
|
||||
String hosts = extras.getString(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_HOSTS);
|
||||
String packageName = extras.getString(
|
||||
PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_PACKAGE_NAME);
|
||||
|
||||
Set<String> fingerprints = getFingerprints(packageName);
|
||||
|
||||
Log.d(TAG, "Received IntentFilter verification broadcast with verificationId:" +
|
||||
verificationId + " hosts:'" + hosts + "' scheme:" + scheme);
|
||||
|
||||
VerificationState vs = getVerificationState(verificationId, hosts, packageName,
|
||||
fingerprints);
|
||||
|
||||
if (hasNetwork()) {
|
||||
sendNetworkVerifications(scheme, vs);
|
||||
return false;
|
||||
}
|
||||
|
||||
// No network, so fail immediately
|
||||
sendFailureResponseIfNeeded(vs);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Set<String> getFingerprints(String packageName) {
|
||||
Context context = getApplicationContext();
|
||||
try {
|
||||
Signature[] signatures = context.getPackageManager().getPackageInfo(packageName,
|
||||
PackageManager.GET_SIGNATURES).signatures;
|
||||
if (signatures.length > 0) {
|
||||
HashSet<String> result = new HashSet<String>();
|
||||
for (Signature sig : signatures) {
|
||||
String fingerprint = computeNormalizedSha256Fingerprint(sig.toByteArray());
|
||||
result.add(fingerprint);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
Log.e(TAG, "Cannot get signatures for package name: " + packageName);
|
||||
}
|
||||
return Collections.EMPTY_SET;
|
||||
}
|
||||
|
||||
private static String computeNormalizedSha256Fingerprint(byte[] signature) {
|
||||
MessageDigest digester;
|
||||
try {
|
||||
digester = MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError("No SHA-256 implementation found.");
|
||||
}
|
||||
digester.update(signature);
|
||||
return byteArrayToHexString(digester.digest());
|
||||
}
|
||||
|
||||
private static String byteArrayToHexString(byte[] array) {
|
||||
if (array.length == 0) {
|
||||
return "";
|
||||
}
|
||||
char[] buf = new char[array.length * 3 - 1];
|
||||
|
||||
int bufIndex = 0;
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
byte b = array[i];
|
||||
if (i > 0) {
|
||||
buf[bufIndex++] = ':';
|
||||
}
|
||||
buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
|
||||
buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
|
||||
}
|
||||
return new String(buf);
|
||||
}
|
||||
|
||||
private static String getAssociationPath() {
|
||||
return WELL_KNOWN_ASSOCIATIONS_JSON;
|
||||
}
|
||||
|
||||
private void sendNetworkVerifications(String scheme, final VerificationState vs) {
|
||||
final int verificationId = vs.verificationId;
|
||||
final String hosts = vs.hosts;
|
||||
|
||||
String[] array = hosts.split(" ");
|
||||
for (final String host : array) {
|
||||
try {
|
||||
final URL url = new URL(scheme, host, getAssociationPath());
|
||||
final String urlStr = url.toString();
|
||||
Log.d(TAG, "Using verification URL: " + urlStr);
|
||||
IntentVerificationRequest req = new IntentVerificationRequest(urlStr,
|
||||
new Response.Listener<JSONArray>() {
|
||||
@Override
|
||||
public void onResponse(JSONArray response) {
|
||||
Log.d(TAG, "From: " + urlStr + " received response: "
|
||||
+ response.toString());
|
||||
handleResponse(vs, host, response);
|
||||
}
|
||||
}, new Response.ErrorListener() {
|
||||
@Override
|
||||
public void onErrorResponse(VolleyError error) {
|
||||
Slog.d(TAG, "From: " + urlStr + " got error: " + error.getMessage()
|
||||
+ (error.networkResponse != null ? " with status code: "
|
||||
+ error.networkResponse.statusCode : ""));
|
||||
handleError(vs, host);
|
||||
}
|
||||
}
|
||||
);
|
||||
mRequestQueue.add(req);
|
||||
} catch (MalformedURLException e) {
|
||||
Log.w(TAG, "Cannot send verificationId: " + verificationId + " to host: " + host);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleError(VerificationState vs, String host) {
|
||||
vs.addFailedHost(host);
|
||||
sendFailureResponseIfNeeded(vs);
|
||||
}
|
||||
|
||||
private void handleResponse(VerificationState vs, String host, JSONArray response) {
|
||||
try {
|
||||
if (response.length() == 0) {
|
||||
Log.d(TAG, "Domain response is empty!");
|
||||
handleError(vs, host);
|
||||
return;
|
||||
}
|
||||
|
||||
JSONObject firstRelation = (JSONObject) response.get(0);
|
||||
if (firstRelation == null) {
|
||||
Log.d(TAG, "Domain response is should have a relation!");
|
||||
handleError(vs, host);
|
||||
return;
|
||||
}
|
||||
|
||||
JSONObject target = (JSONObject) firstRelation.get(JSON_KEY_TARGET);
|
||||
if (target == null) {
|
||||
Log.d(TAG, "Domain response target is empty!");
|
||||
handleError(vs, host);
|
||||
return;
|
||||
}
|
||||
|
||||
String nameSpace = target.getString(JSON_KEY_NAMESPACE);
|
||||
if (TextUtils.isEmpty(nameSpace) || !nameSpace.equals(JSON_VAL_ANDROID_APP)) {
|
||||
Log.d(TAG, "Domain response target name space is not valid: " + nameSpace);
|
||||
handleError(vs, host);
|
||||
return;
|
||||
}
|
||||
|
||||
String packageName = target.getString(JSON_KEY_PACKAGE_NAME);
|
||||
JSONArray certFingerprints = target.getJSONArray(JSON_KEY_CERT_FINGERPRINTS);
|
||||
|
||||
// Early exits is the JSON response is not correct for the package name or signature
|
||||
if (TextUtils.isEmpty(packageName)) {
|
||||
Log.d(TAG, "Domain response has empty package name!");
|
||||
handleError(vs, host);
|
||||
return;
|
||||
}
|
||||
if (certFingerprints.length() == 0) {
|
||||
Log.d(TAG, "Domain response has empty cert signature!");
|
||||
handleError(vs, host);
|
||||
return;
|
||||
}
|
||||
// Now do the real test on package name and signature
|
||||
if (!packageName.equalsIgnoreCase(vs.packageName)) {
|
||||
Log.d(TAG, "Domain response has package name mismatch!" + packageName +
|
||||
" vs " + vs.packageName);
|
||||
handleError(vs, host);
|
||||
return;
|
||||
}
|
||||
final int count = certFingerprints.length();
|
||||
for (int i = 0; i < count; i++) {
|
||||
String fingerprint = certFingerprints.getString(i);
|
||||
if (!vs.fingerprints.contains(fingerprint)) {
|
||||
Log.d(TAG, "Domain response has cert fingerprint mismatch! " +
|
||||
"The domain fingerprint '" + fingerprint + "' is not from the App");
|
||||
handleError(vs, host);
|
||||
return;
|
||||
}
|
||||
}
|
||||
sendSuccessResponseIfNeeded(vs);
|
||||
} catch (JSONException e) {
|
||||
Log.d(TAG, "Domain response is not well formed", e);
|
||||
handleError(vs, host);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendSuccessResponseIfNeeded(VerificationState vs) {
|
||||
if (vs.setResponseCodeAndCheckMax(PackageManager.INTENT_FILTER_VERIFICATION_SUCCESS)) {
|
||||
sendMessage(vs);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendFailureResponseIfNeeded(VerificationState vs) {
|
||||
if (vs.setResponseCodeAndCheckMax(PackageManager.INTENT_FILTER_VERIFICATION_FAILURE)) {
|
||||
sendMessage(vs);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendMessage(VerificationState vs) {
|
||||
Message msg = mHandler.obtainMessage(VerificationHandler.MSG_VERIFY_INTENT_DONE);
|
||||
msg.obj = vs;
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
private void processVerificationDone(Context context, VerificationState state) {
|
||||
int verificationId = state.verificationId;
|
||||
String hosts = state.hosts;
|
||||
int responseCode = state.responseCode;
|
||||
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
|
||||
// Callback the PackageManager
|
||||
pm.verifyIntentFilter(verificationId, responseCode, state.getFailedHosts());
|
||||
Log.d(TAG, "IntentFilter with verificationId: " + verificationId + " and hosts: " +
|
||||
hosts + " got verification code: " + responseCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* We only connect to this service from the same process.
|
||||
*/
|
||||
public class LocalBinder extends Binder {
|
||||
IntentVerificationService getService() { return IntentVerificationService.this; }
|
||||
}
|
||||
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
Slog.i(TAG, "Received start id " + startId + ": " + intent);
|
||||
|
||||
final Message msg = mHandler.obtainMessage(VerificationHandler.MSG_VERIFY_INTENT_START);
|
||||
msg.obj = intent;
|
||||
mHandler.sendMessage(msg);
|
||||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
Slog.d(TAG, "Starting up...");
|
||||
|
||||
final HandlerThread handlerThread = new HandlerThread("IntentVerificationService");
|
||||
handlerThread.start();
|
||||
mHandlerLooper = handlerThread.getLooper();
|
||||
|
||||
mHandler = new VerificationHandler(getApplicationContext(), mHandlerLooper);
|
||||
|
||||
mRequestQueue = Volley.newRequestQueue(this);
|
||||
mRequestQueue.start();
|
||||
|
||||
mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
Slog.d(TAG, "Shutting down...");
|
||||
|
||||
mHandlerLooper.quit();
|
||||
mRequestQueue.stop();
|
||||
}
|
||||
|
||||
private boolean hasNetwork() {
|
||||
NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
|
||||
return (info != null) && info.isConnected();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user