fix: 增加作弊检查

This commit is contained in:
xiaoyan 2022-08-25 13:52:57 +08:00
parent 02215187e7
commit ea4b004637
8 changed files with 435 additions and 14 deletions

View File

@ -143,5 +143,7 @@ dependencies {
implementation 'com.github.Hu12037102:ImageCompress:2.3.0'
//webp
implementation 'com.wanghong.webpnative:webpnative:0.1.0'
// https://github.com/teprinciple/MailSender
implementation 'com.teprinciple:mailsender:1.2.0'
}

View File

@ -1,6 +1,8 @@
package com.navinfo.outdoor.activity;
import com.github.lazylibrary.util.ShellUtils;
import com.google.gson.Gson;
import com.hjq.permissions.XXPermissions;
import com.kongzue.dialog.interfaces.OnDialogButtonClickListener;
import com.kongzue.dialog.util.BaseDialog;
import com.kongzue.dialog.util.DialogSettings;
@ -26,9 +28,13 @@ import androidx.viewpager.widget.ViewPager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
@ -36,6 +42,8 @@ import android.widget.Toast;
import com.navinfo.outdoor.R;
import com.google.android.material.tabs.TabLayout;
import com.gyf.immersionbar.ImmersionBar;
import com.teprinciple.mailsender.Mail;
import com.teprinciple.mailsender.MailSender;
import com.umeng.message.PushAgent;
import com.umeng.message.UmengNotificationClickHandler;
import com.umeng.message.entity.UMessage;
@ -44,10 +52,23 @@ import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
/**
* 首页
* tabLayout + viewPager
@ -62,6 +83,8 @@ public class HomeActivity extends BaseActivity {
public boolean handleMessage(@NonNull Message msg) {
if (msg.what == 0x100) {
isBack = false;
} else if (msg.what == 0x101) {
checkMockLocation();
}
return false;
}
@ -77,6 +100,9 @@ public class HomeActivity extends BaseActivity {
super.onCreate(savedInstanceState);
if (Constant.USHERED != null) {
Constant.initRootFolder(Constant.USHERED);
// 检测用户是否为虚拟定位
boolean result = handler.sendEmptyMessageDelayed(0x101, 1000*60*(int)(10*Math.random()));
Log.d("HomeActivity", "作弊检查:"+result);
} else {
finish();
}
@ -94,6 +120,7 @@ public class HomeActivity extends BaseActivity {
protected void onResume() {
super.onResume();
initUM();
// Toast.makeText(this, "作弊检查:"+result, Toast.LENGTH_SHORT).show();
}
private void initUM() {
@ -269,6 +296,213 @@ public class HomeActivity extends BaseActivity {
}
}
/**
* 检查是否为模拟定位
* */
private void checkMockLocation() {
Log.d("HomeActivity", "checkMockLocation开始");
Observable.create(new ObservableOnSubscribe<Map<String, Boolean>>() {
@Override
public void subscribe(ObservableEmitter<Map<String, Boolean>> emitter) throws Exception {
emitter.onNext(new HashMap<>());
emitter.onComplete();
}
}).subscribeOn(AndroidSchedulers.mainThread())
.observeOn(Schedulers.computation())
.doOnNext(new Consumer<Map<String, Boolean>>() {
@Override
public void accept(Map<String, Boolean> stringBooleanMap) throws Exception {
if (isInstallVirtual(HomeActivity.this)) {
stringBooleanMap.put("安装有虚拟定位软件", true);
}else {
Log.d("HomeActivity", "不安装有虚拟定位软件:");
}
}
}).doOnNext(new Consumer<Map<String, Boolean>>() {
@Override
public void accept(Map<String, Boolean> stringBooleanMap) throws Exception {
if (isOpenMockLocationSetting()) {
stringBooleanMap.put("打开了虚拟定位设置", true);
}else {
Log.d("HomeActivity", "不打开了虚拟定位设置:");
}
}
}).doOnNext(new Consumer<Map<String, Boolean>>() {
@Override
public void accept(Map<String, Boolean> stringBooleanMap) throws Exception {
if (isRunInVirtual()) {
stringBooleanMap.put("程序运行在虚拟环境中", true);
}else {
Log.d("HomeActivity", "不程序运行在虚拟环境中:");
}
}
}).doOnNext(new Consumer<Map<String, Boolean>>() {
@Override
public void accept(Map<String, Boolean> stringBooleanMap) throws Exception {
if (checkPkg(HomeActivity.this)) {
stringBooleanMap.put("存在应用双开", true);
} else {
Log.d("HomeActivity", "不存在应用双开:");
}
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Map<String, Boolean>>() {
@Override
public void accept(Map<String, Boolean> stringBooleanMap) throws Exception {
Log.d("HomeActivity", "checkMockLocation结果"+stringBooleanMap.isEmpty());
if (!stringBooleanMap.isEmpty()) {
StringBuilder stringBuilder = new StringBuilder("检查到您疑似存在以下违规行为:\n");
for (String key: stringBooleanMap.keySet()
) {
stringBuilder.append(key).append("\n");
}
stringBuilder.append("请及时修正,否则可能会影响到您的收益,如有疑问可联系管理员!");
DialogSettings.style = DialogSettings.STYLE.STYLE_IOS;
DialogSettings.cancelable = false;
MessageDialog.show(HomeActivity.this, "提示", stringBuilder, "确定").setOkButton(new OnDialogButtonClickListener() {
@Override
public boolean onClick(BaseDialog baseDialog, View v) {
// 将违规行为通知给运营人员
// 创建邮箱
Mail mail = new Mail();
mail.setMailServerHost("smtp.163.com");
mail.setMailServerPort("25");
mail.setFromAddress("xiaoyan159@163.com");
mail.setPassword("YGPSXLMRPMADRHPS");
ArrayList<String> toAddressList = new ArrayList<>();
toAddressList.add("xiaoyan159@qq.com");
mail.setToAddress(toAddressList);
mail.setSubject("疑似违规记录");
mail.setContent(stringBuilder.append("用户名:").append(Constant.USER_NAME).append("\n")
.append("身份证号:").append(Constant.ID_NUMBER).append("\n")
.append("姓名:").append(Constant.NAME).append("\n")
.append("手机号:").append(Constant.MOBILE).toString());
// mail.attachFiles = arrayListOf(file);
// 发送邮箱
MailSender.getInstance().sendMail(mail, new MailSender.OnMailSendListener() {
@Override
public void onSuccess() {
// 发送成功无需再报告
}
@Override
public void onError(@NonNull Throwable throwable) {
handler.sendEmptyMessageDelayed(0x101, 1000*60*(int)(10*Math.random()));
}
});
baseDialog.doDismiss();
return false;
}
});
} else {
handler.sendEmptyMessageDelayed(0x101, 1000*60*(int)(10*Math.random()));
}
}
});
}
private boolean isInstallVirtual(Context context) {
Map<String, String> packageNames = getVirtualPackageNames();
PackageManager packageManager = context.getPackageManager();
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);
for (int i = 0; i < pinfo.size(); i++) {
if (packageNames.get(pinfo.get(i).packageName) != null) {
return true;
}
}
return false;
}
private Map<String, String> getVirtualPackageNames() {
Map<String, String> packageNames = new HashMap<>();
packageNames.put("com.lerist.fakelocation", "com.lerist.fakelocation");// Fake-location虚拟定位
packageNames.put("top.a1024bytes.mockloc.ca.pro", "top.a1024bytes.mockloc.ca.pro");// 天下任我行
packageNames.put("com.qgwapp.shadowside", "com.qgwapp.shadowside");// 任我行免ROOT
packageNames.put("net.superal", "net.superal");// 超级神行者
packageNames.put("com.deniu.daniu", "com.deniu.daniu");// 大牛
packageNames.put("com.deniu.multi", "com.deniu.multi");// 大牛助手
packageNames.put("com.txy.anywhere", "com.txy.anywhere");// 天下游
packageNames.put("de.robv.android.xposed.installer", "de.robv.android.xposed.installer");// Xposed
packageNames.put("github.tornaco.xposedmoduletest", "github.tornaco.xposedmoduletest");// 应用管理Xposed
return packageNames;
}
/**
* 是否开启虚拟定位设置
* */
private boolean isOpenMockLocationSetting() {
return Settings.Secure.getInt(getContentResolver(),Settings.Secure.ALLOW_MOCK_LOCATION, 0) != 0;
}
private boolean isRunInVirtual() {
// 获取当前应用的uid
String filter = getUid(this);
ShellUtils.CommandResult commandResult = ShellUtils.execCommand("ps", false);
Log.d("HomeActivity: commandResult", commandResult.errorMsg+":::"+commandResult.successMsg+":::"+commandResult.result);
if (commandResult==null&&commandResult.successMsg==null) {
return false;
}
String result = commandResult.successMsg;
if (result == null || result.isEmpty()) {
return false;
}
String[] lines = result.split("\n");
if (lines == null || lines.length <= 0) {
return false;
}
int exitDirCount = 0;
for (int i = 0; i < lines.length; i++) {
if (lines[i].contains(filter)) {
int pkgStartIndex = lines[i].lastIndexOf(" ");
String processName = lines[i].substring(pkgStartIndex <= 0
? 0 : pkgStartIndex + 1, lines[i].length());
File dataFile = new File(String.format("/data/data/%s",
processName, Locale.CHINA));
if (dataFile.exists()) {
exitDirCount++;
}
}
}
return exitDirCount > 1;
}
/**
* 应用列表检查防止应用多开
* */
private boolean checkPkg(Context context) {
try {
if (context == null) {
return false;
}
int count = 0;
String packageName = context.getPackageName();
PackageManager pm = context.getPackageManager();
List<PackageInfo> pkgs = pm.getInstalledPackages(0);
for (PackageInfo info : pkgs) {
if (packageName.equals(info.packageName)) {
count++;
}
}
return count > 1;
} catch (Exception ignore) {}
return false;
}
private String getUid(Context context) {
String uid = "";
try {
PackageManager pm = context.getPackageManager();
ApplicationInfo ai = pm.getApplicationInfo("com.navinfo.outdoor", PackageManager.GET_META_DATA);
uid = String.valueOf(ai.uid);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return uid;
}
@Override
public void onBackPressed() {
if (!BackHandlerHelper.handleBackPress(this)) {

View File

@ -1,10 +1,12 @@
package com.navinfo.outdoor.activity;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.CountDownTimer;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
@ -23,6 +25,8 @@ import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.kongzue.dialog.interfaces.OnDialogButtonClickListener;
import com.kongzue.dialog.util.BaseDialog;
import com.kongzue.dialog.util.DialogSettings;
import com.kongzue.dialog.v3.CustomDialog;
import com.kongzue.dialog.v3.MessageDialog;
import com.lzy.okgo.model.HttpParams;
import com.lzy.okgo.model.Progress;
@ -31,6 +35,7 @@ import com.navinfo.outdoor.api.Constant;
import com.navinfo.outdoor.base.BaseActivity;
import com.navinfo.outdoor.bean.CityBean;
import com.navinfo.outdoor.bean.JsonBean;
import com.navinfo.outdoor.bean.MessageCodeBean;
import com.navinfo.outdoor.bean.UserBean;
import com.navinfo.outdoor.http.Callback;
import com.navinfo.outdoor.http.HttpInterface;
@ -68,6 +73,9 @@ public class UserActivity extends BaseActivity implements View.OnClickListener {
private StringBuilder userBuilder;
private String region_text;
private SharedPreferences spNavinfo;
private Button btnPhoneEdit;
private String sessionId;
private CountDownTimer timer;
@Override
protected int getLayout() {
@ -124,6 +132,8 @@ public class UserActivity extends BaseActivity implements View.OnClickListener {
etPhone = findViewById(R.id.et_phone);
etPhone.setEnabled(false);
etPhone.setOnClickListener(this);
btnPhoneEdit = findViewById(R.id.btn_phone_edit);
btnPhoneEdit.setOnClickListener(this);
etQq = findViewById(R.id.edit_qq);
etQq.setOnClickListener(this);
etMailbox = findViewById(R.id.edit_mailbox);
@ -204,9 +214,107 @@ public class UserActivity extends BaseActivity implements View.OnClickListener {
userBuilder.append(TimestampUtil.time()).append(",").append("点击了微信 去提交的按钮 ,");
ToastUtils.Message(UserActivity.this,"此功能未开通");
break;
case R.id.btn_phone_edit:
// 用户修改手机号
DialogSettings.style = DialogSettings.STYLE.STYLE_IOS;
DialogSettings.cancelable = false;
CustomDialog.show(UserActivity.this, R.layout.edit_phone, new CustomDialog.OnBindView() {
@Override
public void onBind(CustomDialog dialog, View v) {
EditText edtPhoneNew = v.findViewById(R.id.edt_phone_new);
EditText edtConfirmCode = v.findViewById(R.id.edt_phone_confirm_code);
TextView btnConfirmCode = v.findViewById(R.id.tv_confirm_code);
Button btnFinish = v.findViewById(R.id.btm_finish);
btnConfirmCode.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String newPhone=edtPhoneNew.getText().toString();
if (newPhone.length()!=11 || !newPhone.startsWith("1")) {
Toast.makeText(UserActivity.this, "请检查手机号是否正确!", Toast.LENGTH_SHORT).show();
return;
}
if (newPhone.equals(Constant.MOBILE)) {
Toast.makeText(UserActivity.this, "与原有手机号相同!", Toast.LENGTH_SHORT).show();
return;
}
// 发送请求拉取新的验证码
getConfirmCode(UserActivity.this, newPhone, btnConfirmCode);
}
});
btnFinish.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 发送修改手机号请求
}
});
}
});
break;
}
}
private void getConfirmCode(Activity context, String phone, TextView btnPhoneConfirmCode) {
HttpParams httpParams = new HttpParams();
httpParams.put("mobile", phone);
httpParams.put("type", 3);
showLoadingDialog();
OkGoBuilder okGoBuilder = OkGoBuilder.getInstance()
.time(30)
.Builder(context)
.url(HttpInterface.USER_MESSAGE)
.cls(MessageCodeBean.class)
.token(null)
.params(httpParams);
okGoBuilder.getRequest(new Callback<MessageCodeBean>() {
@Override
public void onSuccess(MessageCodeBean response, int id) {
dismissLoadingDialog();
if (response.getCode() == 200) {
sessionId = response.getBody();
registerNote(btnPhoneConfirmCode);
ToastUtils.Message(context, "验证码已发送");
} else {
ToastUtils.Message(context, response.getMessage());
}
}
@Override
public void onError(Throwable e, int id) {
dismissLoadingDialog();
String message = e.getMessage();
assert message != null;
if (message.equals("timeout") || message.equals("Read time out")) {
ToastUtils.Message(context, "请求超时");
} else {
ToastUtils.Message(context, message);
}
}
});
}
private void registerNote(TextView btnConfirm) {
if (timer != null) {
timer.cancel();
timer = null;
}
btnConfirm.setEnabled(false);
timer = new CountDownTimer(60 * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
btnConfirm.setText(millisUntilFinished / 1000 + "秒后重新获取验证码");
}
@Override
public void onFinish() {
btnConfirm.setEnabled(true);
btnConfirm.setText("重新获取");
}
};
timer.start();
}
private void netWork() {
userBuilder.append(TimestampUtil.time()).append(",").append("点击了保存的按钮 ,");
String userphone = etPhone.getText().toString().trim();

View File

@ -1500,7 +1500,7 @@ public class ChargingStationFragment extends BaseDrawerFragment implements View.
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
ToastUtils.Message(getActivity(), taskNameBean.getMessage());
ToastUtils.Message(getActivity(), taskNameBean.getMessage()+"");
editNameContent.setTextColor(Color.RED);
btnSaveLocal.setEnabled(false);
btnUploading.setEnabled(false);

View File

@ -64,7 +64,7 @@ public class HttpInterface {
///m4/user/user/register
public static String USER_REGISTER = IP + USER_PATH + "user/register";//注册接口
///m4/user/ phone/message
public static String USER_MESSAGE = IP + USER_PATH + "phone/message";//获取验证码 type 1注册获取 2更新
public static String USER_MESSAGE = IP + USER_PATH + "phone/message";//获取验证码 type 1注册获取 2更新 3: 修改手机号
///m4/user/user/forgetPassword
public static String USER_FORGET_PASSWORD = IP + USER_PATH + "user/forgetPassword";//忘记密码

View File

@ -438,8 +438,8 @@ public class PoiSaveUtils {
if (execute.code() != 200) {
return execute.code();
}
if (execute.body().string() != null) {
String string = execute.body().string();
String string = execute.body().string();
if (string != null) {
Gson gson = new Gson();
ChargingPileSaveBean chargingPileSaveBean = gson.fromJson(string, ChargingPileSaveBean.class);
if (chargingPileSaveBean.getCode() != 200) {

View File

@ -67,6 +67,7 @@
android:layout_marginStart="20dp"
android:layout_centerVertical="true"
style="@style/user_text_style" />
<Button
android:id="@+id/btn_attestations"
style="@style/user_style"
@ -153,24 +154,35 @@
<TextView
android:id="@+id/tv_number"
style="@style/user_text_style"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:text="手机号码*"
android:layout_centerVertical="true"
android:layout_marginStart="20dp"
style="@style/user_text_style"
/>
android:text="手机号码*" />
<Button
android:id="@+id/btn_phone_edit"
style="@style/user_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="10dp"
android:text="修改"
android:textColor="#fff" />
<EditText
android:id="@+id/et_phone"
android:layout_toEndOf="@id/tv_number"
android:layout_width="match_parent"
style="@style/user_hint_style"
android:digits="1234567890"
android:maxLength="11"
android:layout_centerVertical="true"
android:hint="请输入手机号码"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
android:layout_centerVertical="true"
android:layout_toLeftOf="@id/btn_phone_edit"
android:layout_toRightOf="@id/tv_number"
android:digits="1234567890"
android:hint="请输入手机号码"
android:maxLength="11" />
</RelativeLayout>
<View

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/default_widget_padding"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/edit_phone_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
android:gravity="center"
style="@style/text_style_title"
android:text="修改手机号"></TextView>
<EditText
android:id="@+id/edt_phone_new"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入新手机号"
android:maxLength="11"
android:digits="0123456789"
app:layout_constraintTop_toBottomOf="@id/edit_phone_title"
style="@style/MyEditText"></EditText>
<RelativeLayout
android:id="@+id/layer_confirm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/default_widget_padding"
app:layout_constraintTop_toBottomOf="@id/edt_phone_new"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_confirm_code"
style="@style/user_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="10dp"
android:text="获取验证码"
android:textColor="#fff" />
<EditText
android:id="@+id/edt_phone_confirm_code"
style="@style/MyEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/tv_confirm_code"
android:layout_toLeftOf="@id/tv_confirm_code"
android:digits="0123456789"
android:hint="请输入验证码"
android:maxLength="11"></EditText>
</RelativeLayout>
<Button
android:id="@+id/btm_finish"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/default_widget_padding"
app:layout_constraintTop_toBottomOf="@id/layer_confirm"
android:textColor="@color/white"
style="@style/user_style"
android:text="确认修改"></Button>
</androidx.constraintlayout.widget.ConstraintLayout>