Skip to content

Commit

Permalink
优化:发送通道企业微信应用支持http/socks5代理(应对IP白名单限制)
Browse files Browse the repository at this point in the history
  • Loading branch information
pppscn committed Jul 4, 2022
1 parent 93fb0b6 commit 6ea06ed
Show file tree
Hide file tree
Showing 4 changed files with 314 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
package com.idormy.sms.forwarder.entity.setting

import com.idormy.sms.forwarder.R
import java.io.Serializable
import java.net.Proxy

data class WeworkAgentSetting(
var corpID: String = "",
val agentID: String = "",
val secret: String = "",
val atAll: Boolean? = false,
val toUser: String? = "@all",
) : Serializable
val proxyType: Proxy.Type = Proxy.Type.DIRECT,
val proxyHost: String? = "",
val proxyPort: String? = "",
val proxyAuthenticator: Boolean? = false,
val proxyUsername: String? = "",
val proxyPassword: String? = "",
) : Serializable {

fun getProxyTypeCheckId(): Int {
return when (proxyType) {
Proxy.Type.HTTP -> R.id.rb_proxyHttp
Proxy.Type.SOCKS -> R.id.rb_proxySocks
else -> R.id.rb_proxyNone
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CompoundButton
import android.widget.RadioGroup
import androidx.fragment.app.viewModels
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
Expand All @@ -33,6 +34,7 @@ import io.reactivex.SingleObserver
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import java.net.Proxy
import java.util.*

@Page(name = "企业微信应用")
Expand Down Expand Up @@ -126,6 +128,12 @@ class WeworkAgentFragment : BaseFragment<FragmentSendersWeworkAgentBinding?>(),
binding!!.etSecret.setText(settingVo.secret)
binding!!.sbAtAll.isChecked = settingVo.atAll == true
binding!!.etToUser.setText(settingVo.toUser)
binding!!.rgProxyType.check(settingVo.getProxyTypeCheckId())
binding!!.etProxyHost.setText(settingVo.proxyHost)
binding!!.etProxyPort.setText(settingVo.proxyPort)
binding!!.sbProxyAuthenticator.isChecked = settingVo.proxyAuthenticator == true
binding!!.etProxyUsername.setText(settingVo.proxyUsername)
binding!!.etProxyPassword.setText(settingVo.proxyPassword)
}
}
})
Expand All @@ -136,17 +144,36 @@ class WeworkAgentFragment : BaseFragment<FragmentSendersWeworkAgentBinding?>(),
binding!!.btnDel.setOnClickListener(this)
binding!!.btnSave.setOnClickListener(this)
binding!!.sbAtAll.setOnCheckedChangeListener(this)
binding!!.sbProxyAuthenticator.setOnCheckedChangeListener(this)
binding!!.rgProxyType.setOnCheckedChangeListener { _: RadioGroup?, checkedId: Int ->
if (checkedId == R.id.rb_proxyHttp || checkedId == R.id.rb_proxySocks) {
binding!!.layoutProxyHost.visibility = View.VISIBLE
binding!!.layoutProxyPort.visibility = View.VISIBLE
binding!!.layoutProxyAuthenticator.visibility = if (binding!!.sbProxyAuthenticator.isChecked) View.VISIBLE else View.GONE
} else {
binding!!.layoutProxyHost.visibility = View.GONE
binding!!.layoutProxyPort.visibility = View.GONE
binding!!.layoutProxyAuthenticator.visibility = View.GONE
}
}
}

@SuppressLint("SetTextI18n")
override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) {
//注意:因为只有一个监听,暂不需要判断id
if (isChecked) {
binding!!.etToUser.setText("@all")
binding!!.layoutToUser.visibility = View.GONE
} else {
binding!!.etToUser.setText("")
binding!!.layoutToUser.visibility = View.VISIBLE
override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
when (buttonView.id) {
R.id.sb_at_all -> {
if (isChecked) {
binding!!.etToUser.setText("@all")
binding!!.layoutToUser.visibility = View.GONE
} else {
binding!!.etToUser.setText("")
binding!!.layoutToUser.visibility = View.VISIBLE
}
}
R.id.sb_proxyAuthenticator -> {
binding!!.layoutProxyAuthenticator.visibility = if (isChecked) View.VISIBLE else View.GONE
}
else -> {}
}
}

Expand Down Expand Up @@ -225,7 +252,26 @@ class WeworkAgentFragment : BaseFragment<FragmentSendersWeworkAgentBinding?>(),
val atAll = binding!!.sbAtAll.isChecked
val toUser = binding!!.etToUser.text.toString().trim()

return WeworkAgentSetting(corpID, agentID, secret, atAll, toUser)
val proxyType: Proxy.Type = when (binding!!.rgProxyType.checkedRadioButtonId) {
R.id.rb_proxyHttp -> Proxy.Type.HTTP
R.id.rb_proxySocks -> Proxy.Type.SOCKS
else -> Proxy.Type.DIRECT
}
val proxyHost = binding!!.etProxyHost.text.toString().trim()
val proxyPort = binding!!.etProxyPort.text.toString().trim()

if (proxyType != Proxy.Type.DIRECT && (TextUtils.isEmpty(proxyHost) || TextUtils.isEmpty(proxyPort))) {
throw Exception(getString(R.string.invalid_host_or_port))
}

val proxyAuthenticator = binding!!.sbProxyAuthenticator.isChecked
val proxyUsername = binding!!.etProxyUsername.text.toString().trim()
val proxyPassword = binding!!.etProxyPassword.text.toString().trim()
if (proxyAuthenticator && TextUtils.isEmpty(proxyUsername) && TextUtils.isEmpty(proxyPassword)) {
throw Exception(getString(R.string.invalid_username_or_password))
}

return WeworkAgentSetting(corpID, agentID, secret, atAll, toUser, proxyType, proxyHost, proxyPort, proxyAuthenticator, proxyUsername, proxyPassword)
}

override fun onDestroyView() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ import com.xuexiang.xhttp2.cache.model.CacheMode
import com.xuexiang.xhttp2.callback.SimpleCallBack
import com.xuexiang.xhttp2.exception.ApiException
import com.xuexiang.xui.utils.ResUtils.getString
import com.xuexiang.xutil.net.NetworkUtils
import okhttp3.Credentials
import okhttp3.Response
import okhttp3.Route
import java.net.Authenticator
import java.net.InetSocketAddress
import java.net.PasswordAuthentication
import java.net.Proxy

@Suppress("PrivatePropertyName", "UNUSED_PARAMETER")
class WeworkAgentUtils private constructor() {
Expand All @@ -42,8 +50,49 @@ class WeworkAgentUtils private constructor() {
getTokenUrl += "&corpsecret=" + setting.secret
Log.d(TAG, "getTokenUrl:$getTokenUrl")

XHttp.get(getTokenUrl)
.keepJson(true)
val request = XHttp.get(getTokenUrl)

//设置代理
if ((setting.proxyType == Proxy.Type.HTTP || setting.proxyType == Proxy.Type.SOCKS)
&& !TextUtils.isEmpty(setting.proxyHost) && !TextUtils.isEmpty(setting.proxyPort)
) {
//代理服务器的IP和端口号
Log.d(TAG, "proxyHost = ${setting.proxyHost}, proxyPort = ${setting.proxyPort}")
val proxyHost = if (NetworkUtils.isIP(setting.proxyHost)) setting.proxyHost else NetworkUtils.getDomainAddress(setting.proxyHost)
if (!NetworkUtils.isIP(proxyHost)) {
throw Exception("代理服务器主机名解析失败:proxyHost=$proxyHost")
}
val proxyPort: Int = setting.proxyPort?.toInt() ?: 7890

Log.d(TAG, "proxyHost = $proxyHost, proxyPort = $proxyPort")
request.okproxy(Proxy(setting.proxyType, InetSocketAddress(proxyHost, proxyPort)))

//代理的鉴权账号密码
if (setting.proxyAuthenticator == true
&& (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword))
) {
Log.i(TAG, "proxyUsername = ${setting.proxyUsername}, proxyPassword = ${setting.proxyPassword}")

if (setting.proxyType == Proxy.Type.HTTP) {
request.okproxyAuthenticator { _: Route?, response: Response ->
//设置代理服务器账号密码
val credential = Credentials.basic(setting.proxyUsername.toString(), setting.proxyPassword.toString())
response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build()
}
} else {
Authenticator.setDefault(object : Authenticator() {
override fun getPasswordAuthentication(): PasswordAuthentication {
return PasswordAuthentication(setting.proxyUsername.toString(), setting.proxyPassword?.toCharArray())
}
})
}
}
}

request.keepJson(true)
.ignoreHttpsCert()
.timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s
.cacheMode(CacheMode.NO_CACHE)
.timeStamp(true)
Expand Down Expand Up @@ -96,9 +145,50 @@ class WeworkAgentUtils private constructor() {
val requestMsg: String = Gson().toJson(textMsgMap)
Log.i(TAG, "requestMsg:$requestMsg")

XHttp.post(requestUrl)
.upJson(requestMsg)
val request = XHttp.post(requestUrl)

//设置代理
if ((setting.proxyType == Proxy.Type.HTTP || setting.proxyType == Proxy.Type.SOCKS)
&& !TextUtils.isEmpty(setting.proxyHost) && !TextUtils.isEmpty(setting.proxyPort)
) {
//代理服务器的IP和端口号
Log.d(TAG, "proxyHost = ${setting.proxyHost}, proxyPort = ${setting.proxyPort}")
val proxyHost = if (NetworkUtils.isIP(setting.proxyHost)) setting.proxyHost else NetworkUtils.getDomainAddress(setting.proxyHost)
if (!NetworkUtils.isIP(proxyHost)) {
throw Exception("代理服务器主机名解析失败:proxyHost=$proxyHost")
}
val proxyPort: Int = setting.proxyPort?.toInt() ?: 7890

Log.d(TAG, "proxyHost = $proxyHost, proxyPort = $proxyPort")
request.okproxy(Proxy(setting.proxyType, InetSocketAddress(proxyHost, proxyPort)))

//代理的鉴权账号密码
if (setting.proxyAuthenticator == true
&& (!TextUtils.isEmpty(setting.proxyUsername) || !TextUtils.isEmpty(setting.proxyPassword))
) {
Log.i(TAG, "proxyUsername = ${setting.proxyUsername}, proxyPassword = ${setting.proxyPassword}")

if (setting.proxyType == Proxy.Type.HTTP) {
request.okproxyAuthenticator { _: Route?, response: Response ->
//设置代理服务器账号密码
val credential = Credentials.basic(setting.proxyUsername.toString(), setting.proxyPassword.toString())
response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build()
}
} else {
Authenticator.setDefault(object : Authenticator() {
override fun getPasswordAuthentication(): PasswordAuthentication {
return PasswordAuthentication(setting.proxyUsername.toString(), setting.proxyPassword?.toCharArray())
}
})
}
}
}

request.upJson(requestMsg)
.keepJson(true)
.ignoreHttpsCert()
.timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s
.cacheMode(CacheMode.NO_CACHE)
.retryCount(SettingUtils.requestRetryTimes) //超时重试的次数
Expand Down
Loading

0 comments on commit 6ea06ed

Please sign in to comment.