Parcourir la source

Merge branch 'feature/android_password_encrypt' into 'develop'

android v5.2.0版本

See merge request o2oa/o2oa!1764
楼国栋 il y a 5 ans
Parent
commit
5e5d74cde5
28 fichiers modifiés avec 885 ajouts et 48 suppressions
  1. 2 1
      o2android/app/src/main/AndroidManifest.xml
  2. 2 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/base/BaseMVPActivity.kt
  3. 2 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/base/BaseO2Activity.kt
  4. 2 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/base/BaseO2BindActivity.kt
  5. 3 1
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2InstantMessageActivity.kt
  6. 17 13
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/launch/LaunchActivity.kt
  7. 149 16
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/login/LoginActivity.kt
  8. 26 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/login/LoginContract.kt
  9. 85 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/login/LoginPresenter.kt
  10. 2 1
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/IndexFragment.kt
  11. 4 1
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/IndexPortalFragment.kt
  12. 8 8
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/MyAppPresenter.kt
  13. 1 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/security/AccountSecurityActivity.kt
  14. 5 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/security/AccountSecurityContract.kt
  15. 42 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/security/AccountSecurityPresenter.kt
  16. 151 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/AntiHijackingUtil.java
  17. 200 0
      o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/CheckRoot.java
  18. 41 0
      o2android/app/src/main/res/layout/activity_login.xml
  19. 4 0
      o2android/app/src/main/res/values/strings.xml
  20. 2 2
      o2android/gradle.properties
  21. 30 3
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/OrgAssembleAuthenticationService.kt
  22. 1 1
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/OrgAssemblePersonalService.kt
  23. 12 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/CaptchaImgData.kt
  24. 14 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/LoginModeData.kt
  25. 14 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/LoginWithCaptchaForm.kt
  26. 11 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/RSAPublicKeyData.kt
  27. 2 1
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/main/person/PersonPwdForm.kt
  28. 53 0
      o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/CryptRSA.java

+ 2 - 1
o2android/app/src/main/AndroidManifest.xml

@@ -36,7 +36,8 @@
 
 
     <application
     <application
         android:name=".O2App"
         android:name=".O2App"
-        android:allowBackup="true"
+        android:allowBackup="false"
+        tools:replace="android:allowBackup"
         android:hardwareAccelerated="true"
         android:hardwareAccelerated="true"
         android:icon="@mipmap/logo"
         android:icon="@mipmap/logo"
         android:label="@string/app_name"
         android:label="@string/app_name"

+ 2 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/base/BaseMVPActivity.kt

@@ -2,6 +2,7 @@ package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base
 
 
 import android.content.Context
 import android.content.Context
 import android.os.Bundle
 import android.os.Bundle
+import android.view.WindowManager
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.widget.Toolbar
 import androidx.appcompat.widget.Toolbar
 import android.widget.TextView
 import android.widget.TextView
@@ -50,6 +51,7 @@ abstract class BaseMVPActivity<in V: BaseView, T: BasePresenter<V>>: AppCompatAc
         super.onCreate(savedInstanceState)
         super.onCreate(savedInstanceState)
         beforeSetContentView()
         beforeSetContentView()
         setContentView(layoutResId())
         setContentView(layoutResId())
+        window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
         // 沉浸式状态栏
         // 沉浸式状态栏
         ImmersedStatusBarUtils.setImmersedStatusBar(this)
         ImmersedStatusBarUtils.setImmersedStatusBar(this)
 
 

+ 2 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/base/BaseO2Activity.kt

@@ -1,6 +1,7 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base
 
 
 import android.os.Bundle
 import android.os.Bundle
+import android.view.WindowManager
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.widget.Toolbar
 import androidx.appcompat.widget.Toolbar
 import android.widget.TextView
 import android.widget.TextView
@@ -37,6 +38,7 @@ abstract class BaseO2Activity : AppCompatActivity() {
         super.onCreate(savedInstanceState)
         super.onCreate(savedInstanceState)
         beforeSetContentView()
         beforeSetContentView()
         setContentView(layoutResId())
         setContentView(layoutResId())
+        window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
         // 沉浸式状态栏
         // 沉浸式状态栏
         ImmersedStatusBarUtils.setImmersedStatusBar(this)
         ImmersedStatusBarUtils.setImmersedStatusBar(this)
         afterSetContentView(savedInstanceState)
         afterSetContentView(savedInstanceState)

+ 2 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/base/BaseO2BindActivity.kt

@@ -1,6 +1,7 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base
 
 
 import android.os.Bundle
 import android.os.Bundle
+import android.view.WindowManager
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.widget.Toolbar
 import androidx.appcompat.widget.Toolbar
 import android.widget.TextView
 import android.widget.TextView
@@ -37,6 +38,7 @@ abstract class BaseO2BindActivity : AppCompatActivity() {
         super.onCreate(savedInstanceState)
         super.onCreate(savedInstanceState)
         beforeSetContentView()
         beforeSetContentView()
         bindView(savedInstanceState)
         bindView(savedInstanceState)
+        window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
         // 沉浸式状态栏
         // 沉浸式状态栏
         ImmersedStatusBarUtils.setImmersedStatusBar(this)
         ImmersedStatusBarUtils.setImmersedStatusBar(this)
         afterSetContentView(savedInstanceState)
         afterSetContentView(savedInstanceState)

+ 3 - 1
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/im/O2InstantMessageActivity.kt

@@ -16,6 +16,7 @@ import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseMVPActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.bbs.main.BBSMainActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.bbs.main.BBSMainActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.calendar.CalendarMainActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.calendar.CalendarMainActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.clouddrive.CloudDriveActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.clouddrive.CloudDriveActivity
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.clouddrive.v2.CloudDiskActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.cms.index.CMSIndexActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.cms.index.CMSIndexActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.meeting.main.MeetingMainActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.meeting.main.MeetingMainActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.webview.TaskWebViewActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.webview.TaskWebViewActivity
@@ -122,7 +123,8 @@ class O2InstantMessageActivity : BaseMVPActivity<O2InstantMessageContract.View,
             }
             }
         }else if (type.startsWith("attachment_")) {
         }else if (type.startsWith("attachment_")) {
             setLinkStyle(textView) {
             setLinkStyle(textView) {
-                go<CloudDriveActivity>()
+//                go<CloudDriveActivity>()
+                go<CloudDiskActivity>()
             }
             }
         }else if (type.startsWith("calendar_")) {
         }else if (type.startsWith("calendar_")) {
             setLinkStyle(textView) {
             setLinkStyle(textView) {

+ 17 - 13
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/launch/LaunchActivity.kt

@@ -120,21 +120,25 @@ class LaunchActivity : BaseMVPActivity<LaunchContract.View, LaunchContract.Prese
     fun start() {
     fun start() {
         tv_launch_status.text = getString(R.string.launch_start) //开始启动
         tv_launch_status.text = getString(R.string.launch_start) //开始启动
         circleProgressBar_launch.visible()
         circleProgressBar_launch.visible()
-        PermissionRequester(this)
-                .request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
-                .o2Subscribe {
-                    onNext { (granted, shouldShowRequestPermissionRationale, deniedPermissions) ->
-                        Log.d("LaunchActivity", "granted:$granted, show:$shouldShowRequestPermissionRationale, deniedList:$deniedPermissions")
-                        if (!granted) {
-                            O2DialogSupport.openAlertDialog(this@LaunchActivity, "非常抱歉,应用需要存储权限才能正常运行, 马上去设置", { permissionSetting() })
-                        } else {
-                            checkNetwork()
+        if (CheckRoot.isDeviceRooted()) {
+            O2DialogSupport.openAlertDialog(this, "当前是Root环境,App禁止使用!")
+        }else {
+            PermissionRequester(this)
+                    .request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+                    .o2Subscribe {
+                        onNext { (granted, shouldShowRequestPermissionRationale, deniedPermissions) ->
+                            Log.d("LaunchActivity", "granted:$granted, show:$shouldShowRequestPermissionRationale, deniedList:$deniedPermissions")
+                            if (!granted) {
+                                O2DialogSupport.openAlertDialog(this@LaunchActivity, "非常抱歉,应用需要存储权限才能正常运行, 马上去设置", { permissionSetting() })
+                            } else {
+                                checkNetwork()
+                            }
+                        }
+                        onError { e, _ ->
+                            Log.e("LaunchActivity", "检查权限出错", e)
                         }
                         }
                     }
                     }
-                    onError { e, _ ->
-                        Log.e("LaunchActivity", "检查权限出错", e)
-                    }
-                }
+        }
     }
     }
 
 
     /**
     /**

+ 149 - 16
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/login/LoginActivity.kt

@@ -1,27 +1,30 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.login
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.login
 
 
 import android.content.Context
 import android.content.Context
+import android.graphics.BitmapFactory
 import android.media.AudioManager
 import android.media.AudioManager
 import android.media.MediaPlayer
 import android.media.MediaPlayer
 import android.os.Bundle
 import android.os.Bundle
-import androidx.core.content.ContextCompat
+import android.os.Looper
 import android.text.InputType
 import android.text.InputType
 import android.text.TextUtils
 import android.text.TextUtils
 import android.view.KeyEvent
 import android.view.KeyEvent
 import android.view.View
 import android.view.View
 import android.view.WindowManager
 import android.view.WindowManager
 import android.view.inputmethod.InputMethodManager
 import android.view.inputmethod.InputMethodManager
+import android.widget.Toast
+import androidx.core.content.ContextCompat
 import kotlinx.android.synthetic.main.activity_login.*
 import kotlinx.android.synthetic.main.activity_login.*
 import net.muliba.changeskin.FancySkinManager
 import net.muliba.changeskin.FancySkinManager
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.*
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.*
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseMVPActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseMVPActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.bind.BindPhoneActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.bind.BindPhoneActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.main.MainActivity
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.main.MainActivity
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.CaptchaImgData
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.LoginModeData
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.LoginWithCaptchaForm
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.main.AuthenticationInfoJson
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.main.AuthenticationInfoJson
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.BitmapUtil
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.DateHelper
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XToast
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.*
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.biometric.BioConstants
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.biometric.BioConstants
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.biometric.BiometryManager
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.biometric.BiometryManager
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.biometric.OnBiometryAuthCallback
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.biometric.OnBiometryAuthCallback
@@ -85,11 +88,21 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
     private var loginType = 0 // 0默认的用户名验证码登录 1用户名密码登录
     private var loginType = 0 // 0默认的用户名验证码登录 1用户名密码登录
     private var canBioAuth = false //是否有指纹认证
     private var canBioAuth = false //是否有指纹认证
 
 
+    //验证码
+    private var useCaptcha = true
+    private var captcha : CaptchaImgData? = null
+
 
 
-    override fun afterSetContentView(savedInstanceState: Bundle?) {
-        receivePhone = intent.extras?.getString(REQUEST_PHONE_KEY) ?: ""
 
 
+    override fun afterSetContentView(savedInstanceState: Bundle?) {
+        //获取加密key
+        mPresenter.getRSAPublicKey()
+        //获取图片验证码
+        mPresenter.getCaptcha()
+        //
+        mPresenter.getLoginMode()
 
 
+        receivePhone = intent.extras?.getString(REQUEST_PHONE_KEY) ?: ""
         setDefaultLogo()
         setDefaultLogo()
         login_edit_username_id.setText(receivePhone)
         login_edit_username_id.setText(receivePhone)
         tv_login_copyright.text = getString(R.string.copy_right).plus(" ")
         tv_login_copyright.text = getString(R.string.copy_right).plus(" ")
@@ -114,23 +127,29 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
                 view_login_password_bottom.setBackgroundColor(FancySkinManager.instance().getColor(this, R.color.z_color_input_line_blur))
                 view_login_password_bottom.setBackgroundColor(FancySkinManager.instance().getColor(this, R.color.z_color_input_line_blur))
             }
             }
         }
         }
-
-
+        edit_login_captcha_input.setOnFocusChangeListener { _, hasFocus ->
+            if (hasFocus) {
+                view_login_captcha_input_bottom.setBackgroundColor(FancySkinManager.instance().getColor(this, R.color.z_color_input_line_focus))
+            }else {
+                view_login_captcha_input_bottom.setBackgroundColor(FancySkinManager.instance().getColor(this, R.color.z_color_input_line_blur))
+            }
+        }
 
 
         btn_login_submit.setOnClickListener(this)
         btn_login_submit.setOnClickListener(this)
         btn_bio_auth_login.setOnClickListener(this)
         btn_bio_auth_login.setOnClickListener(this)
         tv_user_fallback_btn.setOnClickListener(this)
         tv_user_fallback_btn.setOnClickListener(this)
         tv_bioauth_btn.setOnClickListener(this)
         tv_bioauth_btn.setOnClickListener(this)
+        image_login_captcha.setOnClickListener(this)
 
 
         //是否开启了指纹识别登录
         //是否开启了指纹识别登录
         checkBioAuthLogin()
         checkBioAuthLogin()
         if (BuildConfig.InnerServer) {
         if (BuildConfig.InnerServer) {
             login_edit_password_id.setHint(R.string.activity_login_password)
             login_edit_password_id.setHint(R.string.activity_login_password)
             login_edit_password_id.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
             login_edit_password_id.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
-//            InputType.TYPE_TEXT_VARIATION_PASSWORD
             button_login_phone_code.gone()
             button_login_phone_code.gone()
             tv_rebind_btn.gone()
             tv_rebind_btn.gone()
             tv_bioauth_btn.gone()
             tv_bioauth_btn.gone()
+            ll_login_captcha.visible()
         }else {
         }else {
             tv_bioauth_btn.visible()
             tv_bioauth_btn.visible()
             login_edit_password_id.setHint(R.string.login_code)
             login_edit_password_id.setHint(R.string.login_code)
@@ -139,6 +158,8 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
             button_login_phone_code.setOnClickListener(this)
             button_login_phone_code.setOnClickListener(this)
             tv_rebind_btn.visible()
             tv_rebind_btn.visible()
             tv_rebind_btn.setOnClickListener(this)
             tv_rebind_btn.setOnClickListener(this)
+            //不需要图片验证码
+            ll_login_captcha.gone()
         }
         }
 
 
     }
     }
@@ -166,6 +187,10 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
 
 
     override fun onResume() {
     override fun onResume() {
         super.onResume()
         super.onResume()
+        //清除用户名密码
+        login_edit_username_id.setText("")
+        login_edit_password_id.setText("")
+        edit_login_captcha_input.setText("")
 
 
         playBeep = true
         playBeep = true
         val audioService = getSystemService(Context.AUDIO_SERVICE) as AudioManager
         val audioService = getSystemService(Context.AUDIO_SERVICE) as AudioManager
@@ -175,6 +200,26 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
         initBeepSound()
         initBeepSound()
     }
     }
 
 
+    override fun onStop() {
+        super.onStop()
+
+        //Activity反劫持检测工具
+        Thread(Runnable { // 白名单
+            val safe = AntiHijackingUtil.checkActivity(applicationContext)
+            // 系统桌面
+            val isHome = AntiHijackingUtil.isHome(applicationContext)
+            // 锁屏操作
+            val isReflectScreen = AntiHijackingUtil.isReflectScreen(applicationContext)
+            // 判断程序是否当前显示
+            if (!safe && !isHome && !isReflectScreen) {
+                Looper.prepare()
+                Toast.makeText(applicationContext, R.string.activity_safe_warning,
+                        Toast.LENGTH_LONG).show()
+                Looper.loop()
+            }
+        }).start()
+    }
+
     override fun onDestroy() {
     override fun onDestroy() {
         super.onDestroy()
         super.onDestroy()
         countDownHelper.destroy()
         countDownHelper.destroy()
@@ -202,6 +247,10 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
                     reBindService()
                     reBindService()
                 })
                 })
             }
             }
+            R.id.image_login_captcha -> {
+                showLoadingDialog()
+                mPresenter.getCaptcha()
+            }
         }
         }
     }
     }
 
 
@@ -228,11 +277,13 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
     }
     }
     private  fun changeLoginType() {
     private  fun changeLoginType() {
         if (loginType == 0) {
         if (loginType == 0) {
+            ll_login_captcha.visible()
             login_edit_password_id.setHint(R.string.activity_login_password)
             login_edit_password_id.setHint(R.string.activity_login_password)
             login_edit_password_id.inputType = InputType.TYPE_TEXT_VARIATION_PASSWORD
             login_edit_password_id.inputType = InputType.TYPE_TEXT_VARIATION_PASSWORD
             button_login_phone_code.gone()
             button_login_phone_code.gone()
             loginType = 1
             loginType = 1
         }else {
         }else {
+            ll_login_captcha.gone()
             login_edit_password_id.setHint(R.string.login_code)
             login_edit_password_id.setHint(R.string.login_code)
             login_edit_password_id.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_NORMAL
             login_edit_password_id.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_NORMAL
             button_login_phone_code.visible()
             button_login_phone_code.visible()
@@ -242,6 +293,32 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
     }
     }
 
 
 
 
+    override fun loginMode(mode: LoginModeData?) {
+        if (mode != null) {
+            useCaptcha = mode.captchaLogin
+            if (useCaptcha) {
+                ll_login_captcha.visible()
+            }else {
+                ll_login_captcha.gone()
+            }
+        }
+    }
+
+    override fun showCaptcha(data: CaptchaImgData) {
+        hideLoadingDialog()
+        captcha = data
+         val stream = Base64ImageUtil.generateBase642Inputstream(data.image)
+        if (stream != null) {
+            image_login_captcha.setImageBitmap(BitmapFactory.decodeStream(stream))
+        }
+    }
+
+    override fun getCaptchaError(err: String) {
+        hideLoadingDialog()
+        //todo 图片验证码没有
+        XLog.error(err)
+    }
+
     override fun loginSuccess(data: AuthenticationInfoJson) {
     override fun loginSuccess(data: AuthenticationInfoJson) {
         if (login_main_biometry.visibility == View.VISIBLE) {
         if (login_main_biometry.visibility == View.VISIBLE) {
             playBeepSound()
             playBeepSound()
@@ -280,16 +357,72 @@ class LoginActivity: BaseMVPActivity<LoginContract.View, LoginContract.Presenter
             XToast.toastShort(this, "$label 不能为空!")
             XToast.toastShort(this, "$label 不能为空!")
             return
             return
         }
         }
-        showLoadingDialog()
-        if (BuildConfig.InnerServer) {
-            mPresenter.loginByPassword(credential, code)
+        if (useCaptcha) {
+            if (BuildConfig.InnerServer) {
+//                mPresenter.loginByPassword(credential, code)
+                val captchaCode = edit_login_captcha_input.text.toString()
+                if (TextUtils.isEmpty(captchaCode)) {
+                    XToast.toastShort(this, "图片验证码 不能为空!")
+                    return
+                }
+                if (captcha == null) {
+                    XToast.toastShort(this, "图片验证码 不能为空!")
+                    return
+                }
+                val form = LoginWithCaptchaForm()
+                form.credential = credential
+                form.password = code
+                form.captcha = captcha!!.id
+                form.captchaAnswer = captchaCode
+                showLoadingDialog()
+                mPresenter.loginWithCaptcha(form)
+            }else {
+                if (loginType == 0) {
+                    showLoadingDialog()
+                    mPresenter.login(credential, code)
+                }else {
+//                    mPresenter.loginByPassword(credential, code)
+                    val captchaCode = edit_login_captcha_input.text.toString()
+                    if (TextUtils.isEmpty(captchaCode)) {
+                        XToast.toastShort(this, "图片验证码 不能为空!")
+                        return
+                    }
+                    if (captcha == null) {
+                        XToast.toastShort(this, "图片验证码 不能为空!")
+                        return
+                    }
+                    val form = LoginWithCaptchaForm()
+                    form.credential = credential
+                    form.password = code
+                    form.captcha = captcha!!.id
+                    form.captchaAnswer = captchaCode
+                    showLoadingDialog()
+                    mPresenter.loginWithCaptcha(form)
+                }
+            }
         }else {
         }else {
-            if (loginType == 0) {
-                mPresenter.login(credential, code)
+            if (BuildConfig.InnerServer) {
+//                mPresenter.loginByPassword(credential, code)
+                val form = LoginWithCaptchaForm()
+                form.credential = credential
+                form.password = code
+                showLoadingDialog()
+                mPresenter.loginWithCaptcha(form)
             }else {
             }else {
-                mPresenter.loginByPassword(credential, code)
+                if (loginType == 0) {
+                    showLoadingDialog()
+                    mPresenter.login(credential, code)
+                }else {
+//                    mPresenter.loginByPassword(credential, code)
+                    val form = LoginWithCaptchaForm()
+                    form.credential = credential
+                    form.password = code
+                    showLoadingDialog()
+                    mPresenter.loginWithCaptcha(form)
+                }
             }
             }
         }
         }
+
     }
     }
 
 
 
 

+ 26 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/login/LoginContract.kt

@@ -2,6 +2,9 @@ package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.login
 
 
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenter
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenter
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseView
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BaseView
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.CaptchaImgData
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.LoginModeData
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.LoginWithCaptchaForm
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.main.AuthenticationInfoJson
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.main.AuthenticationInfoJson
 
 
 /**
 /**
@@ -13,11 +16,19 @@ object LoginContract {
         fun getCodeError()
         fun getCodeError()
         fun loginSuccess(data: AuthenticationInfoJson)
         fun loginSuccess(data: AuthenticationInfoJson)
         fun loginFail()
         fun loginFail()
+        fun showCaptcha(data: CaptchaImgData)
+        fun getCaptchaError(err: String)
+        fun loginMode(mode: LoginModeData?)
     }
     }
 
 
     interface Presenter: BasePresenter<View> {
     interface Presenter: BasePresenter<View> {
 
 
 
 
+        /**
+         * 登录方式
+         */
+        fun getLoginMode()
+
         /**
         /**
          * 获取验证码
          * 获取验证码
          * @param value 用户名或者手机号码
          * @param value 用户名或者手机号码
@@ -37,6 +48,21 @@ object LoginContract {
 
 
         fun ssoLogin(userId: String)
         fun ssoLogin(userId: String)
 
 
+        /**
+         * 获取图片验证码
+         */
+        fun getCaptcha()
+
+
+        /**
+         * 图片验证码登录
+         */
+        fun loginWithCaptcha(form: LoginWithCaptchaForm)
+
+        /**
+         *
+         */
+        fun getRSAPublicKey()
 
 
     }
     }
 }
 }

+ 85 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/login/LoginPresenter.kt

@@ -1,11 +1,14 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.login
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.login
 
 
 
 
+import android.text.TextUtils
 import net.muliba.accounting.app.ExceptionHandler
 import net.muliba.accounting.app.ExceptionHandler
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.O2
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenterImpl
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenterImpl
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.ResponseHandler
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.ResponseHandler
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.LoginWithCaptchaForm
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.Base64ImageUtil
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.Base64ImageUtil
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.CryptRSA
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.o2Subscribe
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.o2Subscribe
 import rx.android.schedulers.AndroidSchedulers
 import rx.android.schedulers.AndroidSchedulers
@@ -17,8 +20,90 @@ import rx.schedulers.Schedulers
 
 
 class LoginPresenter : BasePresenterImpl<LoginContract.View>(), LoginContract.Presenter {
 class LoginPresenter : BasePresenterImpl<LoginContract.View>(), LoginContract.Presenter {
 
 
+    //rsa加密公钥
+    private var publicKey: String = ""
 
 
 
 
+    override fun getLoginMode() {
+        getAssembleAuthenticationService(mView?.getContext())?.let { service ->
+            service.loginMode()
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .o2Subscribe {
+                        onNext {
+                            mView?.loginMode(it.data)
+                        }
+                        onError { e, _ ->
+                            XLog.error("", e)
+                            mView?.loginMode(null)
+                        }
+                    }
+        }
+    }
+
+    override fun getCaptcha() {
+        getAssembleAuthenticationService(mView?.getContext())?.let { service ->
+            service.getCaptchaCodeImg(120, 50)
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .o2Subscribe {
+                        onNext {
+                            if (it.data != null) {
+                                mView?.showCaptcha(it.data)
+                            }else {
+                                mView?.getCaptchaError("没有获取到图片验证码")
+                            }
+                        }
+                        onError { e, _ ->
+                            XLog.error("获取图片验证码错误,", e)
+                            mView?.getCaptchaError("没有获取到图片验证码")
+                        }
+                    }
+        }
+    }
+
+    override fun loginWithCaptcha(form: LoginWithCaptchaForm) {
+        getAssembleAuthenticationService(mView?.getContext())?.let { service ->
+            //加密
+            if (!TextUtils.isEmpty(publicKey)) {
+                XLog.debug("key:$publicKey")
+                val newPwd = CryptRSA.rsaEncryptByPublicKey(form.password, publicKey)
+                if (!TextUtils.isEmpty(newPwd)) {
+                    form.password = newPwd
+                    form.isEncrypted = "y"
+                    XLog.debug("加密成功。。。。。$newPwd")
+                }
+            }
+            service.loginWithCaptchaCode(form)
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .subscribe(ResponseHandler { data -> mView?.loginSuccess(data) },
+                            ExceptionHandler(mView?.getContext()) { e ->
+                                XLog.error("", e)
+                                mView?.loginFail()
+                            })
+        }
+    }
+
+    override fun getRSAPublicKey() {
+        getAssembleAuthenticationService(mView?.getContext())?.let { service ->
+            service.getRSAPublicKey()
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .o2Subscribe {
+                        onNext {
+                            if (it.data!=null) {
+                                publicKey = it.data.publicKey
+                                XLog.debug("public key is ok.lllll ")
+                            }
+                        }
+                        onError { e, _ ->
+                            XLog.error("public key is error ", e)
+                        }
+                    }
+        }
+    }
+
     override fun getVerificationCode(value: String) {
     override fun getVerificationCode(value: String) {
         getAssembleAuthenticationService(mView?.getContext())?.let { service ->
         getAssembleAuthenticationService(mView?.getContext())?.let { service ->
             service.getPhoneCode(value)
             service.getPhoneCode(value)

+ 2 - 1
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/IndexFragment.kt

@@ -81,7 +81,8 @@ class IndexFragment : BaseMVPViewPagerFragment<IndexContract.View, IndexContract
                 ApplicationEnum.READCOMPLETED.key -> activity.go<ReadCompletedListActivity>()
                 ApplicationEnum.READCOMPLETED.key -> activity.go<ReadCompletedListActivity>()
                 ApplicationEnum.BBS.key -> activity.go<BBSMainActivity>()
                 ApplicationEnum.BBS.key -> activity.go<BBSMainActivity>()
                 ApplicationEnum.CMS.key -> activity.go<CMSIndexActivity>()
                 ApplicationEnum.CMS.key -> activity.go<CMSIndexActivity>()
-                ApplicationEnum.YUNPAN.key -> activity.go<CloudDriveActivity>()
+                ApplicationEnum.YUNPAN.key -> activity.go<CloudDiskActivity>()
+//                ApplicationEnum.YUNPAN.key -> activity.go<CloudDriveActivity>()
                 ApplicationEnum.clouddisk.key -> activity.go<CloudDiskActivity>()
                 ApplicationEnum.clouddisk.key -> activity.go<CloudDiskActivity>()
                 ApplicationEnum.MEETING.key -> activity.go<MeetingMainActivity>()
                 ApplicationEnum.MEETING.key -> activity.go<MeetingMainActivity>()
                 ApplicationEnum.ATTENDANCE.key -> activity.go<AttendanceMainActivity>()
                 ApplicationEnum.ATTENDANCE.key -> activity.go<AttendanceMainActivity>()

+ 4 - 1
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/IndexPortalFragment.kt

@@ -114,7 +114,10 @@ class IndexPortalFragment : BaseMVPViewPagerFragment<IndexPortalContract.View, I
     }
     }
 
 
     override fun lazyLoad() {
     override fun lazyLoad() {
-
+        //页面显示的时候调用一个js方法 这个方法可以用来刷新数据之类的
+        web_view_portal_content.evaluateJavascript("window.o2Reload()") { value ->
+            XLog.info("执行o2Reload , result: $value")
+        }
     }
     }
 
 
     override fun loadCmsCategoryListByAppId(categoryList: List<CMSCategoryInfoJson>) {
     override fun loadCmsCategoryListByAppId(categoryList: List<CMSCategoryInfoJson>) {

+ 8 - 8
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/main/MyAppPresenter.kt

@@ -35,10 +35,10 @@ class MyAppPresenter : BasePresenterImpl<MyAppContract.View>(), MyAppContract.Pr
                         obj.appTitle = it.name
                         obj.appTitle = it.name
                         result.add(obj)
                         result.add(obj)
                     }
                     }
-                    val newCloudDiskApp = MyAppListObject()
-                    newCloudDiskApp.appId = ApplicationEnum.clouddisk.key
-                    newCloudDiskApp.appTitle = ApplicationEnum.clouddisk.appName
-                    result.add(newCloudDiskApp)
+//                    val newCloudDiskApp = MyAppListObject()
+//                    newCloudDiskApp.appId = ApplicationEnum.clouddisk.key
+//                    newCloudDiskApp.appTitle = ApplicationEnum.clouddisk.appName
+//                    result.add(newCloudDiskApp)
                     service.findAllPortalList()
                     service.findAllPortalList()
                 }
                 }
                 ?.flatMap { list ->
                 ?.flatMap { list ->
@@ -66,10 +66,10 @@ class MyAppPresenter : BasePresenterImpl<MyAppContract.View>(), MyAppContract.Pr
                                             obj.appTitle = it.name
                                             obj.appTitle = it.name
                                             result.add(obj)
                                             result.add(obj)
                                         }
                                         }
-                                        val newCloudDiskApp = MyAppListObject()
-                                        newCloudDiskApp.appId = ApplicationEnum.clouddisk.key
-                                        newCloudDiskApp.appTitle = ApplicationEnum.clouddisk.appName
-                                        result.add(newCloudDiskApp)
+//                                        val newCloudDiskApp = MyAppListObject()
+//                                        newCloudDiskApp.appId = ApplicationEnum.clouddisk.key
+//                                        newCloudDiskApp.appTitle = ApplicationEnum.clouddisk.appName
+//                                        result.add(newCloudDiskApp)
                                         portalList.filter { portal -> portal.enable }.map {
                                         portalList.filter { portal -> portal.enable }.map {
                                             val obj = MyAppListObject()
                                             val obj = MyAppListObject()
                                             obj.appId = it.id
                                             obj.appId = it.id

+ 1 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/security/AccountSecurityActivity.kt

@@ -23,6 +23,7 @@ class AccountSecurityActivity : BaseMVPActivity<AccountSecurityContract.View, Ac
     override var mPresenter: AccountSecurityContract.Presenter = AccountSecurityPresenter()
     override var mPresenter: AccountSecurityContract.Presenter = AccountSecurityPresenter()
     override fun layoutResId(): Int  = R.layout.activity_account_security
     override fun layoutResId(): Int  = R.layout.activity_account_security
     override fun afterSetContentView(savedInstanceState: Bundle?) {
     override fun afterSetContentView(savedInstanceState: Bundle?) {
+        mPresenter.getRSAPublicKey()
         setupToolBar(getString(R.string.title_activity_account_security), true)
         setupToolBar(getString(R.string.title_activity_account_security), true)
 
 
         account_name_id.text = O2SDKManager.instance().cName
         account_name_id.text = O2SDKManager.instance().cName

+ 5 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/security/AccountSecurityContract.kt

@@ -15,5 +15,10 @@ object AccountSecurityContract {
     interface Presenter : BasePresenter<View> {
     interface Presenter : BasePresenter<View> {
         fun logout(deviceId:String)
         fun logout(deviceId:String)
         fun updateMyPassword(old: String, newPwd: String, newPwdConfirm: String)
         fun updateMyPassword(old: String, newPwd: String, newPwdConfirm: String)
+        /**
+         *
+         */
+        fun getRSAPublicKey()
+
     }
     }
 }
 }

+ 42 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/app/o2/security/AccountSecurityPresenter.kt

@@ -1,11 +1,13 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.security
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.o2.security
 
 
+import android.text.TextUtils
 import net.muliba.accounting.app.ExceptionHandler
 import net.muliba.accounting.app.ExceptionHandler
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenterImpl
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.app.base.BasePresenterImpl
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.ResponseHandler
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.ResponseHandler
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.exception.O2ResponseException
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.exception.O2ResponseException
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.IdData
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.IdData
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.main.person.PersonPwdForm
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.main.person.PersonPwdForm
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.CryptRSA
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.XLog
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.o2Subscribe
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils.extension.o2Subscribe
 import rx.android.schedulers.AndroidSchedulers
 import rx.android.schedulers.AndroidSchedulers
@@ -13,6 +15,28 @@ import rx.schedulers.Schedulers
 
 
 class AccountSecurityPresenter : BasePresenterImpl<AccountSecurityContract.View>(), AccountSecurityContract.Presenter {
 class AccountSecurityPresenter : BasePresenterImpl<AccountSecurityContract.View>(), AccountSecurityContract.Presenter {
 
 
+    //rsa加密公钥
+    private var publicKey: String = ""
+
+
+    override fun getRSAPublicKey() {
+        getAssembleAuthenticationService(mView?.getContext())?.let { service ->
+            service.getRSAPublicKey()
+                    .subscribeOn(Schedulers.io())
+                    .observeOn(AndroidSchedulers.mainThread())
+                    .o2Subscribe {
+                        onNext {
+                            if (it.data!=null) {
+                                publicKey = it.data.publicKey
+                                XLog.debug("public key is ok.lllll ")
+                            }
+                        }
+                        onError { e, _ ->
+                            XLog.error("public key is error ", e)
+                        }
+                    }
+        }
+    }
 
 
     override fun logout(deviceId: String) {
     override fun logout(deviceId: String) {
         getAssembleAuthenticationService(mView?.getContext())?.let { service->
         getAssembleAuthenticationService(mView?.getContext())?.let { service->
@@ -29,6 +53,24 @@ class AccountSecurityPresenter : BasePresenterImpl<AccountSecurityContract.View>
         val service = getAssemblePersonalApi(mView?.getContext())
         val service = getAssemblePersonalApi(mView?.getContext())
         if (service != null) {
         if (service != null) {
             val form = PersonPwdForm(old, newPwd, newPwdConfirm)
             val form = PersonPwdForm(old, newPwd, newPwdConfirm)
+
+            if (!TextUtils.isEmpty(publicKey)) {
+                XLog.debug("key:$publicKey")
+                val newOld = CryptRSA.rsaEncryptByPublicKey(old, publicKey)
+                if (!TextUtils.isEmpty(newOld)) {
+                    form.oldPassword = newOld
+                }
+                val newNewPwd = CryptRSA.rsaEncryptByPublicKey(newPwd, publicKey)
+                if (!TextUtils.isEmpty(newNewPwd)) {
+                    form.newPassword = newNewPwd
+                }
+                val newNewPwdConfirm = CryptRSA.rsaEncryptByPublicKey(newPwdConfirm, publicKey)
+                if (!TextUtils.isEmpty(newNewPwdConfirm)) {
+                    form.confirmPassword = newNewPwdConfirm
+                }
+                form.isEncrypted = "y"
+            }
+
             service.modifyCurrentPersonPassword(form)
             service.modifyCurrentPersonPassword(form)
                     .subscribeOn(Schedulers.io())
                     .subscribeOn(Schedulers.io())
                     .observeOn(AndroidSchedulers.mainThread())
                     .observeOn(AndroidSchedulers.mainThread())

+ 151 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/AntiHijackingUtil.java

@@ -0,0 +1,151 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils;
+
+import android.app.ActivityManager;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Description: Activity反劫持检测工具
+ * author: zs
+ * Date: 2018/7/8 16:31
+ */
+public class AntiHijackingUtil {
+    public static final String TAG = "AntiHijackingUtil";
+
+    /**
+     * 检测当前Activity是否安全
+     */
+    public static boolean checkActivity(Context context) {
+        PackageManager pm = context.getPackageManager();
+        // 查询所有已经安装的应用程序
+        List<ApplicationInfo> listAppcations =
+                pm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
+        Collections.sort(listAppcations, new ApplicationInfo.DisplayNameComparator(pm));// 排序
+
+        List<String> safePackages = new ArrayList<>();
+        for (ApplicationInfo app : listAppcations) {// 这个排序必须有.
+            if ((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+                safePackages.add(app.packageName);
+            }
+        }
+        // 得到所有的系统程序包名放进白名单里面.
+        ActivityManager activityManager =
+                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        String runningActivityPackageName;
+        int sdkVersion;
+        try {
+            sdkVersion = Integer.valueOf(android.os.Build.VERSION.SDK);
+        } catch (NumberFormatException e) {
+            sdkVersion = 0;
+        }
+        if (sdkVersion >= 21) {// 获取系统api版本号,如果是5x系统就用这个方法获取当前运行的包名
+            runningActivityPackageName = getCurrentPkgName(context);
+        } else {
+            runningActivityPackageName =
+                    activityManager.getRunningTasks(1).get(0).topActivity.getPackageName();
+        }
+        // 如果是4x及以下,用这个方法.
+        if (runningActivityPackageName != null) {
+            // 有些情况下在5x的手机中可能获取不到当前运行的包名,所以要非空判断。
+            if (runningActivityPackageName.equals(context.getPackageName())) {
+                return true;
+            }
+            // 白名单比对
+            for (String safePack : safePackages) {
+                if (safePack.equals(runningActivityPackageName)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static String getCurrentPkgName(Context context) {
+        // 5x系统以后利用反射获取当前栈顶activity的包名.
+        ActivityManager.RunningAppProcessInfo currentInfo = null;
+        Field field = null;
+        int START_TASK_TO_FRONT = 2;
+        String pkgName = null;
+        try {
+            // 通过反射获取进程状态字段.
+            field = ActivityManager.RunningAppProcessInfo.class.getDeclaredField("processState");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        List appList = am.getRunningAppProcesses();
+        ActivityManager.RunningAppProcessInfo app;
+        for (int i = 0; i < appList.size(); i++) {
+            //ActivityManager.RunningAppProcessInfo app : appList
+            app = (ActivityManager.RunningAppProcessInfo) appList.get(i);
+            //表示前台运行进程.
+            if (app.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+                Integer state = null;
+                try {
+                    state = field.getInt(app);// 反射调用字段值的方法,获取该进程的状态.
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+                // 根据这个判断条件从前台中获取当前切换的进程对象
+                if (state != null && state == START_TASK_TO_FRONT) {
+                    currentInfo = app;
+                    break;
+                }
+            }
+        }
+        if (currentInfo != null) {
+            pkgName = currentInfo.processName;
+        }
+        return pkgName;
+    }
+
+    /**
+     * 判断当前是否在桌面
+     *
+     * @param context 上下文
+     */
+    public static boolean isHome(Context context) {
+        ActivityManager mActivityManager =
+                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        List<ActivityManager.RunningTaskInfo> rti = mActivityManager.getRunningTasks(1);
+        return getHomes(context).contains(rti.get(0).topActivity.getPackageName());
+    }
+
+    /**
+     * 获得属于桌面的应用的应用包名称
+     *
+     * @return 返回包含所有包名的字符串列表
+     */
+    private static List<String> getHomes(Context context) {
+        List<String> names = new ArrayList<String>();
+        PackageManager packageManager = context.getPackageManager();
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.addCategory(Intent.CATEGORY_HOME);
+        List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent,
+                PackageManager.MATCH_DEFAULT_ONLY);
+        for (ResolveInfo ri : resolveInfo) {
+            names.add(ri.activityInfo.packageName);
+        }
+        return names;
+    }
+
+    /**
+     * 判断当前是否在锁屏再解锁状态
+     *
+     * @param context 上下文
+     */
+    public static boolean isReflectScreen(Context context) {
+        KeyguardManager mKeyguardManager =
+                (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
+        return mKeyguardManager.inKeyguardRestrictedInputMode();
+    }
+}

+ 200 - 0
o2android/app/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/CheckRoot.java

@@ -0,0 +1,200 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils;
+
+/**
+ * Created by fancyLou on 2020-09-28.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.util.ArrayList;
+
+public class CheckRoot {
+    private static String LOG_TAG = CheckRoot.class.getName();
+
+    public static boolean isDeviceRooted() {
+        if (checkDeviceDebuggable()) {
+            return true;
+        }//check buildTags
+        if (checkSuperuserApk()) {
+            return true;
+        }//Superuser.apk
+        //if (checkRootPathSU()){return true;}//find su in some path
+        //if (checkRootWhichSU()){return true;}//find su use 'which'
+        if (checkBusybox()) {
+            return true;
+        }//find su use 'which'
+        if (checkAccessRootData()) {
+            return true;
+        }//find su use 'which'
+        if (checkGetRootAuth()) {
+            return true;
+        }//exec su
+
+        return false;
+    }
+
+    public static boolean checkDeviceDebuggable() {
+        String buildTags = android.os.Build.TAGS;
+        if (buildTags != null && buildTags.contains("test-keys")) {
+            Log.i(LOG_TAG, "buildTags=" + buildTags);
+            return true;
+        }
+        return false;
+    }
+
+    public static boolean checkSuperuserApk() {
+        try {
+            File file = new File("/system/app/Superuser.apk");
+            if (file.exists()) {
+                Log.i(LOG_TAG, "/system/app/Superuser.apk exist");
+                return true;
+            }
+        } catch (Exception e) {
+        }
+        return false;
+    }
+
+    public static synchronized boolean checkGetRootAuth() {
+        Process process = null;
+        DataOutputStream os = null;
+        try {
+            Log.i(LOG_TAG, "to exec su");
+            process = Runtime.getRuntime().exec("su");
+            os = new DataOutputStream(process.getOutputStream());
+            os.writeBytes("exit\n");
+            os.flush();
+            int exitValue = process.waitFor();
+            Log.i(LOG_TAG, "exitValue=" + exitValue);
+            if (exitValue == 0) {
+                return true;
+            } else {
+                return false;
+            }
+        } catch (Exception e) {
+            Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
+                    + e.getMessage());
+            return false;
+        } finally {
+            try {
+                if (os != null) {
+                    os.close();
+                }
+                process.destroy();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public static synchronized boolean checkBusybox() {
+        try {
+            Log.i(LOG_TAG, "to exec busybox df");
+            String[] strCmd = new String[]{"busybox", "df"};
+            ArrayList<String> execResult = executeCommand(strCmd);
+            if (execResult != null) {
+                Log.i(LOG_TAG, "execResult=" + execResult.toString());
+                return true;
+            } else {
+                Log.i(LOG_TAG, "execResult=null");
+                return false;
+            }
+        } catch (Exception e) {
+            Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
+                    + e.getMessage());
+            return false;
+        }
+    }
+
+    public static ArrayList<String> executeCommand(String[] shellCmd) {
+        String line = null;
+        ArrayList<String> fullResponse = new ArrayList<String>();
+        Process localProcess = null;
+        try {
+            Log.i(LOG_TAG, "to shell exec which for find su :");
+            localProcess = Runtime.getRuntime().exec(shellCmd);
+        } catch (Exception e) {
+            return null;
+        }
+        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(localProcess.getOutputStream()));
+        BufferedReader in = new BufferedReader(new InputStreamReader(localProcess.getInputStream()));
+        try {
+            while ((line = in.readLine()) != null) {
+                Log.i(LOG_TAG, "–> Line received: " + line);
+                fullResponse.add(line);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        Log.i(LOG_TAG, "–> Full response was: " + fullResponse);
+        return fullResponse;
+    }
+
+    public static synchronized boolean checkAccessRootData() {
+        try {
+            Log.i(LOG_TAG, "to write /data");
+            String fileContent = "test_ok";
+            Boolean writeFlag = writeFile("/data/su_test", fileContent);
+            if (writeFlag) {
+                Log.i(LOG_TAG, "write ok");
+            } else {
+                Log.i(LOG_TAG, "write failed");
+            }
+
+            Log.i(LOG_TAG, "to read /data");
+            String strRead = readFile("/data/su_test");
+            Log.i(LOG_TAG, "strRead=" + strRead);
+            if (fileContent.equals(strRead)) {
+                return true;
+            } else {
+                return false;
+            }
+        } catch (Exception e) {
+            Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
+                    + e.getMessage());
+            return false;
+        }
+    }
+
+    //写文件
+    public static Boolean writeFile(String fileName, String message) {
+        try {
+            FileOutputStream fout = new FileOutputStream(fileName);
+            byte[] bytes = message.getBytes();
+            fout.write(bytes);
+            fout.close();
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    //读文件
+    public static String readFile(String fileName) {
+        File file = new File(fileName);
+        try {
+            FileInputStream fis = new FileInputStream(file);
+            byte[] bytes = new byte[1024];
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            int len;
+            while ((len = fis.read(bytes)) > 0) {
+                bos.write(bytes, 0, len);
+            }
+            String result = new String(bos.toByteArray());
+            Log.i(LOG_TAG, result);
+            return result;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+}

+ 41 - 0
o2android/app/src/main/res/layout/activity_login.xml

@@ -153,6 +153,47 @@
                         android:background="@color/z_color_input_line_blur"
                         android:background="@color/z_color_input_line_blur"
                         />
                         />
 
 
+                    <LinearLayout
+                        android:id="@+id/ll_login_captcha"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginTop="10dp"
+                        android:orientation="horizontal">
+                        <LinearLayout
+                            android:layout_width="0dp"
+                            android:layout_weight="1"
+                            android:layout_height="match_parent"
+                            android:orientation="vertical">
+                            <net.zoneland.x.bpm.mobile.v1.zoneXBPM.widgets.ClearTextEdit
+                                android:id="@+id/edit_login_captcha_input"
+                                android:layout_width="match_parent"
+                                android:layout_height="49dp"
+                                android:layout_gravity="center_vertical"
+                                android:background="@null"
+                                android:hint="@string/login_captcha"
+                                android:maxLines="1"
+                                android:inputType="number"
+                                android:textColor="@color/z_color_text_primary"
+                                android:textColorHint="@color/z_color_text_hint"
+                                android:textSize="13sp" />
+                            <View
+                                android:id="@+id/view_login_captcha_input_bottom"
+                                android:layout_width="match_parent"
+                                android:layout_height="1dp"
+                                android:background="@color/z_color_input_line_blur"
+                                />
+                        </LinearLayout>
+                        <ImageView
+                            android:id="@+id/image_login_captcha"
+                            android:layout_width="120dp"
+                            android:layout_height="50dp"
+                            android:scaleType="fitCenter"
+                            />
+
+                    </LinearLayout>
+
+
+
                     <Button
                     <Button
                         android:id="@+id/btn_login_submit"
                         android:id="@+id/btn_login_submit"
                         android:layout_width="match_parent"
                         android:layout_width="match_parent"

+ 4 - 0
o2android/app/src/main/res/values/strings.xml

@@ -2,6 +2,7 @@
     <string name="app_name">O2OA</string>
     <string name="app_name">O2OA</string>
     <string name="app_about">关于O2OA</string>
     <string name="app_about">关于O2OA</string>
     <string name="app_name_about">O2OA</string>
     <string name="app_name_about">O2OA</string>
+    <string name="activity_safe_warning">已切换至后台运行!</string>
     <string name="copy_right">&#169;</string>
     <string name="copy_right">&#169;</string>
     <string name="reserved">All right reserved.</string>
     <string name="reserved">All right reserved.</string>
     <string name="version">版本:</string>
     <string name="version">版本:</string>
@@ -13,6 +14,8 @@
     <string name="bind_phone_choose_company">选择单位</string>
     <string name="bind_phone_choose_company">选择单位</string>
     <string name="app_error">应用异常</string>
     <string name="app_error">应用异常</string>
 
 
+
+
     <string name="launch_start">准备中&#8230;</string>
     <string name="launch_start">准备中&#8230;</string>
     <string name="launch_network_is_not_connected">网络未连接,请检查网络连接情况!</string>
     <string name="launch_network_is_not_connected">网络未连接,请检查网络连接情况!</string>
     <string name="launch_check_bind">正在连接O2云&#8230;</string>
     <string name="launch_check_bind">正在连接O2云&#8230;</string>
@@ -112,6 +115,7 @@
     <string name="activity_login_username">用户名或手机号码</string>
     <string name="activity_login_username">用户名或手机号码</string>
     <string name="login_phone">输入手机号码</string>
     <string name="login_phone">输入手机号码</string>
     <string name="login_code">验证码</string>
     <string name="login_code">验证码</string>
+    <string name="login_captcha">图片验证码</string>
     <string name="activity_login_password">密码</string>
     <string name="activity_login_password">密码</string>
     <string name="activity_login_submit">登    录</string>
     <string name="activity_login_submit">登    录</string>
     <string name="activity_login_other">其他登录方式</string>
     <string name="activity_login_other">其他登录方式</string>

+ 2 - 2
o2android/gradle.properties

@@ -23,6 +23,6 @@ android.enableJetifier=true
 
 
 
 
 # o2
 # o2
-o2.versionName=5.1.9
-o2.versionCode=119
+o2.versionName=5.2.0
+o2.versionCode=120
 
 

+ 30 - 3
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/OrgAssembleAuthenticationService.kt

@@ -1,8 +1,6 @@
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.service
 package net.zoneland.x.bpm.mobile.v1.zoneXBPM.core.component.api.service
 
 
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.ApiResponse
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.IdData
-import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.ValueData
+import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.*
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.main.AuthenticationInfoJson
 import net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.main.AuthenticationInfoJson
 import retrofit2.http.*
 import retrofit2.http.*
 import rx.Observable
 import rx.Observable
@@ -15,6 +13,13 @@ import rx.Observable
 
 
 interface OrgAssembleAuthenticationService{
 interface OrgAssembleAuthenticationService{
 
 
+
+    /**
+     * 登录状态
+     */
+    @GET("jaxrs/authentication/mode")
+    fun loginMode(): Observable<ApiResponse<LoginModeData>>
+
     /**
     /**
      * 登陆
      * 登陆
      * @param json
      * @param json
@@ -62,6 +67,21 @@ interface OrgAssembleAuthenticationService{
     fun getPhoneCode(@Path("credential") credential: String): Observable<ApiResponse<ValueData>>
     fun getPhoneCode(@Path("credential") credential: String): Observable<ApiResponse<ValueData>>
 
 
 
 
+    /**
+     * 获取图片验证码
+     */
+    @GET("jaxrs/authentication/captcha/width/{width}/height/{height}")
+    fun getCaptchaCodeImg(@Path("width") width: Int, @Path("height") height: Int): Observable<ApiResponse<CaptchaImgData>>
+
+
+    /**
+     * 用图片验证码登录
+     */
+    @Headers("Content-Type:application/json;charset=UTF-8")
+    @POST("jaxrs/authentication/captcha")
+    fun loginWithCaptchaCode(@Body form:LoginWithCaptchaForm): Observable<ApiResponse<AuthenticationInfoJson>>
+
+
     /**
     /**
      * 扫一扫 确认登录
      * 扫一扫 确认登录
      * @param meta
      * @param meta
@@ -72,6 +92,13 @@ interface OrgAssembleAuthenticationService{
     @POST("jaxrs/authentication/bind/meta/{meta}")
     @POST("jaxrs/authentication/bind/meta/{meta}")
     fun scanConfirmWebLogin(@Path("meta") meta: String): Observable<ApiResponse<AuthenticationInfoJson>>
     fun scanConfirmWebLogin(@Path("meta") meta: String): Observable<ApiResponse<AuthenticationInfoJson>>
 
 
+    /**
+     * 获取RSA 加密公钥
+     */
+    @GET("jaxrs/authentication/captchaRSAPublicKey")
+    fun getRSAPublicKey(): Observable<ApiResponse<RSAPublicKeyData>>
+
+
     /**
     /**
      * 登出
      * 登出
      * @return
      * @return

+ 1 - 1
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/core/component/api/service/OrgAssemblePersonalService.kt

@@ -51,6 +51,6 @@ interface OrgAssemblePersonalService {
     /**
     /**
      * 更新当前用户密码
      * 更新当前用户密码
      */
      */
-    @PUT("jaxrs/password")
+    @PUT("jaxrs/person/password")
     fun modifyCurrentPersonPassword(@Body body: PersonPwdForm): Observable<ApiResponse<ValueData>>
     fun modifyCurrentPersonPassword(@Body body: PersonPwdForm): Observable<ApiResponse<ValueData>>
 }
 }

+ 12 - 0
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/CaptchaImgData.kt

@@ -0,0 +1,12 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api
+
+/**
+ * Created by fancyLou on 2020-09-27.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+
+
+data class CaptchaImgData (
+        var id: String = "",
+        var image: String = "" //验证码图片的base64
+)

+ 14 - 0
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/LoginModeData.kt

@@ -0,0 +1,14 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api
+
+/**
+ * Created by fancyLou on 2020-09-27.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+
+
+data class LoginModeData (
+        var captchaLogin: Boolean = false, //验证码登录
+        var codeLogin: Boolean = false, //短信验证码登录
+        var bindLogin: Boolean = false,
+        var faceLogin: Boolean = false
+)

+ 14 - 0
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/LoginWithCaptchaForm.kt

@@ -0,0 +1,14 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api
+
+/**
+ * Created by fancyLou on 2020-09-27.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+
+data class LoginWithCaptchaForm (
+        var credential: String = "",
+        var password: String = "",
+        var captcha: String ="", //图片认证编号id
+        var captchaAnswer: String =  "",//图片认证码
+        var isEncrypted: String = "" //是否启用加密
+)

+ 11 - 0
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/RSAPublicKeyData.kt

@@ -0,0 +1,11 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api
+
+/**
+ * Created by fancyLou on 2020-09-27.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+
+
+data class RSAPublicKeyData (
+        var publicKey: String = "" //公钥
+)

+ 2 - 1
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/model/bo/api/main/person/PersonPwdForm.kt

@@ -9,5 +9,6 @@ package net.zoneland.x.bpm.mobile.v1.zoneXBPM.model.bo.api.main.person
 class PersonPwdForm(
 class PersonPwdForm(
         var oldPassword: String = "",
         var oldPassword: String = "",
         var newPassword: String = "",
         var newPassword: String = "",
-        var confirmPassword: String = ""
+        var confirmPassword: String = "",
+        var isEncrypted: String = ""
 )
 )

+ 53 - 0
o2android/o2_auth_sdk/src/main/java/net/zoneland/x/bpm/mobile/v1/zoneXBPM/utils/CryptRSA.java

@@ -0,0 +1,53 @@
+package net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils;
+
+
+import android.util.Base64;
+
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.spec.X509EncodedKeySpec;
+
+import javax.crypto.Cipher;
+
+/**
+ * Created by fancyLou on 2020-09-27.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+public class CryptRSA {
+    /**RSA算法*/
+    private static final String RSA = "RSA";
+
+    private static KeyFactory keyFactory;
+    static {
+        //实例化密钥工厂
+        try {
+            keyFactory = KeyFactory.getInstance(RSA);
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 公钥加密
+     *
+     * @param content   待加密数据
+     * @param publicKey 密钥
+     * @return string 加密后数据
+     */
+    public static String rsaEncryptByPublicKey(String content, String publicKey) throws Exception {
+        byte[] keyBytes = Base64.decode(publicKey, Base64.NO_WRAP);
+        //初始化公钥
+        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
+        //产生公钥
+        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
+        //数据加密
+        //PKCS1Padding
+        Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
+        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
+        return new String(Base64.encode(cipher.doFinal(content.trim().getBytes("utf-8")), Base64.NO_WRAP));
+
+    }
+
+
+}