diff --git a/app/src/main/java/com/idormy/sms/forwarder/entity/setting/WebhookSetting.kt b/app/src/main/java/com/idormy/sms/forwarder/entity/setting/WebhookSetting.kt index 168c00c1..bd23dbdc 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/entity/setting/WebhookSetting.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/entity/setting/WebhookSetting.kt @@ -11,10 +11,11 @@ data class WebhookSetting( val headers: Map?, ) : Serializable { fun getMethodCheckId(): Int { - return if (method == null || method == "POST") { - R.id.rb_method_post - } else { - R.id.rb_method_get + return when (method) { + null, "POST" -> R.id.rb_method_post + "PUT" -> R.id.rb_method_put + "PATCH" -> R.id.rb_method_patch + else -> R.id.rb_method_get } } } \ No newline at end of file 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 0d7cabcf..b2a95185 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 @@ -49,13 +49,19 @@ class WebhookUtils { 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() + @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")) + 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") } @@ -64,7 +70,8 @@ class WebhookUtils { //支持HTTP基本认证(Basic Authentication) val regex = "^(https?://)([^:]+):([^@]+)@(.+)" - val matches = Regex(regex, RegexOption.IGNORE_CASE).findAll(requestUrl).toList().flatMap(MatchResult::groupValues) + 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] @@ -72,7 +79,10 @@ class WebhookUtils { } val request = if (setting.method == "GET" && TextUtils.isEmpty(webParams)) { - setting.webServer += (if (setting.webServer.contains("?")) "&" else "?") + "from=" + URLEncoder.encode(from, "UTF-8") + 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" @@ -114,29 +124,39 @@ class WebhookUtils { .replace("[receive_time]", receiveTime) .replace("[timestamp]", timestamp.toString()) .replace("[sign]", sign) - Log.d(TAG, "method = POST, Url = $requestUrl, bodyMsg = $bodyMsg") - XHttp.post(requestUrl).keepJson(true).upJson(bodyMsg) + 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]" } - - val postRequest = XHttp.post(requestUrl).keepJson(true) + 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.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.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 diff --git a/app/src/main/res/layout/fragment_senders_webhook.xml b/app/src/main/res/layout/fragment_senders_webhook.xml index 8dfc546d..2bbb3437 100644 --- a/app/src/main/res/layout/fragment_senders_webhook.xml +++ b/app/src/main/res/layout/fragment_senders_webhook.xml @@ -81,6 +81,18 @@ android:layout_height="wrap_content" android:text="@string/get" /> + + + + diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index a2f4207e..5a54e07e 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -395,6 +395,8 @@ Example of multiple matching rules: (see wiki for syntax)\n\nAND IS PACKAGE_NAME EQUALS com.tencent.mm\n[space]OR IS PACKAGE_NAME EQUALS com.tencent.mm\nAND IS INFORM_CONTENT CONTAIN arrears\n\nThe above rules mean: Receive an APP notification, and (the APP package name is com.tencent.mm or the APP package name is com.tencent.mm), and the content of the notification includes forwarding the notification when the payment is in arrears\n\nNote: The space at the beginning of each line represents the level, too complex multiple rules may lead to a large memory usage! POST GET + PUT + PATCH Local IP: Instructions: \n[Note] The APP version of the sender and receiver must be the same!\n1. Please keep the SOURCE and DESTINATION phones in the same Wi-Fi network, and do not turn on isolation. \n2. Tap "Send" on SOURCE mobile phone, and get "server IP" \n3. After filling in "Server IP" on DESTINATION phone, tap "Receive". \n [NOTE:] sender(s), forwarding rule(s) and log(s) will be overwritten after cloning! diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 21e9b03e..620f0c26 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -396,6 +396,8 @@ 多重匹配规则示例:(语法参见wiki)\n\n并且 是 APP包名 相等 com.tencent.mm\n[空格]或者 是 APP包名 相等 com.tencent.mm\n并且 是 通知内容 包含 欠费\n\n以上规则表示:收到APP通知,并且(APP包名是com.tencent.mm 或者 APP包名是com.tencent.mm),并且 通知内容 包含 欠费 时转发通知\n\n注意:每行开始的空格代表层级,太过复杂的多重规则可能导致内存占用很大! POST GET + PUT + PATCH 本机IP: 严正声明:\n该功能仅限个人新旧手机切换使用,用于非法用途后果自负!\n\n操作说明:\n1.新旧手机连接同一个WiFi网络(禁用AP隔离),如需穿透内网请先配置Frpc\n2.【二选一】旧手机点【推送】按钮,将本机的配置推送到服务端\n3.【二选一】新手机点【拉取】按钮,将拉取服务端的配置到本机\n\n注意事项:\n1.客户端与服务端的APP版本必须一致,才能克隆!\n2.导入成功后,发送通道、转发规则将完全被覆盖,清空历史记录!\n3.主动请求、保活措施、个性设置不在克隆范围 diff --git a/versions.gradle b/versions.gradle index 5ee9f529..c85d3a02 100644 --- a/versions.gradle +++ b/versions.gradle @@ -42,7 +42,7 @@ versions.xui = "1.2.2" versions.xupdate = "2.1.3" versions.xaop = "1.1.0" versions.xutil = "2.0.0" -versions.xhttp2 = "2.0.8" +versions.xhttp2 = "2.0.9" versions.xpage = "3.3.0" versions.xrouter = "1.0.1"