diff --git a/app/src/main/java/com/idormy/sms/forwarder/service/ForegroundService.kt b/app/src/main/java/com/idormy/sms/forwarder/service/ForegroundService.kt index e3eb9116..1c08f5e1 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/service/ForegroundService.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/service/ForegroundService.kt @@ -1,174 +1,174 @@ -package com.idormy.sms.forwarder.service - -import android.app.* -import android.content.Intent -import android.graphics.BitmapFactory -import android.graphics.Color -import android.os.Build -import android.os.IBinder -import android.text.TextUtils -import android.util.Log -import androidx.core.app.NotificationCompat -import androidx.lifecycle.Observer -import com.idormy.sms.forwarder.App -import com.idormy.sms.forwarder.R -import com.idormy.sms.forwarder.activity.MainActivity -import com.idormy.sms.forwarder.database.AppDatabase -import com.idormy.sms.forwarder.utils.* -import com.jeremyliao.liveeventbus.LiveEventBus -import com.xuexiang.xutil.file.FileUtils -import frpclib.Frpclib -import io.reactivex.Single -import io.reactivex.SingleObserver -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.disposables.Disposable -import io.reactivex.schedulers.Schedulers -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.async - -@Suppress("PrivatePropertyName", "DeferredResultUnused", "OPT_IN_USAGE") -class ForegroundService : Service() { - private val TAG: String = "ForegroundService" - private val compositeDisposable = CompositeDisposable() - private val frpcObserver = Observer { uid: String -> - if (Frpclib.isRunning(uid)) { - return@Observer - } - AppDatabase.getInstance(App.context) - .frpcDao() - .get(uid) - .flatMap { (uid1, _, config) -> - val error = Frpclib.runContent(uid1, config) - Single.just(error) - } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : SingleObserver { - override fun onSubscribe(d: Disposable) { - compositeDisposable.add(d) - } - - override fun onError(e: Throwable) { - e.printStackTrace() - LiveEventBus.get(EVENT_FRPC_RUNNING_ERROR, String::class.java).post(uid) - } - - override fun onSuccess(msg: String) { - if (!TextUtils.isEmpty(msg)) { - Log.e(TAG, msg) - LiveEventBus.get(EVENT_FRPC_RUNNING_ERROR, String::class.java).post(uid) - } else { - LiveEventBus.get(EVENT_FRPC_RUNNING_SUCCESS, String::class.java).post(uid) - } - } - }) - } - private var notificationManager: NotificationManager? = null - - companion object { - var isRunning = false - } - - override fun onCreate() { - super.onCreate() - - try { - //纯客户端模式 - if (SettingUtils.enablePureClientMode) return - - notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager - startForeground(FRONT_NOTIFY_ID, createForegroundNotification()) - - //开关通知监听服务 - if (SettingUtils.enableAppNotify && CommonUtils.isNotificationListenerServiceEnabled(this)) { - CommonUtils.toggleNotificationListenerService(this) - } - - if (FileUtils.isFileExists(filesDir.absolutePath + "/libs/libgojni.so")) { - //监听Frpc启动指令 - LiveEventBus.get(INTENT_FRPC_APPLY_FILE, String::class.java).observeStickyForever(frpcObserver) - //自启动的Frpc - GlobalScope.async(Dispatchers.IO) { - val frpcList = AppDatabase.getInstance(App.context).frpcDao().getAutorun() - - if (frpcList.isEmpty()) { - Log.d(TAG, "没有自启动的Frpc") - return@async - } - - for (frpc in frpcList) { - val error = Frpclib.runContent(frpc.uid, frpc.config) - if (!TextUtils.isEmpty(error)) { - Log.e(TAG, error) - } - } - } - } - - isRunning = true - } catch (e: Exception) { - e.printStackTrace() - isRunning = false - } - - } - - override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { - isRunning = true - return START_STICKY - } - - override fun onDestroy() { - //纯客户端模式 - if (SettingUtils.enablePureClientMode) { - super.onDestroy() - return - } - - try { - stopForeground(true) - compositeDisposable.dispose() - isRunning = false - } catch (e: Exception) { - e.printStackTrace() - } - super.onDestroy() - } - - override fun onBind(intent: Intent): IBinder? { - return null - } - - private fun createForegroundNotification(): Notification { - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val importance = NotificationManager.IMPORTANCE_HIGH - val notificationChannel = NotificationChannel(FRONT_CHANNEL_ID, FRONT_CHANNEL_NAME, importance) - notificationChannel.description = "Frpc Foreground Service" - notificationChannel.enableLights(true) - notificationChannel.lightColor = Color.GREEN - notificationChannel.vibrationPattern = longArrayOf(0, 1000, 500, 1000) - notificationChannel.enableVibration(true) - if (notificationManager != null) { - notificationManager!!.createNotificationChannel(notificationChannel) - } - } - val builder = NotificationCompat.Builder(this, FRONT_CHANNEL_ID) - builder.setSmallIcon(R.drawable.ic_forwarder) - builder.setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.ic_menu_frpc)) - // TODO: 部分机型标题会重复待排除 - // if (DeviceUtils.getDeviceBrand().contains("Xiaomi")) { - builder.setContentTitle(getString(R.string.app_name)) - //} - builder.setContentText(SettingUtils.notifyContent.toString()) - builder.setWhen(System.currentTimeMillis()) - val activityIntent = Intent(this, MainActivity::class.java) - val flags = if (Build.VERSION.SDK_INT >= 30) PendingIntent.FLAG_IMMUTABLE else PendingIntent.FLAG_UPDATE_CURRENT - val pendingIntent = PendingIntent.getActivity(this, 0, activityIntent, flags) - builder.setContentIntent(pendingIntent) - return builder.build() - } - +package com.idormy.sms.forwarder.service + +import android.app.* +import android.content.Intent +import android.graphics.BitmapFactory +import android.graphics.Color +import android.os.Build +import android.os.IBinder +import android.text.TextUtils +import android.util.Log +import androidx.core.app.NotificationCompat +import androidx.lifecycle.Observer +import com.idormy.sms.forwarder.App +import com.idormy.sms.forwarder.R +import com.idormy.sms.forwarder.activity.MainActivity +import com.idormy.sms.forwarder.database.AppDatabase +import com.idormy.sms.forwarder.utils.* +import com.jeremyliao.liveeventbus.LiveEventBus +import com.xuexiang.xutil.file.FileUtils +import frpclib.Frpclib +import io.reactivex.Single +import io.reactivex.SingleObserver +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.async + +@Suppress("PrivatePropertyName", "DeferredResultUnused", "OPT_IN_USAGE") +class ForegroundService : Service() { + private val TAG: String = "ForegroundService" + private val compositeDisposable = CompositeDisposable() + private val frpcObserver = Observer { uid: String -> + if (Frpclib.isRunning(uid)) { + return@Observer + } + AppDatabase.getInstance(App.context) + .frpcDao() + .get(uid) + .flatMap { (uid1, _, config) -> + val error = Frpclib.runContent(uid1, config) + Single.just(error) + } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : SingleObserver { + override fun onSubscribe(d: Disposable) { + compositeDisposable.add(d) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + LiveEventBus.get(EVENT_FRPC_RUNNING_ERROR, String::class.java).post(uid) + } + + override fun onSuccess(msg: String) { + if (!TextUtils.isEmpty(msg)) { + Log.e(TAG, msg) + LiveEventBus.get(EVENT_FRPC_RUNNING_ERROR, String::class.java).post(uid) + } else { + LiveEventBus.get(EVENT_FRPC_RUNNING_SUCCESS, String::class.java).post(uid) + } + } + }) + } + private var notificationManager: NotificationManager? = null + + companion object { + var isRunning = false + } + + override fun onCreate() { + super.onCreate() + + try { + //纯客户端模式 + if (SettingUtils.enablePureClientMode) return + + notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager + startForeground(FRONT_NOTIFY_ID, createForegroundNotification()) + + //开关通知监听服务 + if (SettingUtils.enableAppNotify && CommonUtils.isNotificationListenerServiceEnabled(this)) { + CommonUtils.toggleNotificationListenerService(this) + } + + if (FileUtils.isFileExists(filesDir.absolutePath + "/libs/libgojni.so")) { + //监听Frpc启动指令 + LiveEventBus.get(INTENT_FRPC_APPLY_FILE, String::class.java).observeStickyForever(frpcObserver) + //自启动的Frpc + GlobalScope.async(Dispatchers.IO) { + val frpcList = AppDatabase.getInstance(App.context).frpcDao().getAutorun() + + if (frpcList.isEmpty()) { + Log.d(TAG, "没有自启动的Frpc") + return@async + } + + for (frpc in frpcList) { + val error = Frpclib.runContent(frpc.uid, frpc.config) + if (!TextUtils.isEmpty(error)) { + Log.e(TAG, error) + } + } + } + } + + isRunning = true + } catch (e: Exception) { + e.printStackTrace() + isRunning = false + } + + } + + override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { + isRunning = true + return START_STICKY + } + + override fun onDestroy() { + //纯客户端模式 + if (SettingUtils.enablePureClientMode) { + super.onDestroy() + return + } + + try { + stopForeground(true) + compositeDisposable.dispose() + isRunning = false + } catch (e: Exception) { + e.printStackTrace() + } + super.onDestroy() + } + + override fun onBind(intent: Intent): IBinder? { + return null + } + + private fun createForegroundNotification(): Notification { + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val importance = NotificationManager.IMPORTANCE_HIGH + val notificationChannel = NotificationChannel(FRONT_CHANNEL_ID, FRONT_CHANNEL_NAME, importance) + notificationChannel.description = "Frpc Foreground Service" + notificationChannel.enableLights(true) + notificationChannel.lightColor = Color.GREEN + notificationChannel.vibrationPattern = longArrayOf(0, 1000, 500, 1000) + notificationChannel.enableVibration(true) + if (notificationManager != null) { + notificationManager!!.createNotificationChannel(notificationChannel) + } + } + val builder = NotificationCompat.Builder(this, FRONT_CHANNEL_ID) + builder.setSmallIcon(R.drawable.ic_forwarder) + builder.setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.ic_menu_frpc)) + // TODO: 部分机型标题会重复待排除 + // if (DeviceUtils.getDeviceBrand().contains("Xiaomi")) { + builder.setContentTitle(getString(R.string.app_name)) + //} + builder.setContentText(SettingUtils.notifyContent) + builder.setWhen(System.currentTimeMillis()) + val activityIntent = Intent(this, MainActivity::class.java) + val flags = if (Build.VERSION.SDK_INT >= 30) PendingIntent.FLAG_IMMUTABLE else PendingIntent.FLAG_UPDATE_CURRENT + val pendingIntent = PendingIntent.getActivity(this, 0, activityIntent, flags) + builder.setContentIntent(pendingIntent) + return builder.build() + } + } \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/BarkUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/BarkUtils.kt index fb98a91a..e195b8c5 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/BarkUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/BarkUtils.kt @@ -35,7 +35,7 @@ class BarkUtils { val content: String = if (rule != null) { msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) } else { - msgInfo.getContentForSend(SettingUtils.smsTemplate.toString()) + msgInfo.getContentForSend(SettingUtils.smsTemplate) } val requestUrl: String = setting.server //推送地址 diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkGroupRobotUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkGroupRobotUtils.kt index b6f6f319..a8e95c60 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkGroupRobotUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkGroupRobotUtils.kt @@ -35,7 +35,7 @@ class DingtalkGroupRobotUtils private constructor() { val content: String = if (rule != null) { msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) } else { - msgInfo.getContentForSend(SettingUtils.smsTemplate.toString()) + msgInfo.getContentForSend(SettingUtils.smsTemplate) } var requestUrl = if (setting.token.startsWith("http")) setting.token else "https://oapi.dingtalk.com/robot/send?access_token=" + setting.token diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkInnerRobotUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkInnerRobotUtils.kt index e3958c57..5cbf9a38 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkInnerRobotUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkInnerRobotUtils.kt @@ -126,7 +126,7 @@ class DingtalkInnerRobotUtils private constructor() { val content: String = if (rule != null) { msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) } else { - msgInfo.getContentForSend(SettingUtils.smsTemplate.toString()) + msgInfo.getContentForSend(SettingUtils.smsTemplate) } val msgParam: MutableMap = mutableMapOf() diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/EmailUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/EmailUtils.kt index 942b1eba..2b233f3f 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/EmailUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/EmailUtils.kt @@ -1,151 +1,151 @@ -package com.idormy.sms.forwarder.utils.sender - -import android.util.Log -import com.idormy.sms.forwarder.R -import com.idormy.sms.forwarder.database.entity.Rule -import com.idormy.sms.forwarder.entity.MsgInfo -import com.idormy.sms.forwarder.entity.setting.EmailSetting -import com.idormy.sms.forwarder.utils.SendUtils -import com.idormy.sms.forwarder.utils.SettingUtils -import com.idormy.sms.forwarder.utils.mail.Mail -import com.idormy.sms.forwarder.utils.mail.MailSender -import com.xuexiang.xui.utils.ResUtils - -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") -class EmailUtils { - companion object { - - private val TAG: String = EmailUtils::class.java.simpleName - - fun sendMsg( - setting: EmailSetting, - msgInfo: MsgInfo, - rule: Rule?, - logId: Long?, - ) { - val title: String = if (rule != null) { - msgInfo.getTitleForSend(setting.title.toString(), rule.regexReplace) - } else { - msgInfo.getTitleForSend(setting.title.toString()) - } - val message: String = if (rule != null) { - msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) - } else { - msgInfo.getContentForSend(SettingUtils.smsTemplate.toString()) - } - - //常用邮箱类型的转换 - when (setting.mailType) { - "@qq.com", "@foxmail.com" -> { - setting.host = "smtp.qq.com" - setting.port = "465" - setting.ssl = true - setting.fromEmail += setting.mailType - } - "@exmail.qq.com" -> { - setting.host = "smtp.exmail.qq.com" - setting.port = "465" - setting.ssl = true - setting.fromEmail += setting.mailType - } - "@msn.com" -> { - setting.host = "smtp-mail.outlook.com" - setting.port = "587" - setting.ssl = false - setting.startTls = true - setting.fromEmail += setting.mailType - } - "@outlook.com", "@office365.com", "@live.com", "@hotmail.com" -> { - setting.host = "smtp.office365.com" - setting.port = "587" - setting.ssl = false - setting.startTls = true - setting.fromEmail += setting.mailType - } - "@gmail.com" -> { - setting.host = "smtp.gmail.com" - setting.port = "587" - setting.ssl = true - setting.startTls = true - setting.fromEmail += setting.mailType - } - "@yeah.net" -> { - setting.host = "smtp.yeah.net" - setting.port = "465" - setting.ssl = true - setting.fromEmail += setting.mailType - } - "@163.com" -> { - setting.host = "smtp.163.com" - setting.port = "465" - setting.ssl = true - setting.fromEmail += setting.mailType - } - "@126.com" -> { - setting.host = "smtp.126.com" - setting.port = "465" - setting.ssl = true - setting.fromEmail += setting.mailType - } - "@sina.com" -> { - setting.host = "smtp.sina.com" - setting.port = "465" - setting.ssl = true - setting.fromEmail += setting.mailType - } - "@sina.cn" -> { - setting.host = "smtp.sina.cn" - setting.port = "465" - setting.ssl = true - setting.fromEmail += setting.mailType - } - "@139.com" -> { - setting.host = "smtp.139.com" - setting.port = "465" - setting.ssl = true - setting.fromEmail += setting.mailType - } - "@189.cn" -> { - setting.host = "smtp.189.cn" - setting.port = "465" - setting.ssl = true - setting.fromEmail += setting.mailType - } - else -> {} - } - - //收件地址 - val toAddressList = setting.toEmail.toString().replace("[,,;;]".toRegex(), ",").trim(',').split(',') - - //创建邮箱 - val mail = Mail().apply { - mailServerHost = setting.host.toString() - mailServerPort = setting.port.toString() - fromAddress = setting.fromEmail.toString() - fromNickname = msgInfo.getTitleForSend(setting.nickname.toString()) - password = setting.pwd.toString() - toAddress = toAddressList - subject = title - content = message.replace("\n", "
") - openSSL = setting.ssl == true - startTls = setting.startTls == true - } - - MailSender.getInstance().sendMail(mail, object : MailSender.OnMailSendListener { - override fun onError(e: Throwable) { - Log.e("MailSender", e.message.toString()) - SendUtils.updateLogs(logId, 0, e.message.toString()) - } - - override fun onSuccess() { - SendUtils.updateLogs(logId, 2, ResUtils.getString(R.string.request_succeeded)) - } - }) - - } - - fun sendMsg(setting: EmailSetting, msgInfo: MsgInfo) { - sendMsg(setting, msgInfo, null, null) - } - } +package com.idormy.sms.forwarder.utils.sender + +import android.util.Log +import com.idormy.sms.forwarder.R +import com.idormy.sms.forwarder.database.entity.Rule +import com.idormy.sms.forwarder.entity.MsgInfo +import com.idormy.sms.forwarder.entity.setting.EmailSetting +import com.idormy.sms.forwarder.utils.SendUtils +import com.idormy.sms.forwarder.utils.SettingUtils +import com.idormy.sms.forwarder.utils.mail.Mail +import com.idormy.sms.forwarder.utils.mail.MailSender +import com.xuexiang.xui.utils.ResUtils + +@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") +class EmailUtils { + companion object { + + private val TAG: String = EmailUtils::class.java.simpleName + + fun sendMsg( + setting: EmailSetting, + msgInfo: MsgInfo, + rule: Rule?, + logId: Long?, + ) { + val title: String = if (rule != null) { + msgInfo.getTitleForSend(setting.title.toString(), rule.regexReplace) + } else { + msgInfo.getTitleForSend(setting.title.toString()) + } + val message: String = if (rule != null) { + msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) + } else { + msgInfo.getContentForSend(SettingUtils.smsTemplate) + } + + //常用邮箱类型的转换 + when (setting.mailType) { + "@qq.com", "@foxmail.com" -> { + setting.host = "smtp.qq.com" + setting.port = "465" + setting.ssl = true + setting.fromEmail += setting.mailType + } + "@exmail.qq.com" -> { + setting.host = "smtp.exmail.qq.com" + setting.port = "465" + setting.ssl = true + setting.fromEmail += setting.mailType + } + "@msn.com" -> { + setting.host = "smtp-mail.outlook.com" + setting.port = "587" + setting.ssl = false + setting.startTls = true + setting.fromEmail += setting.mailType + } + "@outlook.com", "@office365.com", "@live.com", "@hotmail.com" -> { + setting.host = "smtp.office365.com" + setting.port = "587" + setting.ssl = false + setting.startTls = true + setting.fromEmail += setting.mailType + } + "@gmail.com" -> { + setting.host = "smtp.gmail.com" + setting.port = "587" + setting.ssl = true + setting.startTls = true + setting.fromEmail += setting.mailType + } + "@yeah.net" -> { + setting.host = "smtp.yeah.net" + setting.port = "465" + setting.ssl = true + setting.fromEmail += setting.mailType + } + "@163.com" -> { + setting.host = "smtp.163.com" + setting.port = "465" + setting.ssl = true + setting.fromEmail += setting.mailType + } + "@126.com" -> { + setting.host = "smtp.126.com" + setting.port = "465" + setting.ssl = true + setting.fromEmail += setting.mailType + } + "@sina.com" -> { + setting.host = "smtp.sina.com" + setting.port = "465" + setting.ssl = true + setting.fromEmail += setting.mailType + } + "@sina.cn" -> { + setting.host = "smtp.sina.cn" + setting.port = "465" + setting.ssl = true + setting.fromEmail += setting.mailType + } + "@139.com" -> { + setting.host = "smtp.139.com" + setting.port = "465" + setting.ssl = true + setting.fromEmail += setting.mailType + } + "@189.cn" -> { + setting.host = "smtp.189.cn" + setting.port = "465" + setting.ssl = true + setting.fromEmail += setting.mailType + } + else -> {} + } + + //收件地址 + val toAddressList = setting.toEmail.toString().replace("[,,;;]".toRegex(), ",").trim(',').split(',') + + //创建邮箱 + val mail = Mail().apply { + mailServerHost = setting.host.toString() + mailServerPort = setting.port.toString() + fromAddress = setting.fromEmail.toString() + fromNickname = msgInfo.getTitleForSend(setting.nickname.toString()) + password = setting.pwd.toString() + toAddress = toAddressList + subject = title + content = message.replace("\n", "
") + openSSL = setting.ssl == true + startTls = setting.startTls == true + } + + MailSender.getInstance().sendMail(mail, object : MailSender.OnMailSendListener { + override fun onError(e: Throwable) { + Log.e("MailSender", e.message.toString()) + SendUtils.updateLogs(logId, 0, e.message.toString()) + } + + override fun onSuccess() { + SendUtils.updateLogs(logId, 2, ResUtils.getString(R.string.request_succeeded)) + } + }) + + } + + fun sendMsg(setting: EmailSetting, msgInfo: MsgInfo) { + sendMsg(setting, msgInfo, null, null) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuAppUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuAppUtils.kt index f2ccc898..f8353d0c 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuAppUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuAppUtils.kt @@ -84,7 +84,7 @@ class FeishuAppUtils private constructor() { val content: String = if (rule != null) { msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) } else { - msgInfo.getContentForSend(SettingUtils.smsTemplate.toString()) + msgInfo.getContentForSend(SettingUtils.smsTemplate) } val msgContent = if ("interactive" == setting.msgType) { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuUtils.kt index f8e14944..7268c6c0 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuUtils.kt @@ -94,7 +94,7 @@ class FeishuUtils private constructor() { val content: String = if (rule != null) { msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) } else { - msgInfo.getContentForSend(SettingUtils.smsTemplate.toString()) + msgInfo.getContentForSend(SettingUtils.smsTemplate) } val requestUrl = setting.webhook diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/GotifyUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/GotifyUtils.kt index 53f5c9ce..52b797e7 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/GotifyUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/GotifyUtils.kt @@ -1,89 +1,89 @@ -package com.idormy.sms.forwarder.utils.sender - -import android.util.Log -import com.google.gson.Gson -import com.idormy.sms.forwarder.database.entity.Rule -import com.idormy.sms.forwarder.entity.MsgInfo -import com.idormy.sms.forwarder.entity.result.GotifyResult -import com.idormy.sms.forwarder.entity.setting.GotifySetting -import com.idormy.sms.forwarder.utils.SendUtils -import com.idormy.sms.forwarder.utils.SettingUtils -import com.xuexiang.xhttp2.XHttp -import com.xuexiang.xhttp2.cache.model.CacheMode -import com.xuexiang.xhttp2.callback.SimpleCallBack -import com.xuexiang.xhttp2.exception.ApiException - -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") -class GotifyUtils { - companion object { - - private val TAG: String = GotifyUtils::class.java.simpleName - - fun sendMsg( - setting: GotifySetting, - msgInfo: MsgInfo, - rule: Rule?, - logId: Long?, - ) { - val title: String = if (rule != null) { - msgInfo.getTitleForSend(setting.title.toString(), rule.regexReplace) - } else { - msgInfo.getTitleForSend(setting.title.toString()) - } - val content: String = if (rule != null) { - msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) - } else { - msgInfo.getContentForSend(SettingUtils.smsTemplate.toString()) - } - - val requestUrl: String = setting.webServer //推送地址 - Log.i(TAG, "requestUrl:$requestUrl") - - //支持HTTP基本认证(Basic Authentication) - val regex = "^(https?://)([^:]+):([^@]+)@(.+)" - val matches = Regex(regex, RegexOption.IGNORE_CASE).findAll(requestUrl).toList().flatMap(MatchResult::groupValues) - Log.i(TAG, "matches = $matches") - val request = if (matches.isNotEmpty()) { - XHttp.post(matches[1] + matches[4]).addInterceptor(BasicAuthInterceptor(matches[2], matches[3])) - } else { - XHttp.post(requestUrl) - } - - request.params("title", title) - .params("message", content) - .params("priority", setting.priority) - .ignoreHttpsCert() //忽略https证书 - .keepJson(true) - .timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s - .cacheMode(CacheMode.NO_CACHE) - .retryCount(SettingUtils.requestRetryTimes) //超时重试的次数 - .retryDelay(SettingUtils.requestDelayTime) //超时重试的延迟时间 - .retryIncreaseDelay(SettingUtils.requestDelayTime) //超时重试叠加延时 - .timeStamp(true) - .execute(object : SimpleCallBack() { - - override fun onError(e: ApiException) { - Log.e(TAG, e.detailMessage) - SendUtils.updateLogs(logId, 0, e.displayMessage) - } - - override fun onSuccess(response: String) { - Log.i(TAG, response) - - val resp = Gson().fromJson(response, GotifyResult::class.java) - if (resp?.id != null) { - SendUtils.updateLogs(logId, 2, response) - } else { - SendUtils.updateLogs(logId, 0, response) - } - } - - }) - - } - - fun sendMsg(setting: GotifySetting, msgInfo: MsgInfo) { - sendMsg(setting, msgInfo, null, null) - } - } +package com.idormy.sms.forwarder.utils.sender + +import android.util.Log +import com.google.gson.Gson +import com.idormy.sms.forwarder.database.entity.Rule +import com.idormy.sms.forwarder.entity.MsgInfo +import com.idormy.sms.forwarder.entity.result.GotifyResult +import com.idormy.sms.forwarder.entity.setting.GotifySetting +import com.idormy.sms.forwarder.utils.SendUtils +import com.idormy.sms.forwarder.utils.SettingUtils +import com.xuexiang.xhttp2.XHttp +import com.xuexiang.xhttp2.cache.model.CacheMode +import com.xuexiang.xhttp2.callback.SimpleCallBack +import com.xuexiang.xhttp2.exception.ApiException + +@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") +class GotifyUtils { + companion object { + + private val TAG: String = GotifyUtils::class.java.simpleName + + fun sendMsg( + setting: GotifySetting, + msgInfo: MsgInfo, + rule: Rule?, + logId: Long?, + ) { + val title: String = if (rule != null) { + msgInfo.getTitleForSend(setting.title.toString(), rule.regexReplace) + } else { + msgInfo.getTitleForSend(setting.title.toString()) + } + val content: String = if (rule != null) { + msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) + } else { + msgInfo.getContentForSend(SettingUtils.smsTemplate) + } + + val requestUrl: String = setting.webServer //推送地址 + Log.i(TAG, "requestUrl:$requestUrl") + + //支持HTTP基本认证(Basic Authentication) + val regex = "^(https?://)([^:]+):([^@]+)@(.+)" + val matches = Regex(regex, RegexOption.IGNORE_CASE).findAll(requestUrl).toList().flatMap(MatchResult::groupValues) + Log.i(TAG, "matches = $matches") + val request = if (matches.isNotEmpty()) { + XHttp.post(matches[1] + matches[4]).addInterceptor(BasicAuthInterceptor(matches[2], matches[3])) + } else { + XHttp.post(requestUrl) + } + + request.params("title", title) + .params("message", content) + .params("priority", setting.priority) + .ignoreHttpsCert() //忽略https证书 + .keepJson(true) + .timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s + .cacheMode(CacheMode.NO_CACHE) + .retryCount(SettingUtils.requestRetryTimes) //超时重试的次数 + .retryDelay(SettingUtils.requestDelayTime) //超时重试的延迟时间 + .retryIncreaseDelay(SettingUtils.requestDelayTime) //超时重试叠加延时 + .timeStamp(true) + .execute(object : SimpleCallBack() { + + override fun onError(e: ApiException) { + Log.e(TAG, e.detailMessage) + SendUtils.updateLogs(logId, 0, e.displayMessage) + } + + override fun onSuccess(response: String) { + Log.i(TAG, response) + + val resp = Gson().fromJson(response, GotifyResult::class.java) + if (resp?.id != null) { + SendUtils.updateLogs(logId, 2, response) + } else { + SendUtils.updateLogs(logId, 0, response) + } + } + + }) + + } + + fun sendMsg(setting: GotifySetting, msgInfo: MsgInfo) { + sendMsg(setting, msgInfo, null, null) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/PushplusUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/PushplusUtils.kt index b2322efe..4d5a0644 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/PushplusUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/PushplusUtils.kt @@ -37,7 +37,7 @@ class PushplusUtils private constructor() { val content: String = if (rule != null) { msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) } else { - msgInfo.getContentForSend(SettingUtils.smsTemplate.toString()) + msgInfo.getContentForSend(SettingUtils.smsTemplate) } val requestUrl = "https://" + setting.website + "/send" @@ -63,7 +63,6 @@ class PushplusUtils private constructor() { } } - val requestMsg: String = Gson().toJson(msgMap) Log.i(TAG, "requestMsg:$requestMsg") diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/ServerchanUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/ServerchanUtils.kt index 058bdeb2..5269345d 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/ServerchanUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/ServerchanUtils.kt @@ -1,83 +1,83 @@ -package com.idormy.sms.forwarder.utils.sender - -import android.text.TextUtils -import android.util.Log -import com.google.gson.Gson -import com.idormy.sms.forwarder.database.entity.Rule -import com.idormy.sms.forwarder.entity.MsgInfo -import com.idormy.sms.forwarder.entity.result.ServerchanResult -import com.idormy.sms.forwarder.entity.setting.ServerchanSetting -import com.idormy.sms.forwarder.utils.SendUtils -import com.idormy.sms.forwarder.utils.SettingUtils -import com.xuexiang.xhttp2.XHttp -import com.xuexiang.xhttp2.cache.model.CacheMode -import com.xuexiang.xhttp2.callback.SimpleCallBack -import com.xuexiang.xhttp2.exception.ApiException - -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") -class ServerchanUtils { - companion object { - - private val TAG: String = ServerchanUtils::class.java.simpleName - - fun sendMsg( - setting: ServerchanSetting, - msgInfo: MsgInfo, - rule: Rule?, - logId: Long?, - ) { - val title: String = if (rule != null) { - msgInfo.getTitleForSend(setting.titleTemplate.toString(), rule.regexReplace) - } else { - msgInfo.getTitleForSend(setting.titleTemplate.toString()) - } - val content: String = if (rule != null) { - msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) - } else { - msgInfo.getContentForSend(SettingUtils.smsTemplate.toString()) - } - - val requestUrl: String = String.format("https://sctapi.ftqq.com/%s.send", setting.sendKey) //推送地址 - Log.i(TAG, "requestUrl:$requestUrl") - - val request = XHttp.post(requestUrl) - .params("title", title) - .params("desp", content) - - if (!TextUtils.isEmpty(setting.channel)) request.params("channel", setting.channel) - if (!TextUtils.isEmpty(setting.openid)) request.params("group", setting.openid) - - request.keepJson(true) - .timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s - .cacheMode(CacheMode.NO_CACHE) - .retryCount(SettingUtils.requestRetryTimes) //超时重试的次数 - .retryDelay(SettingUtils.requestDelayTime) //超时重试的延迟时间 - .retryIncreaseDelay(SettingUtils.requestDelayTime) //超时重试叠加延时 - .timeStamp(true) - .execute(object : SimpleCallBack() { - - override fun onError(e: ApiException) { - Log.e(TAG, e.detailMessage) - SendUtils.updateLogs(logId, 0, e.displayMessage) - } - - override fun onSuccess(response: String) { - Log.i(TAG, response) - - val resp = Gson().fromJson(response, ServerchanResult::class.java) - if (resp?.code == 0L) { - SendUtils.updateLogs(logId, 2, response) - } else { - SendUtils.updateLogs(logId, 0, response) - } - } - - }) - - } - - fun sendMsg(setting: ServerchanSetting, msgInfo: MsgInfo) { - sendMsg(setting, msgInfo, null, null) - } - } +package com.idormy.sms.forwarder.utils.sender + +import android.text.TextUtils +import android.util.Log +import com.google.gson.Gson +import com.idormy.sms.forwarder.database.entity.Rule +import com.idormy.sms.forwarder.entity.MsgInfo +import com.idormy.sms.forwarder.entity.result.ServerchanResult +import com.idormy.sms.forwarder.entity.setting.ServerchanSetting +import com.idormy.sms.forwarder.utils.SendUtils +import com.idormy.sms.forwarder.utils.SettingUtils +import com.xuexiang.xhttp2.XHttp +import com.xuexiang.xhttp2.cache.model.CacheMode +import com.xuexiang.xhttp2.callback.SimpleCallBack +import com.xuexiang.xhttp2.exception.ApiException + +@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") +class ServerchanUtils { + companion object { + + private val TAG: String = ServerchanUtils::class.java.simpleName + + fun sendMsg( + setting: ServerchanSetting, + msgInfo: MsgInfo, + rule: Rule?, + logId: Long?, + ) { + val title: String = if (rule != null) { + msgInfo.getTitleForSend(setting.titleTemplate.toString(), rule.regexReplace) + } else { + msgInfo.getTitleForSend(setting.titleTemplate.toString()) + } + val content: String = if (rule != null) { + msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) + } else { + msgInfo.getContentForSend(SettingUtils.smsTemplate) + } + + val requestUrl: String = String.format("https://sctapi.ftqq.com/%s.send", setting.sendKey) //推送地址 + Log.i(TAG, "requestUrl:$requestUrl") + + val request = XHttp.post(requestUrl) + .params("title", title) + .params("desp", content) + + if (!TextUtils.isEmpty(setting.channel)) request.params("channel", setting.channel) + if (!TextUtils.isEmpty(setting.openid)) request.params("group", setting.openid) + + request.keepJson(true) + .timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s + .cacheMode(CacheMode.NO_CACHE) + .retryCount(SettingUtils.requestRetryTimes) //超时重试的次数 + .retryDelay(SettingUtils.requestDelayTime) //超时重试的延迟时间 + .retryIncreaseDelay(SettingUtils.requestDelayTime) //超时重试叠加延时 + .timeStamp(true) + .execute(object : SimpleCallBack() { + + override fun onError(e: ApiException) { + Log.e(TAG, e.detailMessage) + SendUtils.updateLogs(logId, 0, e.displayMessage) + } + + override fun onSuccess(response: String) { + Log.i(TAG, response) + + val resp = Gson().fromJson(response, ServerchanResult::class.java) + if (resp?.code == 0L) { + SendUtils.updateLogs(logId, 2, response) + } else { + SendUtils.updateLogs(logId, 0, response) + } + } + + }) + + } + + fun sendMsg(setting: ServerchanSetting, msgInfo: MsgInfo) { + sendMsg(setting, msgInfo, null, null) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/TelegramUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/TelegramUtils.kt index a44b0f91..6db91de8 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/TelegramUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/TelegramUtils.kt @@ -40,7 +40,7 @@ class TelegramUtils private constructor() { val content: String = if (rule != null) { msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) } else { - msgInfo.getContentForSend(SettingUtils.smsTemplate.toString()) + msgInfo.getContentForSend(SettingUtils.smsTemplate) } var requestUrl = if (setting.apiToken.startsWith("http")) { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WebhookUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WebhookUtils.kt index 7f937eda..05906d24 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WebhookUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WebhookUtils.kt @@ -1,209 +1,209 @@ -package com.idormy.sms.forwarder.utils.sender - -import android.annotation.SuppressLint -import android.text.TextUtils -import android.util.Base64 -import android.util.Log -import com.google.gson.Gson -import com.idormy.sms.forwarder.database.entity.Rule -import com.idormy.sms.forwarder.entity.MsgInfo -import com.idormy.sms.forwarder.entity.setting.WebhookSetting -import com.idormy.sms.forwarder.utils.SendUtils -import com.idormy.sms.forwarder.utils.SettingUtils -import com.xuexiang.xhttp2.XHttp -import com.xuexiang.xhttp2.cache.model.CacheMode -import com.xuexiang.xhttp2.callback.SimpleCallBack -import com.xuexiang.xhttp2.exception.ApiException -import com.xuexiang.xutil.app.AppUtils -import java.net.URLEncoder -import java.nio.charset.StandardCharsets -import java.text.SimpleDateFormat -import java.util.* -import javax.crypto.Mac -import javax.crypto.spec.SecretKeySpec - -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") -class WebhookUtils { - companion object { - - private val TAG: String = WebhookUtils::class.java.simpleName - - fun sendMsg( - setting: WebhookSetting, - msgInfo: MsgInfo, - rule: Rule?, - logId: Long?, - ) { - val from: String = msgInfo.from - val content: String = if (rule != null) { - msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) - } else { - msgInfo.getContentForSend(SettingUtils.smsTemplate.toString()) - } - - var requestUrl: String = setting.webServer //推送地址 - Log.i(TAG, "requestUrl:$requestUrl") - - val timestamp = System.currentTimeMillis() - val orgContent: String = msgInfo.content - val deviceMark: String = SettingUtils.extraDeviceMark ?: "" - val appVersion: String = AppUtils.getAppVersionName() - val simInfo: String = msgInfo.simInfo - @SuppressLint("SimpleDateFormat") val receiveTime = - SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date()) //smsVo.getDate() - - var sign = "" - if (!TextUtils.isEmpty(setting.secret)) { - val stringToSign = "$timestamp\n" + setting.secret - val mac = Mac.getInstance("HmacSHA256") - mac.init( - SecretKeySpec( - setting.secret?.toByteArray(StandardCharsets.UTF_8), - "HmacSHA256" - ) - ) - val signData = mac.doFinal(stringToSign.toByteArray(StandardCharsets.UTF_8)) - sign = URLEncoder.encode(String(Base64.encode(signData, Base64.NO_WRAP)), "UTF-8") - } - - var webParams = setting.webParams?.trim() - - //支持HTTP基本认证(Basic Authentication) - val regex = "^(https?://)([^:]+):([^@]+)@(.+)" - val matches = Regex(regex, RegexOption.IGNORE_CASE).findAll(requestUrl).toList() - .flatMap(MatchResult::groupValues) - Log.i(TAG, "matches = $matches") - if (matches.isNotEmpty()) { - requestUrl = matches[1] + matches[4] - Log.i(TAG, "requestUrl:$requestUrl") - } - - val request = if (setting.method == "GET" && TextUtils.isEmpty(webParams)) { - setting.webServer += (if (setting.webServer.contains("?")) "&" else "?") + "from=" + URLEncoder.encode( - from, - "UTF-8" - ) - requestUrl += "&content=" + URLEncoder.encode(content, "UTF-8") - if (!TextUtils.isEmpty(sign)) { - requestUrl += "×tamp=$timestamp" - requestUrl += "&sign=$sign" - } - Log.d(TAG, "method = GET, Url = $requestUrl") - XHttp.get(requestUrl).keepJson(true) - } else if (setting.method == "GET" && !TextUtils.isEmpty(webParams)) { - webParams = webParams.toString().replace("[from]", URLEncoder.encode(from, "UTF-8")) - .replace("[content]", URLEncoder.encode(content, "UTF-8")) - .replace("[msg]", URLEncoder.encode(content, "UTF-8")) - .replace("[org_content]", URLEncoder.encode(orgContent, "UTF-8")) - .replace("[device_mark]", URLEncoder.encode(deviceMark, "UTF-8")) - .replace("[app_version]", URLEncoder.encode(appVersion, "UTF-8")) - .replace("[title]", URLEncoder.encode(simInfo, "UTF-8")) - .replace("[card_slot]", URLEncoder.encode(simInfo, "UTF-8")) - .replace("[receive_time]", URLEncoder.encode(receiveTime, "UTF-8")) - .replace("\n", "%0A") - if (!TextUtils.isEmpty(setting.secret)) { - webParams = webParams.replace("[timestamp]", timestamp.toString()) - .replace("[sign]", URLEncoder.encode(sign, "UTF-8")) - } - requestUrl += if (webParams.startsWith("/")) { - webParams - } else { - (if (requestUrl.contains("?")) "&" else "?") + webParams - } - Log.d(TAG, "method = GET, Url = $requestUrl") - XHttp.get(requestUrl).keepJson(true) - } else if (webParams != null && webParams.isNotEmpty() && webParams.startsWith("{")) { - val bodyMsg = webParams.replace("[from]", from) - .replace("[content]", escapeJson(content)) - .replace("[msg]", escapeJson(content)) - .replace("[org_content]", escapeJson(orgContent)) - .replace("[device_mark]", escapeJson(deviceMark)) - .replace("[app_version]", appVersion) - .replace("[title]", escapeJson(simInfo)) - .replace("[card_slot]", escapeJson(simInfo)) - .replace("[receive_time]", receiveTime) - .replace("[timestamp]", timestamp.toString()) - .replace("[sign]", sign) - Log.d(TAG, "method = ${setting.method}, Url = $requestUrl, bodyMsg = $bodyMsg") - when (setting.method) { - "PUT" -> XHttp.put(requestUrl).keepJson(true).upJson(bodyMsg) - "PATCH" -> XHttp.patch(requestUrl).keepJson(true).upJson(bodyMsg) - else -> XHttp.post(requestUrl).keepJson(true).upJson(bodyMsg) - } - } else { - if (webParams == null || webParams.isEmpty()) { - webParams = "from=[from]&content=[content]×tamp=[timestamp]" - if (!TextUtils.isEmpty(sign)) webParams += "&sign=[sign]" - } - Log.d(TAG, "method = ${setting.method}, Url = $requestUrl") - val postRequest = when (setting.method) { - "PUT" -> XHttp.put(requestUrl).keepJson(true) - "PATCH" -> XHttp.patch(requestUrl).keepJson(true) - else -> XHttp.post(requestUrl).keepJson(true) - } - webParams.trim('&').split("&").forEach { - val param = it.split("=") - if (param.size == 2) { - postRequest.params( - param[0], param[1].replace("[from]", from) - .replace("[content]", content) - .replace("[msg]", content) - .replace("[org_content]", orgContent) - .replace("[device_mark]", deviceMark) - .replace("[app_version]", appVersion) - .replace("[title]", simInfo) - .replace("[card_slot]", simInfo) - .replace("[receive_time]", receiveTime) - .replace("[timestamp]", timestamp.toString()) - .replace("[sign]", sign) - ) - } - } - postRequest - } - - //添加headers - for ((key, value) in setting.headers?.entries!!) { - request.headers(key, value) - } - - //支持HTTP基本认证(Basic Authentication) - if (matches.isNotEmpty()) { - request.addInterceptor(BasicAuthInterceptor(matches[2], matches[3])) - } - - request.ignoreHttpsCert() //忽略https证书 - .timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s - .cacheMode(CacheMode.NO_CACHE) - .retryCount(SettingUtils.requestRetryTimes) //超时重试的次数 - .retryDelay(SettingUtils.requestDelayTime) //超时重试的延迟时间 - .retryIncreaseDelay(SettingUtils.requestDelayTime) //超时重试叠加延时 - .timeStamp(true) - .execute(object : SimpleCallBack() { - - override fun onError(e: ApiException) { - Log.e(TAG, e.detailMessage) - SendUtils.updateLogs(logId, 0, e.displayMessage) - } - - override fun onSuccess(response: String) { - Log.i(TAG, response) - SendUtils.updateLogs(logId, 2, response) - } - - }) - - } - - //JSON需要转义的字符 - private fun escapeJson(str: String?): String { - if (str == null) return "null" - val jsonStr: String = Gson().toJson(str) - return if (jsonStr.length >= 2) jsonStr.substring(1, jsonStr.length - 1) else jsonStr - } - - fun sendMsg(setting: WebhookSetting, msgInfo: MsgInfo) { - sendMsg(setting, msgInfo, null, null) - } - } +package com.idormy.sms.forwarder.utils.sender + +import android.annotation.SuppressLint +import android.text.TextUtils +import android.util.Base64 +import android.util.Log +import com.google.gson.Gson +import com.idormy.sms.forwarder.database.entity.Rule +import com.idormy.sms.forwarder.entity.MsgInfo +import com.idormy.sms.forwarder.entity.setting.WebhookSetting +import com.idormy.sms.forwarder.utils.SendUtils +import com.idormy.sms.forwarder.utils.SettingUtils +import com.xuexiang.xhttp2.XHttp +import com.xuexiang.xhttp2.cache.model.CacheMode +import com.xuexiang.xhttp2.callback.SimpleCallBack +import com.xuexiang.xhttp2.exception.ApiException +import com.xuexiang.xutil.app.AppUtils +import java.net.URLEncoder +import java.nio.charset.StandardCharsets +import java.text.SimpleDateFormat +import java.util.* +import javax.crypto.Mac +import javax.crypto.spec.SecretKeySpec + +@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") +class WebhookUtils { + companion object { + + private val TAG: String = WebhookUtils::class.java.simpleName + + fun sendMsg( + setting: WebhookSetting, + msgInfo: MsgInfo, + rule: Rule?, + logId: Long?, + ) { + val from: String = msgInfo.from + val content: String = if (rule != null) { + msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) + } else { + msgInfo.getContentForSend(SettingUtils.smsTemplate) + } + + var requestUrl: String = setting.webServer //推送地址 + Log.i(TAG, "requestUrl:$requestUrl") + + val timestamp = System.currentTimeMillis() + val orgContent: String = msgInfo.content + val deviceMark: String = SettingUtils.extraDeviceMark + val appVersion: String = AppUtils.getAppVersionName() + val simInfo: String = msgInfo.simInfo + @SuppressLint("SimpleDateFormat") val receiveTime = + SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date()) //smsVo.getDate() + + var sign = "" + if (!TextUtils.isEmpty(setting.secret)) { + val stringToSign = "$timestamp\n" + setting.secret + val mac = Mac.getInstance("HmacSHA256") + mac.init( + SecretKeySpec( + setting.secret?.toByteArray(StandardCharsets.UTF_8), + "HmacSHA256" + ) + ) + val signData = mac.doFinal(stringToSign.toByteArray(StandardCharsets.UTF_8)) + sign = URLEncoder.encode(String(Base64.encode(signData, Base64.NO_WRAP)), "UTF-8") + } + + var webParams = setting.webParams?.trim() + + //支持HTTP基本认证(Basic Authentication) + val regex = "^(https?://)([^:]+):([^@]+)@(.+)" + val matches = Regex(regex, RegexOption.IGNORE_CASE).findAll(requestUrl).toList() + .flatMap(MatchResult::groupValues) + Log.i(TAG, "matches = $matches") + if (matches.isNotEmpty()) { + requestUrl = matches[1] + matches[4] + Log.i(TAG, "requestUrl:$requestUrl") + } + + val request = if (setting.method == "GET" && TextUtils.isEmpty(webParams)) { + setting.webServer += (if (setting.webServer.contains("?")) "&" else "?") + "from=" + URLEncoder.encode( + from, + "UTF-8" + ) + requestUrl += "&content=" + URLEncoder.encode(content, "UTF-8") + if (!TextUtils.isEmpty(sign)) { + requestUrl += "×tamp=$timestamp" + requestUrl += "&sign=$sign" + } + Log.d(TAG, "method = GET, Url = $requestUrl") + XHttp.get(requestUrl).keepJson(true) + } else if (setting.method == "GET" && !TextUtils.isEmpty(webParams)) { + webParams = webParams.toString().replace("[from]", URLEncoder.encode(from, "UTF-8")) + .replace("[content]", URLEncoder.encode(content, "UTF-8")) + .replace("[msg]", URLEncoder.encode(content, "UTF-8")) + .replace("[org_content]", URLEncoder.encode(orgContent, "UTF-8")) + .replace("[device_mark]", URLEncoder.encode(deviceMark, "UTF-8")) + .replace("[app_version]", URLEncoder.encode(appVersion, "UTF-8")) + .replace("[title]", URLEncoder.encode(simInfo, "UTF-8")) + .replace("[card_slot]", URLEncoder.encode(simInfo, "UTF-8")) + .replace("[receive_time]", URLEncoder.encode(receiveTime, "UTF-8")) + .replace("\n", "%0A") + if (!TextUtils.isEmpty(setting.secret)) { + webParams = webParams.replace("[timestamp]", timestamp.toString()) + .replace("[sign]", URLEncoder.encode(sign, "UTF-8")) + } + requestUrl += if (webParams.startsWith("/")) { + webParams + } else { + (if (requestUrl.contains("?")) "&" else "?") + webParams + } + Log.d(TAG, "method = GET, Url = $requestUrl") + XHttp.get(requestUrl).keepJson(true) + } else if (webParams != null && webParams.isNotEmpty() && webParams.startsWith("{")) { + val bodyMsg = webParams.replace("[from]", from) + .replace("[content]", escapeJson(content)) + .replace("[msg]", escapeJson(content)) + .replace("[org_content]", escapeJson(orgContent)) + .replace("[device_mark]", escapeJson(deviceMark)) + .replace("[app_version]", appVersion) + .replace("[title]", escapeJson(simInfo)) + .replace("[card_slot]", escapeJson(simInfo)) + .replace("[receive_time]", receiveTime) + .replace("[timestamp]", timestamp.toString()) + .replace("[sign]", sign) + Log.d(TAG, "method = ${setting.method}, Url = $requestUrl, bodyMsg = $bodyMsg") + when (setting.method) { + "PUT" -> XHttp.put(requestUrl).keepJson(true).upJson(bodyMsg) + "PATCH" -> XHttp.patch(requestUrl).keepJson(true).upJson(bodyMsg) + else -> XHttp.post(requestUrl).keepJson(true).upJson(bodyMsg) + } + } else { + if (webParams == null || webParams.isEmpty()) { + webParams = "from=[from]&content=[content]×tamp=[timestamp]" + if (!TextUtils.isEmpty(sign)) webParams += "&sign=[sign]" + } + Log.d(TAG, "method = ${setting.method}, Url = $requestUrl") + val postRequest = when (setting.method) { + "PUT" -> XHttp.put(requestUrl).keepJson(true) + "PATCH" -> XHttp.patch(requestUrl).keepJson(true) + else -> XHttp.post(requestUrl).keepJson(true) + } + webParams.trim('&').split("&").forEach { + val param = it.split("=") + if (param.size == 2) { + postRequest.params( + param[0], param[1].replace("[from]", from) + .replace("[content]", content) + .replace("[msg]", content) + .replace("[org_content]", orgContent) + .replace("[device_mark]", deviceMark) + .replace("[app_version]", appVersion) + .replace("[title]", simInfo) + .replace("[card_slot]", simInfo) + .replace("[receive_time]", receiveTime) + .replace("[timestamp]", timestamp.toString()) + .replace("[sign]", sign) + ) + } + } + postRequest + } + + //添加headers + for ((key, value) in setting.headers?.entries!!) { + request.headers(key, value) + } + + //支持HTTP基本认证(Basic Authentication) + if (matches.isNotEmpty()) { + request.addInterceptor(BasicAuthInterceptor(matches[2], matches[3])) + } + + request.ignoreHttpsCert() //忽略https证书 + .timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s + .cacheMode(CacheMode.NO_CACHE) + .retryCount(SettingUtils.requestRetryTimes) //超时重试的次数 + .retryDelay(SettingUtils.requestDelayTime) //超时重试的延迟时间 + .retryIncreaseDelay(SettingUtils.requestDelayTime) //超时重试叠加延时 + .timeStamp(true) + .execute(object : SimpleCallBack() { + + override fun onError(e: ApiException) { + Log.e(TAG, e.detailMessage) + SendUtils.updateLogs(logId, 0, e.displayMessage) + } + + override fun onSuccess(response: String) { + Log.i(TAG, response) + SendUtils.updateLogs(logId, 2, response) + } + + }) + + } + + //JSON需要转义的字符 + private fun escapeJson(str: String?): String { + if (str == null) return "null" + val jsonStr: String = Gson().toJson(str) + return if (jsonStr.length >= 2) jsonStr.substring(1, jsonStr.length - 1) else jsonStr + } + + fun sendMsg(setting: WebhookSetting, msgInfo: MsgInfo) { + sendMsg(setting, msgInfo, null, null) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WeworkAgentUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WeworkAgentUtils.kt index 8e8c0baa..875be7ff 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WeworkAgentUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WeworkAgentUtils.kt @@ -120,7 +120,7 @@ class WeworkAgentUtils private constructor() { val content: String = if (rule != null) { msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) } else { - msgInfo.getContentForSend(SettingUtils.smsTemplate.toString()) + msgInfo.getContentForSend(SettingUtils.smsTemplate) } val textMsgMap: MutableMap = mutableMapOf() @@ -132,7 +132,7 @@ class WeworkAgentUtils private constructor() { val textText: MutableMap = mutableMapOf() textText["content"] = content textMsgMap["text"] = textText - var accessToken: String by SharedPreference("access_token_" + setting.agentID, "") + val accessToken: String by SharedPreference("access_token_" + setting.agentID, "") val requestUrl = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=$accessToken" Log.i(TAG, "requestUrl:$requestUrl") val requestMsg: String = Gson().toJson(textMsgMap) diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WeworkRobotUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WeworkRobotUtils.kt index 57a61a90..8048fafe 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WeworkRobotUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WeworkRobotUtils.kt @@ -28,7 +28,7 @@ class WeworkRobotUtils private constructor() { val content: String = if (rule != null) { msgInfo.getContentForSend(rule.smsTemplate, rule.regexReplace) } else { - msgInfo.getContentForSend(SettingUtils.smsTemplate.toString()) + msgInfo.getContentForSend(SettingUtils.smsTemplate) } val requestUrl = setting.webHook diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index d61052da..46d452c4 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -340,7 +340,7 @@ SIM2 SubId/Label Label of SIM,\neg. AT&T_88888888 Number must be greater than 0! - ^[1-9]?\\d+$ + ^[1-9]?\\d+$ Low Power Alarm Value range: 0–99.\nLeft blank or 0 is disabled Retry Interval diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eed58d82..d12a0ae7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -341,7 +341,7 @@ SIM2主键/备注 序号/运营商_手机号 数字必须大于0! - ^[1-9]?\\d+$ + ^[1-9]?\\d+$ 安全电量范围(%) 超出安全范围将发出预警 请求重试机制