mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-24 18:45:28 +00:00
Seperate Google proprietary code
This commit is contained in:
parent
d4798b02ac
commit
42a6e0dd10
@ -63,6 +63,5 @@ dependencies {
|
|||||||
implementation 'org.bouncycastle:bcprov-jdk15on:1.57'
|
implementation 'org.bouncycastle:bcprov-jdk15on:1.57'
|
||||||
implementation 'org.bouncycastle:bcpkix-jdk15on:1.57'
|
implementation 'org.bouncycastle:bcpkix-jdk15on:1.57'
|
||||||
implementation 'org.kamranzafar:jtar:2.3'
|
implementation 'org.kamranzafar:jtar:2.3'
|
||||||
implementation 'com.google.android.gms:play-services-safetynet:9.0.1'
|
|
||||||
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
|
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
|
||||||
}
|
}
|
||||||
|
@ -90,9 +90,10 @@
|
|||||||
android:resource="@xml/file_paths" />
|
android:resource="@xml/file_paths" />
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
|
<!-- Hardcode GMS version -->
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.android.gms.version"
|
android:name="com.google.android.gms.version"
|
||||||
android:value="@integer/google_play_services_version" />
|
android:value="11400000" />
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import android.app.NotificationManager;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.annotation.StringRes;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
import android.support.v7.widget.CardView;
|
import android.support.v7.widget.CardView;
|
||||||
@ -19,7 +20,9 @@ import android.widget.ProgressBar;
|
|||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.asyncs.CheckSafetyNet;
|
||||||
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
import com.topjohnwu.magisk.asyncs.CheckUpdates;
|
||||||
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
import com.topjohnwu.magisk.components.ExpandableView;
|
import com.topjohnwu.magisk.components.ExpandableView;
|
||||||
import com.topjohnwu.magisk.components.Fragment;
|
import com.topjohnwu.magisk.components.Fragment;
|
||||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
@ -39,6 +42,13 @@ import butterknife.Unbinder;
|
|||||||
public class MagiskFragment extends Fragment
|
public class MagiskFragment extends Fragment
|
||||||
implements Topic.Subscriber, SwipeRefreshLayout.OnRefreshListener, ExpandableView {
|
implements Topic.Subscriber, SwipeRefreshLayout.OnRefreshListener, ExpandableView {
|
||||||
|
|
||||||
|
public static final int CAUSE_SERVICE_DISCONNECTED = 0x00001;
|
||||||
|
public static final int CAUSE_NETWORK_LOST = 0x00010;
|
||||||
|
public static final int RESPONSE_ERR = 0x00100;
|
||||||
|
|
||||||
|
public static final int BASIC_PASS = 0x01000;
|
||||||
|
public static final int CTS_PASS = 0x10000;
|
||||||
|
|
||||||
private Container expandableContainer = new Container();
|
private Container expandableContainer = new Container();
|
||||||
|
|
||||||
private MagiskManager mm;
|
private MagiskManager mm;
|
||||||
@ -85,11 +95,28 @@ public class MagiskFragment extends Fragment
|
|||||||
|
|
||||||
@OnClick(R.id.safetyNet_title)
|
@OnClick(R.id.safetyNet_title)
|
||||||
void safetyNet() {
|
void safetyNet() {
|
||||||
|
Runnable task = () -> {
|
||||||
|
mm.snet_version = CheckSafetyNet.SNET_VER;
|
||||||
|
mm.prefs.edit().putInt("snet_version", CheckSafetyNet.SNET_VER).apply();
|
||||||
safetyNetProgress.setVisibility(View.VISIBLE);
|
safetyNetProgress.setVisibility(View.VISIBLE);
|
||||||
safetyNetRefreshIcon.setVisibility(View.GONE);
|
safetyNetRefreshIcon.setVisibility(View.GONE);
|
||||||
safetyNetStatusText.setText(R.string.checking_safetyNet_status);
|
safetyNetStatusText.setText(R.string.checking_safetyNet_status);
|
||||||
Utils.checkSafetyNet(getActivity());
|
new CheckSafetyNet(getActivity()).exec();
|
||||||
collapse();
|
collapse();
|
||||||
|
};
|
||||||
|
if (mm.snet_version < 0) {
|
||||||
|
// Show dialog
|
||||||
|
new AlertDialogBuilder(getActivity())
|
||||||
|
.setTitle(R.string.proprietary_title)
|
||||||
|
.setMessage(R.string.proprietary_notice)
|
||||||
|
.setCancelable(true)
|
||||||
|
.setPositiveButton(R.string.yes, (d, i) -> task.run())
|
||||||
|
.setNegativeButton(R.string.no_thanks, null)
|
||||||
|
.show();
|
||||||
|
} else {
|
||||||
|
task.run();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.install_button)
|
@OnClick(R.id.install_button)
|
||||||
@ -158,11 +185,11 @@ public class MagiskFragment extends Fragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTopicPublished(Topic topic) {
|
public void onTopicPublished(Topic topic, Object result) {
|
||||||
if (topic == mm.updateCheckDone) {
|
if (topic == mm.updateCheckDone) {
|
||||||
updateCheckUI();
|
updateCheckUI();
|
||||||
} else if (topic == mm.safetyNetDone) {
|
} else if (topic == mm.safetyNetDone) {
|
||||||
updateSafetyNetUI();
|
updateSafetyNetUI((int) result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,37 +329,41 @@ public class MagiskFragment extends Fragment
|
|||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSafetyNetUI() {
|
private void updateSafetyNetUI(int response) {
|
||||||
int image, color;
|
|
||||||
safetyNetProgress.setVisibility(View.GONE);
|
safetyNetProgress.setVisibility(View.GONE);
|
||||||
safetyNetRefreshIcon.setVisibility(View.VISIBLE);
|
safetyNetRefreshIcon.setVisibility(View.VISIBLE);
|
||||||
if (mm.SNCheckResult.failed) {
|
if (response < 0) {
|
||||||
safetyNetStatusText.setText(mm.SNCheckResult.errmsg);
|
safetyNetStatusText.setText(R.string.safetyNet_api_error);
|
||||||
collapse();
|
} else if ((response & 0x111) == 0) {
|
||||||
} else {
|
|
||||||
safetyNetStatusText.setText(R.string.safetyNet_check_success);
|
safetyNetStatusText.setText(R.string.safetyNet_check_success);
|
||||||
if (mm.SNCheckResult.ctsProfile) {
|
|
||||||
color = colorOK;
|
|
||||||
image = R.drawable.ic_check_circle;
|
|
||||||
} else {
|
|
||||||
color = colorBad;
|
|
||||||
image = R.drawable.ic_cancel;
|
|
||||||
}
|
|
||||||
ctsStatusText.setText("ctsProfile: " + mm.SNCheckResult.ctsProfile);
|
|
||||||
ctsStatusIcon.setImageResource(image);
|
|
||||||
ctsStatusIcon.setColorFilter(color);
|
|
||||||
|
|
||||||
if (mm.SNCheckResult.basicIntegrity) {
|
boolean b;
|
||||||
color = colorOK;
|
b = (response & CTS_PASS) != 0;
|
||||||
image = R.drawable.ic_check_circle;
|
ctsStatusText.setText("ctsProfile: " + b);
|
||||||
} else {
|
ctsStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel);
|
||||||
color = colorBad;
|
ctsStatusIcon.setColorFilter(b ? colorOK : colorBad);
|
||||||
image = R.drawable.ic_cancel;
|
|
||||||
}
|
b = (response & BASIC_PASS) != 0;
|
||||||
basicStatusText.setText("basicIntegrity: " + mm.SNCheckResult.basicIntegrity);
|
basicStatusText.setText("basicIntegrity: " + b);
|
||||||
basicStatusIcon.setImageResource(image);
|
basicStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel);
|
||||||
basicStatusIcon.setColorFilter(color);
|
basicStatusIcon.setColorFilter(b ? colorOK : colorBad);
|
||||||
|
|
||||||
expand();
|
expand();
|
||||||
|
} else {
|
||||||
|
@StringRes int resid;
|
||||||
|
switch (response) {
|
||||||
|
case CAUSE_SERVICE_DISCONNECTED:
|
||||||
|
resid = R.string.safetyNet_network_loss;
|
||||||
|
break;
|
||||||
|
case CAUSE_NETWORK_LOST:
|
||||||
|
resid = R.string.safetyNet_service_disconnected;
|
||||||
|
break;
|
||||||
|
case RESPONSE_ERR:
|
||||||
|
default:
|
||||||
|
resid = R.string.safetyNet_res_invalid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
safetyNetStatusText.setText(resid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ public class MagiskHideFragment extends Fragment implements Topic.Subscriber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTopicPublished(Topic topic) {
|
public void onTopicPublished(Topic topic, Object result) {
|
||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
appAdapter.filter(lastFilter);
|
appAdapter.filter(lastFilter);
|
||||||
}
|
}
|
||||||
|
@ -20,13 +20,12 @@ import com.topjohnwu.magisk.asyncs.DownloadBusybox;
|
|||||||
import com.topjohnwu.magisk.asyncs.LoadModules;
|
import com.topjohnwu.magisk.asyncs.LoadModules;
|
||||||
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
import com.topjohnwu.magisk.asyncs.ParallelTask;
|
||||||
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
import com.topjohnwu.magisk.asyncs.UpdateRepos;
|
||||||
|
import com.topjohnwu.magisk.container.Module;
|
||||||
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.container.Module;
|
|
||||||
import com.topjohnwu.magisk.services.UpdateCheckService;
|
import com.topjohnwu.magisk.services.UpdateCheckService;
|
||||||
import com.topjohnwu.magisk.superuser.SuReceiver;
|
import com.topjohnwu.magisk.superuser.SuReceiver;
|
||||||
import com.topjohnwu.magisk.superuser.SuRequestActivity;
|
import com.topjohnwu.magisk.superuser.SuRequestActivity;
|
||||||
import com.topjohnwu.magisk.utils.SafetyNetHelper;
|
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Topic;
|
import com.topjohnwu.magisk.utils.Topic;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
@ -72,7 +71,6 @@ public class MagiskManager extends Application {
|
|||||||
public String remoteManagerVersionString;
|
public String remoteManagerVersionString;
|
||||||
public int remoteManagerVersionCode = -1;
|
public int remoteManagerVersionCode = -1;
|
||||||
public String managerLink;
|
public String managerLink;
|
||||||
public SafetyNetHelper.Result SNCheckResult;
|
|
||||||
public String bootBlock = null;
|
public String bootBlock = null;
|
||||||
public boolean isSuClient = false;
|
public boolean isSuClient = false;
|
||||||
public String suVersion = null;
|
public String suVersion = null;
|
||||||
@ -103,6 +101,7 @@ public class MagiskManager extends Application {
|
|||||||
public String localeConfig;
|
public String localeConfig;
|
||||||
public int updateChannel;
|
public int updateChannel;
|
||||||
public String bootFormat;
|
public String bootFormat;
|
||||||
|
public int snet_version;
|
||||||
|
|
||||||
// Global resources
|
// Global resources
|
||||||
public SharedPreferences prefs;
|
public SharedPreferences prefs;
|
||||||
@ -184,6 +183,7 @@ public class MagiskManager extends Application {
|
|||||||
updateNotification = prefs.getBoolean("notification", true);
|
updateNotification = prefs.getBoolean("notification", true);
|
||||||
updateChannel = Utils.getPrefsInt(prefs, "update_channel", CheckUpdates.STABLE_CHANNEL);
|
updateChannel = Utils.getPrefsInt(prefs, "update_channel", CheckUpdates.STABLE_CHANNEL);
|
||||||
bootFormat = prefs.getString("boot_format", ".img");
|
bootFormat = prefs.getString("boot_format", ".img");
|
||||||
|
snet_version = prefs.getInt("snet_version", -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toast(String msg, int duration) {
|
public void toast(String msg, int duration) {
|
||||||
|
@ -102,7 +102,7 @@ public class MainActivity extends Activity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTopicPublished(Topic topic) {
|
public void onTopicPublished(Topic topic, Object result) {
|
||||||
recreate();
|
recreate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ public class ModulesFragment extends Fragment implements Topic.Subscriber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTopicPublished(Topic topic) {
|
public void onTopicPublished(Topic topic, Object result) {
|
||||||
Logger.dev("ModulesFragment: UI refresh triggered");
|
Logger.dev("ModulesFragment: UI refresh triggered");
|
||||||
updateUI();
|
updateUI();
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ public class ReposFragment extends Fragment implements Topic.Subscriber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTopicPublished(Topic topic) {
|
public void onTopicPublished(Topic topic, Object result) {
|
||||||
mSwipeRefreshLayout.setRefreshing(false);
|
mSwipeRefreshLayout.setRefreshing(false);
|
||||||
recyclerView.setVisibility(adapter.getItemCount() == 0 ? View.GONE : View.VISIBLE);
|
recyclerView.setVisibility(adapter.getItemCount() == 0 ? View.GONE : View.VISIBLE);
|
||||||
emptyRv.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
emptyRv.setVisibility(adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||||
|
@ -62,7 +62,7 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTopicPublished(Topic topic) {
|
public void onTopicPublished(Topic topic, Object result) {
|
||||||
recreate();
|
recreate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,7 +273,7 @@ public class SettingsActivity extends Activity implements Topic.Subscriber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTopicPublished(Topic topic) {
|
public void onTopicPublished(Topic topic, Object result) {
|
||||||
setLocalePreference((ListPreference) findPreference("locale"));
|
setLocalePreference((ListPreference) findPreference("locale"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,8 +15,8 @@ import com.topjohnwu.magisk.R;
|
|||||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
import com.topjohnwu.magisk.components.ExpandableView;
|
import com.topjohnwu.magisk.components.ExpandableView;
|
||||||
import com.topjohnwu.magisk.components.SnackbarMaker;
|
import com.topjohnwu.magisk.components.SnackbarMaker;
|
||||||
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
|
||||||
import com.topjohnwu.magisk.container.Policy;
|
import com.topjohnwu.magisk.container.Policy;
|
||||||
|
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -17,9 +17,9 @@ import com.topjohnwu.magisk.R;
|
|||||||
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
|
import com.topjohnwu.magisk.asyncs.MarkDownWindow;
|
||||||
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
|
import com.topjohnwu.magisk.asyncs.ProcessRepoZip;
|
||||||
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
import com.topjohnwu.magisk.components.AlertDialogBuilder;
|
||||||
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
|
||||||
import com.topjohnwu.magisk.container.Module;
|
import com.topjohnwu.magisk.container.Module;
|
||||||
import com.topjohnwu.magisk.container.Repo;
|
import com.topjohnwu.magisk.container.Repo;
|
||||||
|
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -12,8 +12,8 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.R;
|
import com.topjohnwu.magisk.R;
|
||||||
import com.topjohnwu.magisk.components.ExpandableView;
|
import com.topjohnwu.magisk.components.ExpandableView;
|
||||||
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
|
||||||
import com.topjohnwu.magisk.container.SuLogEntry;
|
import com.topjohnwu.magisk.container.SuLogEntry;
|
||||||
|
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
package com.topjohnwu.magisk.asyncs;
|
||||||
|
|
||||||
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.container.ByteArrayStream;
|
||||||
|
import com.topjohnwu.magisk.utils.WebService;
|
||||||
|
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
|
||||||
|
import dalvik.system.DexClassLoader;
|
||||||
|
|
||||||
|
public class CheckSafetyNet extends ParallelTask<Void, Void, Exception> {
|
||||||
|
|
||||||
|
public static final int SNET_VER = 1;
|
||||||
|
|
||||||
|
// Test URL, will switch to proper URL
|
||||||
|
private static final String SNET_URL = "https://www.dropbox.com/s/i5vvbl5eenmag5q/snet-release-unsigned.apk?dl=1";
|
||||||
|
private static final String PKG = "com.topjohnwu.snet";
|
||||||
|
|
||||||
|
private File dexPath;
|
||||||
|
private DexClassLoader loader;
|
||||||
|
|
||||||
|
public CheckSafetyNet(FragmentActivity activity) {
|
||||||
|
super(activity);
|
||||||
|
dexPath = new File(activity.getCacheDir().getParent() + "/snet", "snet.apk");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPreExecute() {
|
||||||
|
if (getMagiskManager().snet_version < CheckSafetyNet.SNET_VER) {
|
||||||
|
getShell().sh("rm -rf " + dexPath.getParent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Exception doInBackground(Void... voids) {
|
||||||
|
try {
|
||||||
|
if (!dexPath.exists()) {
|
||||||
|
HttpURLConnection conn = WebService.request(SNET_URL, null);
|
||||||
|
ByteArrayStream bas = new ByteArrayStream();
|
||||||
|
bas.readFrom(conn.getInputStream());
|
||||||
|
conn.disconnect();
|
||||||
|
dexPath.getParentFile().mkdir();
|
||||||
|
try (OutputStream out = new BufferedOutputStream(new FileOutputStream(dexPath))) {
|
||||||
|
bas.writeTo(out);
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loader = new DexClassLoader(dexPath.toString(), dexPath.getParent(),
|
||||||
|
null, ClassLoader.getSystemClassLoader());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(Exception err) {
|
||||||
|
try {
|
||||||
|
if (err != null) throw err;
|
||||||
|
Class<?> helperClazz = loader.loadClass(PKG + ".SafetyNetHelper");
|
||||||
|
Class<?> callbackClazz = loader.loadClass(PKG + ".SafetyNetCallback");
|
||||||
|
Object helper = helperClazz.getConstructors()[0].newInstance(
|
||||||
|
getActivity(), Proxy.newProxyInstance(
|
||||||
|
loader, new Class[] { callbackClazz }, (proxy, method, args) -> {
|
||||||
|
getMagiskManager().safetyNetDone.publish(false, args[0]);
|
||||||
|
return null;
|
||||||
|
}));
|
||||||
|
helperClazz.getMethod("requestTest").invoke(helper);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
getMagiskManager().safetyNetDone.publish(false, -1);
|
||||||
|
}
|
||||||
|
super.onPostExecute(err);
|
||||||
|
}
|
||||||
|
}
|
@ -8,8 +8,8 @@ import android.text.TextUtils;
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.container.AdaptiveList;
|
import com.topjohnwu.magisk.container.AdaptiveList;
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
|
||||||
import com.topjohnwu.magisk.container.TarEntry;
|
import com.topjohnwu.magisk.container.TarEntry;
|
||||||
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
import com.topjohnwu.magisk.utils.ZipUtils;
|
import com.topjohnwu.magisk.utils.ZipUtils;
|
||||||
|
|
||||||
|
@ -3,11 +3,10 @@ package com.topjohnwu.magisk.asyncs;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.container.BaseModule;
|
|
||||||
import com.topjohnwu.magisk.container.Module;
|
import com.topjohnwu.magisk.container.Module;
|
||||||
|
import com.topjohnwu.magisk.container.ValueSortedMap;
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
import com.topjohnwu.magisk.container.ValueSortedMap;
|
|
||||||
|
|
||||||
public class LoadModules extends ParallelTask<Void, Void, Void> {
|
public class LoadModules extends ParallelTask<Void, Void, Void> {
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import android.content.SharedPreferences;
|
|||||||
|
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.ReposFragment;
|
import com.topjohnwu.magisk.ReposFragment;
|
||||||
import com.topjohnwu.magisk.container.BaseModule;
|
|
||||||
import com.topjohnwu.magisk.container.Repo;
|
import com.topjohnwu.magisk.container.Repo;
|
||||||
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
import com.topjohnwu.magisk.database.RepoDatabaseHelper;
|
||||||
import com.topjohnwu.magisk.utils.WebService;
|
import com.topjohnwu.magisk.utils.WebService;
|
||||||
|
@ -5,8 +5,6 @@ import android.content.ContentValues;
|
|||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public abstract class BaseModule implements Comparable<BaseModule> {
|
public abstract class BaseModule implements Comparable<BaseModule> {
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
package com.topjohnwu.magisk.container;
|
package com.topjohnwu.magisk.container;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.topjohnwu.magisk.container;
|
package com.topjohnwu.magisk.container;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
|
||||||
import com.topjohnwu.magisk.utils.Shell;
|
import com.topjohnwu.magisk.utils.Shell;
|
||||||
import com.topjohnwu.magisk.utils.Utils;
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ package com.topjohnwu.magisk.container;
|
|||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.utils.Logger;
|
|
||||||
import com.topjohnwu.magisk.utils.WebService;
|
import com.topjohnwu.magisk.utils.WebService;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -4,7 +4,6 @@ import android.content.ContentValues;
|
|||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
|
||||||
import com.topjohnwu.magisk.MagiskManager;
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
import com.topjohnwu.magisk.container.Policy;
|
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
@ -1,114 +0,0 @@
|
|||||||
package com.topjohnwu.magisk.utils;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.v4.app.FragmentActivity;
|
|
||||||
import android.util.Base64;
|
|
||||||
|
|
||||||
import com.google.android.gms.common.ConnectionResult;
|
|
||||||
import com.google.android.gms.common.api.GoogleApiClient;
|
|
||||||
import com.google.android.gms.common.api.Status;
|
|
||||||
import com.google.android.gms.safetynet.SafetyNet;
|
|
||||||
import com.topjohnwu.magisk.R;
|
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
|
|
||||||
public abstract class SafetyNetHelper
|
|
||||||
implements GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
|
|
||||||
|
|
||||||
private static boolean isRunning = false;
|
|
||||||
|
|
||||||
private GoogleApiClient mGoogleApiClient;
|
|
||||||
private Result ret;
|
|
||||||
protected FragmentActivity mActivity;
|
|
||||||
|
|
||||||
public SafetyNetHelper(FragmentActivity activity) {
|
|
||||||
ret = new Result();
|
|
||||||
mActivity = activity;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entry point to start test
|
|
||||||
public void requestTest() {
|
|
||||||
if (isRunning)
|
|
||||||
return;
|
|
||||||
// Connect Google Service
|
|
||||||
mGoogleApiClient = new GoogleApiClient.Builder(mActivity)
|
|
||||||
.enableAutoManage(mActivity, this)
|
|
||||||
.addApi(SafetyNet.API)
|
|
||||||
.addConnectionCallbacks(this)
|
|
||||||
.build();
|
|
||||||
mGoogleApiClient.connect();
|
|
||||||
isRunning = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConnectionFailed(@NonNull ConnectionResult result) {
|
|
||||||
Logger.dev("SN: Google API fail");
|
|
||||||
ret.errmsg = result.getErrorMessage();
|
|
||||||
handleResults(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConnectionSuspended(int i) {
|
|
||||||
Logger.dev("SN: Google API Suspended");
|
|
||||||
switch (i) {
|
|
||||||
case CAUSE_NETWORK_LOST:
|
|
||||||
ret.errmsg = mActivity.getString(R.string.safetyNet_network_loss);
|
|
||||||
break;
|
|
||||||
case CAUSE_SERVICE_DISCONNECTED:
|
|
||||||
ret.errmsg = mActivity.getString(R.string.safetyNet_service_disconnected);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
handleResults(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConnected(@Nullable Bundle bundle) {
|
|
||||||
Logger.dev("SN: Google API Connected");
|
|
||||||
// Create nonce
|
|
||||||
byte[] nonce = new byte[24];
|
|
||||||
new SecureRandom().nextBytes(nonce);
|
|
||||||
|
|
||||||
Logger.dev("SN: Check with nonce: " + Base64.encodeToString(nonce, Base64.DEFAULT));
|
|
||||||
|
|
||||||
// Call SafetyNet
|
|
||||||
SafetyNet.SafetyNetApi.attest(mGoogleApiClient, nonce)
|
|
||||||
.setResultCallback(result -> {
|
|
||||||
Status status = result.getStatus();
|
|
||||||
if (status.isSuccess()) {
|
|
||||||
String json = new String(Base64.decode(result.getJwsResult().split("\\.")[1], Base64.DEFAULT));
|
|
||||||
Logger.dev("SN: Response: " + json);
|
|
||||||
try {
|
|
||||||
JSONObject decoded = new JSONObject(json);
|
|
||||||
ret.ctsProfile = decoded.getBoolean("ctsProfileMatch");
|
|
||||||
ret.basicIntegrity = decoded.getBoolean("basicIntegrity");
|
|
||||||
ret.failed = false;
|
|
||||||
} catch (JSONException e) {
|
|
||||||
ret.errmsg = mActivity.getString(R.string.safetyNet_res_invalid);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Logger.dev("SN: No response");
|
|
||||||
ret.errmsg = mActivity.getString(R.string.safetyNet_no_response);
|
|
||||||
}
|
|
||||||
// Disconnect
|
|
||||||
mGoogleApiClient.stopAutoManage(mActivity);
|
|
||||||
mGoogleApiClient.disconnect();
|
|
||||||
isRunning = false;
|
|
||||||
handleResults(ret);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Callback function to save the results
|
|
||||||
public abstract void handleResults(Result result);
|
|
||||||
|
|
||||||
public static class Result {
|
|
||||||
public boolean failed = true;
|
|
||||||
public String errmsg;
|
|
||||||
public boolean ctsProfile = false;
|
|
||||||
public boolean basicIntegrity = false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -31,15 +31,19 @@ public class Topic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void publish() {
|
public void publish() {
|
||||||
publish(true);
|
publish(true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void publish(boolean record) {
|
public void publish(boolean record) {
|
||||||
|
publish(record, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void publish(boolean record, Object result) {
|
||||||
hasPublished = record;
|
hasPublished = record;
|
||||||
if (subscribers != null) {
|
if (subscribers != null) {
|
||||||
for (WeakReference<Subscriber> subscriber : subscribers) {
|
for (WeakReference<Subscriber> subscriber : subscribers) {
|
||||||
if (subscriber.get() != null)
|
if (subscriber.get() != null)
|
||||||
subscriber.get().onTopicPublished(this);
|
subscriber.get().onTopicPublished(this, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,9 +64,12 @@ public class Topic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
default void onTopicPublished() {
|
default void onTopicPublished() {
|
||||||
onTopicPublished(null);
|
onTopicPublished(null, null);
|
||||||
}
|
}
|
||||||
void onTopicPublished(Topic topic);
|
default void onTopicPublished(Topic topic) {
|
||||||
|
onTopicPublished(topic, null);
|
||||||
|
}
|
||||||
|
void onTopicPublished(Topic topic, Object result);
|
||||||
Topic[] getSubscription();
|
Topic[] getSubscription();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@ import android.provider.OpenableColumns;
|
|||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.support.design.widget.Snackbar;
|
import android.support.design.widget.Snackbar;
|
||||||
import android.support.v4.app.ActivityCompat;
|
import android.support.v4.app.ActivityCompat;
|
||||||
import android.support.v4.app.FragmentActivity;
|
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
import android.support.v4.app.TaskStackBuilder;
|
import android.support.v4.app.TaskStackBuilder;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
@ -150,16 +149,6 @@ public class Utils {
|
|||||||
return (MagiskManager) context.getApplicationContext();
|
return (MagiskManager) context.getApplicationContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void checkSafetyNet(FragmentActivity activity) {
|
|
||||||
new SafetyNetHelper(activity) {
|
|
||||||
@Override
|
|
||||||
public void handleResults(Result result) {
|
|
||||||
getMagiskManager(mActivity).SNCheckResult = result;
|
|
||||||
getMagiskManager(mActivity).safetyNetDone.publish(false);
|
|
||||||
}
|
|
||||||
}.requestTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void clearRepoCache(Context context) {
|
public static void clearRepoCache(Context context) {
|
||||||
MagiskManager mm = getMagiskManager(context);
|
MagiskManager mm = getMagiskManager(context);
|
||||||
mm.prefs.edit().remove(UpdateRepos.ETAG_KEY).apply();
|
mm.prefs.edit().remove(UpdateRepos.ETAG_KEY).apply();
|
||||||
|
@ -22,7 +22,8 @@
|
|||||||
<string name="not_rooted">Not rooted</string>
|
<string name="not_rooted">Not rooted</string>
|
||||||
<string name="safetyNet_check_text">Tap to start SafetyNet check</string>
|
<string name="safetyNet_check_text">Tap to start SafetyNet check</string>
|
||||||
<string name="checking_safetyNet_status">Checking SafetyNet status…</string>
|
<string name="checking_safetyNet_status">Checking SafetyNet status…</string>
|
||||||
<string name="safetyNet_check_success">SafetyNet Check Was Successful</string>
|
<string name="safetyNet_check_success">SafetyNet Check Success</string>
|
||||||
|
<string name="safetyNet_api_error">SafetyNet API Error</string>
|
||||||
<string name="safetyNet_no_response">Cannot verify SafetyNet, no internet?</string>
|
<string name="safetyNet_no_response">Cannot verify SafetyNet, no internet?</string>
|
||||||
<string name="safetyNet_network_loss">Network connection unavailable</string>
|
<string name="safetyNet_network_loss">Network connection unavailable</string>
|
||||||
<string name="safetyNet_service_disconnected">Service has been killed</string>
|
<string name="safetyNet_service_disconnected">Service has been killed</string>
|
||||||
@ -123,6 +124,8 @@
|
|||||||
<string name="restore_done">Restoration done!</string>
|
<string name="restore_done">Restoration done!</string>
|
||||||
<string name="restore_fail">Stock backup does not exist!</string>
|
<string name="restore_fail">Stock backup does not exist!</string>
|
||||||
<string name="uninstall_toast">Uninstalling Magisk Manager in 5 seconds, please manually reboot afterwards</string>
|
<string name="uninstall_toast">Uninstalling Magisk Manager in 5 seconds, please manually reboot afterwards</string>
|
||||||
|
<string name="proprietary_title">Download Proprietary Code</string>
|
||||||
|
<string name="proprietary_notice">Magisk Manager is FOSS so doesn\'t contain Google\'s proprietary SafetyNet API code.\n\nDo you allow Magisk Manager to download an extension (contains GoogleApiClient) for SafetyNet checks?</string>
|
||||||
|
|
||||||
<!--Settings Activity -->
|
<!--Settings Activity -->
|
||||||
<string name="settings_general_category">General</string>
|
<string name="settings_general_category">General</string>
|
||||||
|
@ -5,6 +5,7 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven { url "https://maven.google.com" }
|
maven { url "https://maven.google.com" }
|
||||||
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.0.0-beta7'
|
classpath 'com.android.tools.build:gradle:3.0.0-beta7'
|
||||||
@ -18,6 +19,7 @@ allprojects {
|
|||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
maven { url "https://jitpack.io" }
|
maven { url "https://jitpack.io" }
|
||||||
|
google()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
include ':app', ':unhide', ':resource'
|
include ':app', ':unhide', ':resource', ':snet'
|
1
snet/.gitignore
vendored
Normal file
1
snet/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build
|
27
snet/build.gradle
Normal file
27
snet/build.gradle
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 26
|
||||||
|
buildToolsVersion "26.0.2"
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "com.topjohnwu.sn"
|
||||||
|
minSdkVersion 21
|
||||||
|
targetSdkVersion 26
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled true
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
implementation 'com.google.android.gms:play-services-safetynet:11.4.2'
|
||||||
|
}
|
24
snet/proguard-rules.pro
vendored
Normal file
24
snet/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
||||||
|
|
||||||
|
-keep class com.topjohnwu.snet.SafetyNet* { *; }
|
||||||
|
-dontwarn java.lang.invoke**
|
7
snet/src/main/AndroidManifest.xml
Normal file
7
snet/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.topjohnwu.snet">
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="com.google.android.gms.version"
|
||||||
|
android:value="@integer/google_play_services_version" />
|
||||||
|
</manifest>
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.topjohnwu.snet;
|
||||||
|
|
||||||
|
public interface SafetyNetCallback {
|
||||||
|
void onResponse(int responseCode);
|
||||||
|
}
|
118
snet/src/main/java/com/topjohnwu/snet/SafetyNetHelper.java
Normal file
118
snet/src/main/java/com/topjohnwu/snet/SafetyNetHelper.java
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
package com.topjohnwu.snet;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.util.Base64;
|
||||||
|
|
||||||
|
import com.google.android.gms.common.ConnectionResult;
|
||||||
|
import com.google.android.gms.common.api.GoogleApiClient;
|
||||||
|
import com.google.android.gms.common.api.ResultCallback;
|
||||||
|
import com.google.android.gms.common.api.Status;
|
||||||
|
import com.google.android.gms.safetynet.SafetyNet;
|
||||||
|
import com.google.android.gms.safetynet.SafetyNetApi;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
|
public class SafetyNetHelper
|
||||||
|
implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
||||||
|
|
||||||
|
public static final int CONNECTION_FAIL = -1;
|
||||||
|
|
||||||
|
public static final int CAUSE_SERVICE_DISCONNECTED = 0x00001;
|
||||||
|
public static final int CAUSE_NETWORK_LOST = 0x00010;
|
||||||
|
public static final int RESPONSE_ERR = 0x00100;
|
||||||
|
|
||||||
|
public static final int BASIC_PASS = 0x01000;
|
||||||
|
public static final int CTS_PASS = 0x10000;
|
||||||
|
|
||||||
|
private GoogleApiClient mGoogleApiClient;
|
||||||
|
private Context mActivity;
|
||||||
|
private int responseCode;
|
||||||
|
private SafetyNetCallback cb;
|
||||||
|
|
||||||
|
public SafetyNetHelper(Context context, SafetyNetCallback cb) {
|
||||||
|
mActivity = context;
|
||||||
|
this.cb = cb;
|
||||||
|
responseCode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entry point to start test
|
||||||
|
public void requestTest() {
|
||||||
|
// Connect Google Service
|
||||||
|
GoogleApiClient.Builder builder = new GoogleApiClient.Builder(mActivity);
|
||||||
|
try {
|
||||||
|
// Use reflection to workaround FragmentActivity crap
|
||||||
|
Class<?> clazz = Class.forName("com.google.android.gms.common.api.GoogleApiClient$Builder");
|
||||||
|
for (Method m : clazz.getMethods()) {
|
||||||
|
if (m.getName().equals("enableAutoManage")) {
|
||||||
|
m.invoke(builder, mActivity, this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
mGoogleApiClient = builder.addApi(SafetyNet.API).addConnectionCallbacks(this).build();
|
||||||
|
mGoogleApiClient.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectionSuspended(int i) {
|
||||||
|
cb.onResponse(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
|
||||||
|
cb.onResponse(CONNECTION_FAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConnected(@Nullable Bundle bundle) {
|
||||||
|
// Create nonce
|
||||||
|
byte[] nonce = new byte[24];
|
||||||
|
new SecureRandom().nextBytes(nonce);
|
||||||
|
|
||||||
|
// Call SafetyNet
|
||||||
|
SafetyNet.SafetyNetApi.attest(mGoogleApiClient, nonce)
|
||||||
|
.setResultCallback(new ResultCallback<SafetyNetApi.AttestationResult>() {
|
||||||
|
@Override
|
||||||
|
public void onResult(@NonNull SafetyNetApi.AttestationResult result) {
|
||||||
|
Status status = result.getStatus();
|
||||||
|
try {
|
||||||
|
if (!status.isSuccess()) throw new JSONException("");
|
||||||
|
String json = new String(Base64.decode(
|
||||||
|
result.getJwsResult().split("\\.")[1], Base64.DEFAULT));
|
||||||
|
JSONObject decoded = new JSONObject(json);
|
||||||
|
responseCode |= decoded.getBoolean("ctsProfileMatch") ? CTS_PASS : 0;
|
||||||
|
responseCode |= decoded.getBoolean("basicIntegrity") ? BASIC_PASS : 0;
|
||||||
|
} catch (JSONException e) {
|
||||||
|
responseCode |= RESPONSE_ERR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Disconnect
|
||||||
|
try {
|
||||||
|
// Use reflection to workaround FragmentActivity crap
|
||||||
|
Class<?> clazz = Class.forName("com.google.android.gms.common.api.GoogleApiClient");
|
||||||
|
for (Method m : clazz.getMethods()) {
|
||||||
|
if (m.getName().equals("stopAutoManage")) {
|
||||||
|
m.invoke(mGoogleApiClient, mActivity, this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
mGoogleApiClient.disconnect();
|
||||||
|
|
||||||
|
// Return results
|
||||||
|
cb.onResponse(responseCode);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user