mirror of
https://github.com/pppscn/SmsForwarder
synced 2025-08-04 01:47:40 +08:00
新增:支持Bark推送加密 #273 (详见:https://bark.day.app/#/encryption)
This commit is contained in:
parent
f5de522967
commit
1bc2668ab2
@ -19,4 +19,10 @@ data class BarkSetting(
|
|||||||
val level: String? = "active",
|
val level: String? = "active",
|
||||||
//标题模板
|
//标题模板
|
||||||
val title: String? = "",
|
val title: String? = "",
|
||||||
|
//加密算法
|
||||||
|
val transformation: String = "none",
|
||||||
|
//加密密钥
|
||||||
|
val key: String = "",
|
||||||
|
//初始偏移向量
|
||||||
|
val iv: String = "",
|
||||||
) : Serializable
|
) : Serializable
|
@ -46,6 +46,7 @@ class BarkFragment : BaseFragment<FragmentSendersBarkBinding?>(), View.OnClickLi
|
|||||||
private val viewModel by viewModels<SenderViewModel> { BaseViewModelFactory(context) }
|
private val viewModel by viewModels<SenderViewModel> { BaseViewModelFactory(context) }
|
||||||
private var mCountDownHelper: CountDownButtonHelper? = null
|
private var mCountDownHelper: CountDownButtonHelper? = null
|
||||||
private var barkLevel: String = "active" //通知级别
|
private var barkLevel: String = "active" //通知级别
|
||||||
|
private var transformation: String = "none" //加密算法
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
@AutoWired(name = KEY_SENDER_ID)
|
@AutoWired(name = KEY_SENDER_ID)
|
||||||
@ -103,6 +104,18 @@ class BarkFragment : BaseFragment<FragmentSendersBarkBinding?>(), View.OnClickLi
|
|||||||
}
|
}
|
||||||
binding!!.spLevel.selectedIndex = 0
|
binding!!.spLevel.selectedIndex = 0
|
||||||
|
|
||||||
|
binding!!.spEncryptionAlgorithm.setItems(BARK_ENCRYPTION_ALGORITHM_MAP.values.toList())
|
||||||
|
binding!!.spEncryptionAlgorithm.setOnItemSelectedListener { _: MaterialSpinner?, _: Int, _: Long, item: Any ->
|
||||||
|
BARK_ENCRYPTION_ALGORITHM_MAP.forEach {
|
||||||
|
if (it.value == item) transformation = it.key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding!!.spEncryptionAlgorithm.setOnNothingSelectedListener {
|
||||||
|
binding!!.spEncryptionAlgorithm.selectedIndex = 0
|
||||||
|
transformation = "none"
|
||||||
|
}
|
||||||
|
binding!!.spEncryptionAlgorithm.selectedIndex = 0
|
||||||
|
|
||||||
//新增
|
//新增
|
||||||
if (senderId <= 0) {
|
if (senderId <= 0) {
|
||||||
titleBar?.setSubTitle(getString(R.string.add_sender))
|
titleBar?.setSubTitle(getString(R.string.add_sender))
|
||||||
@ -112,43 +125,43 @@ class BarkFragment : BaseFragment<FragmentSendersBarkBinding?>(), View.OnClickLi
|
|||||||
|
|
||||||
//编辑
|
//编辑
|
||||||
binding!!.btnDel.setText(R.string.del)
|
binding!!.btnDel.setText(R.string.del)
|
||||||
AppDatabase.getInstance(requireContext())
|
AppDatabase.getInstance(requireContext()).senderDao().get(senderId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver<Sender> {
|
||||||
.senderDao()
|
override fun onSubscribe(d: Disposable) {}
|
||||||
.get(senderId)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(object : SingleObserver<Sender> {
|
|
||||||
override fun onSubscribe(d: Disposable) {}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {
|
override fun onError(e: Throwable) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSuccess(sender: Sender) {
|
override fun onSuccess(sender: Sender) {
|
||||||
if (isClone) {
|
if (isClone) {
|
||||||
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
|
titleBar?.setSubTitle(getString(R.string.clone_sender) + ": " + sender.name)
|
||||||
binding!!.btnDel.setText(R.string.discard)
|
binding!!.btnDel.setText(R.string.discard)
|
||||||
} else {
|
} else {
|
||||||
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
|
titleBar?.setSubTitle(getString(R.string.edit_sender) + ": " + sender.name)
|
||||||
}
|
|
||||||
binding!!.etName.setText(sender.name)
|
|
||||||
binding!!.sbEnable.isChecked = sender.status == 1
|
|
||||||
val settingVo = Gson().fromJson(sender.jsonSetting, BarkSetting::class.java)
|
|
||||||
Log.d(TAG, settingVo.toString())
|
|
||||||
if (settingVo != null) {
|
|
||||||
binding!!.etServer.setText(settingVo.server)
|
|
||||||
binding!!.etGroup.setText(settingVo.group)
|
|
||||||
binding!!.etIcon.setText(settingVo.icon)
|
|
||||||
binding!!.etSound.setText(settingVo.sound)
|
|
||||||
binding!!.etBadge.setText(settingVo.badge)
|
|
||||||
binding!!.etUrl.setText(settingVo.url)
|
|
||||||
BARK_LEVEL_MAP.forEach {
|
|
||||||
if (it.key == settingVo.level) binding!!.spLevel.setSelectedItem(it.value)
|
|
||||||
}
|
|
||||||
binding!!.etTitleTemplate.setText(settingVo.title)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
binding!!.etName.setText(sender.name)
|
||||||
|
binding!!.sbEnable.isChecked = sender.status == 1
|
||||||
|
val settingVo = Gson().fromJson(sender.jsonSetting, BarkSetting::class.java)
|
||||||
|
Log.d(TAG, settingVo.toString())
|
||||||
|
if (settingVo != null) {
|
||||||
|
binding!!.etServer.setText(settingVo.server)
|
||||||
|
binding!!.etGroup.setText(settingVo.group)
|
||||||
|
binding!!.etIcon.setText(settingVo.icon)
|
||||||
|
binding!!.etSound.setText(settingVo.sound)
|
||||||
|
binding!!.etBadge.setText(settingVo.badge)
|
||||||
|
binding!!.etUrl.setText(settingVo.url)
|
||||||
|
BARK_LEVEL_MAP.forEach {
|
||||||
|
if (it.key == settingVo.level) binding!!.spLevel.setSelectedItem(it.value)
|
||||||
|
}
|
||||||
|
binding!!.etTitleTemplate.setText(settingVo.title)
|
||||||
|
BARK_ENCRYPTION_ALGORITHM_MAP.forEach {
|
||||||
|
if (it.value == settingVo.transformation) binding!!.spEncryptionAlgorithm.setSelectedItem(it.value)
|
||||||
|
}
|
||||||
|
binding!!.etEncryptionKey.setText(settingVo.key)
|
||||||
|
binding!!.etEncryptionIv.setText(settingVo.iv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,18 +185,22 @@ class BarkFragment : BaseFragment<FragmentSendersBarkBinding?>(), View.OnClickLi
|
|||||||
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_from))
|
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_from))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.bt_insert_extra -> {
|
R.id.bt_insert_extra -> {
|
||||||
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_card_slot))
|
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_card_slot))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.bt_insert_time -> {
|
R.id.bt_insert_time -> {
|
||||||
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_receive_time))
|
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_receive_time))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.bt_insert_device_name -> {
|
R.id.bt_insert_device_name -> {
|
||||||
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_device_name))
|
CommonUtils.insertOrReplaceText2Cursor(etTitleTemplate, getString(R.string.tag_device_name))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.btn_test -> {
|
R.id.btn_test -> {
|
||||||
mCountDownHelper?.start()
|
mCountDownHelper?.start()
|
||||||
Thread {
|
Thread {
|
||||||
@ -202,25 +219,21 @@ class BarkFragment : BaseFragment<FragmentSendersBarkBinding?>(), View.OnClickLi
|
|||||||
}.start()
|
}.start()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.btn_del -> {
|
R.id.btn_del -> {
|
||||||
if (senderId <= 0 || isClone) {
|
if (senderId <= 0 || isClone) {
|
||||||
popToBack()
|
popToBack()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialDialog.Builder(requireContext())
|
MaterialDialog.Builder(requireContext()).title(R.string.delete_sender_title).content(R.string.delete_sender_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? ->
|
||||||
.title(R.string.delete_sender_title)
|
viewModel.delete(senderId)
|
||||||
.content(R.string.delete_sender_tips)
|
XToastUtils.success(R.string.delete_sender_toast)
|
||||||
.positiveText(R.string.lab_yes)
|
popToBack()
|
||||||
.negativeText(R.string.lab_no)
|
}.show()
|
||||||
.onPositive { _: MaterialDialog?, _: DialogAction? ->
|
|
||||||
viewModel.delete(senderId)
|
|
||||||
XToastUtils.success(R.string.delete_sender_toast)
|
|
||||||
popToBack()
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.btn_save -> {
|
R.id.btn_save -> {
|
||||||
val name = binding!!.etName.text.toString().trim()
|
val name = binding!!.etName.text.toString().trim()
|
||||||
if (TextUtils.isEmpty(name)) {
|
if (TextUtils.isEmpty(name)) {
|
||||||
@ -262,8 +275,17 @@ class BarkFragment : BaseFragment<FragmentSendersBarkBinding?>(), View.OnClickLi
|
|||||||
throw Exception(getString(R.string.invalid_bark_url))
|
throw Exception(getString(R.string.invalid_bark_url))
|
||||||
}
|
}
|
||||||
val title = binding!!.etTitleTemplate.text.toString().trim()
|
val title = binding!!.etTitleTemplate.text.toString().trim()
|
||||||
|
val key = binding!!.etEncryptionKey.text.toString().trim()
|
||||||
|
val iv = binding!!.etEncryptionIv.text.toString().trim()
|
||||||
|
if (transformation.startsWith("AES128") && (key.length != 16 || iv.length != 16)) {
|
||||||
|
throw Exception(getString(R.string.bark_encryption_key_error1))
|
||||||
|
} else if (transformation.startsWith("AES192") && (key.length != 24 || iv.length != 24)) {
|
||||||
|
throw Exception(getString(R.string.bark_encryption_key_error2))
|
||||||
|
} else if (transformation.startsWith("AES256") && (key.length != 32 || iv.length != 32)) {
|
||||||
|
throw Exception(getString(R.string.bark_encryption_key_error3))
|
||||||
|
}
|
||||||
|
|
||||||
return BarkSetting(server, group, icon, sound, badge, url, barkLevel, title)
|
return BarkSetting(server, group, icon, sound, badge, url, barkLevel, title, transformation, key, iv)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
@ -167,6 +167,15 @@ val BARK_LEVEL_MAP = mapOf(
|
|||||||
"timeSensitive" to getString(R.string.bark_level_timeSensitive),
|
"timeSensitive" to getString(R.string.bark_level_timeSensitive),
|
||||||
"passive" to getString(R.string.bark_level_passive)
|
"passive" to getString(R.string.bark_level_passive)
|
||||||
)
|
)
|
||||||
|
val BARK_ENCRYPTION_ALGORITHM_MAP = mapOf(
|
||||||
|
"none" to getString(R.string.bark_encryption_algorithm_none),
|
||||||
|
"AES128/CBC/PKCS7Padding" to "AES128/CBC/PKCS7Padding",
|
||||||
|
"AES128/ECB/PKCS7Padding" to "AES128/ECB/PKCS7Padding",
|
||||||
|
"AES192/CBC/PKCS7Padding" to "AES192/CBC/PKCS7Padding",
|
||||||
|
"AES192/ECB/PKCS7Padding" to "AES192/ECB/PKCS7Padding",
|
||||||
|
"AES256/CBC/PKCS7Padding" to "AES256/CBC/PKCS7Padding",
|
||||||
|
"AES256/ECB/PKCS7Padding" to "AES256/ECB/PKCS7Padding",
|
||||||
|
)
|
||||||
|
|
||||||
//发送通道
|
//发送通道
|
||||||
const val TYPE_DINGTALK_GROUP_ROBOT = 0
|
const val TYPE_DINGTALK_GROUP_ROBOT = 0
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.idormy.sms.forwarder.utils.sender
|
package com.idormy.sms.forwarder.utils.sender
|
||||||
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
|
import android.util.Base64
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.idormy.sms.forwarder.database.entity.Rule
|
import com.idormy.sms.forwarder.database.entity.Rule
|
||||||
@ -13,8 +14,13 @@ import com.xuexiang.xhttp2.XHttp
|
|||||||
import com.xuexiang.xhttp2.cache.model.CacheMode
|
import com.xuexiang.xhttp2.cache.model.CacheMode
|
||||||
import com.xuexiang.xhttp2.callback.SimpleCallBack
|
import com.xuexiang.xhttp2.callback.SimpleCallBack
|
||||||
import com.xuexiang.xhttp2.exception.ApiException
|
import com.xuexiang.xhttp2.exception.ApiException
|
||||||
|
import java.net.URLEncoder
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
import javax.crypto.Cipher
|
||||||
|
import javax.crypto.spec.IvParameterSpec
|
||||||
|
import javax.crypto.spec.SecretKeySpec
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
class BarkUtils {
|
class BarkUtils {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@ -52,29 +58,40 @@ class BarkUtils {
|
|||||||
XHttp.post(requestUrl)
|
XHttp.post(requestUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
request.params("title", title)
|
val msgMap: MutableMap<String, Any> = mutableMapOf()
|
||||||
.params("body", content)
|
msgMap["title"] = title
|
||||||
.params("isArchive", 1)
|
msgMap["body"] = content
|
||||||
if (!TextUtils.isEmpty(setting.group)) request.params("group", setting.group)
|
msgMap["isArchive"] = 1
|
||||||
if (!TextUtils.isEmpty(setting.icon)) request.params("icon", setting.icon)
|
if (!TextUtils.isEmpty(setting.group)) msgMap["group"] = setting.group.toString()
|
||||||
if (!TextUtils.isEmpty(setting.level)) request.params("level", setting.level)
|
if (!TextUtils.isEmpty(setting.icon)) msgMap["icon"] = setting.icon.toString()
|
||||||
if (!TextUtils.isEmpty(setting.sound)) request.params("sound", setting.sound)
|
if (!TextUtils.isEmpty(setting.level)) msgMap["level"] = setting.level.toString()
|
||||||
if (!TextUtils.isEmpty(setting.badge)) request.params("badge", setting.badge)
|
if (!TextUtils.isEmpty(setting.sound)) msgMap["sound"] = setting.sound.toString()
|
||||||
if (!TextUtils.isEmpty(setting.url)) request.params("url", setting.url)
|
if (!TextUtils.isEmpty(setting.badge)) msgMap["badge"] = setting.badge.toString()
|
||||||
|
if (!TextUtils.isEmpty(setting.url)) msgMap["url"] = setting.url.toString()
|
||||||
|
|
||||||
val isCode: Int = content.indexOf("验证码")
|
//自动复制验证码
|
||||||
val isPassword: Int = content.indexOf("动态密码")
|
val pattern = Regex("(?<!回复)(验证码|授权码|校验码|检验码|确认码|激活码|动态码|安全码|(验证)?代码|校验代码|检验代码|激活代码|确认代码|动态代码|安全代码|登入码|认证码|识别码|短信口令|动态密码|交易码|上网密码|动态口令|随机码|驗證碼|授權碼|校驗碼|檢驗碼|確認碼|激活碼|動態碼|(驗證)?代碼|校驗代碼|檢驗代碼|確認代碼|激活代碼|動態代碼|登入碼|認證碼|識別碼|一次性密码|[Cc][Oo][Dd][Ee]|[Vv]erification)")
|
||||||
val isPassword2: Int = content.indexOf("短信密码")
|
if (pattern.containsMatchIn(content)) {
|
||||||
if (isCode != -1 || isPassword != -1 || isPassword2 != -1) {
|
var code = content.replace("(.*)((代|授权|验证|动态|校验)码|[【\\[].*[】\\]]|[Cc][Oo][Dd][Ee]|[Vv]erification\\s?([Cc]ode)?)\\s?(G-|<#>)?([::\\s是为]|[Ii][Ss]){0,3}[\\((\\[【{「]?(([0-9\\s]{4,7})|([\\dA-Za-z]{5,6})(?!([Vv]erification)?([Cc][Oo][Dd][Ee])|:))[」}】\\])\\)]?(?=([^0-9a-zA-Z]|\$))(.*)".toRegex(), "$7").trim()
|
||||||
val p = Pattern.compile("(\\d{4,6})")
|
code = code.replace("[^\\d]*[\\((\\[【{「]?([0-9]{3}\\s?[0-9]{1,3})[」}】\\])\\)]?(?=.*((代|授权|验证|动态|校验)码|[【\\[].*[】\\]]|[Cc][Oo][Dd][Ee]|[Vv]erification\\s?([Cc]ode)?))(.*)".toRegex(), "$1").trim()
|
||||||
val m = p.matcher(content)
|
if (code.isNotEmpty()) {
|
||||||
if (m.find()) {
|
msgMap["copy"] = code
|
||||||
println(m.group())
|
msgMap["automaticallyCopy"] = 1
|
||||||
request.params("automaticallyCopy", "1")
|
|
||||||
request.params("copy", m.group())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val requestMsg: String = Gson().toJson(msgMap)
|
||||||
|
Log.i(TAG, "requestMsg:$requestMsg")
|
||||||
|
//推送加密
|
||||||
|
if (setting.transformation.isNotEmpty() && "none" != setting.transformation && setting.key.isNotEmpty() && setting.iv.isNotEmpty()) {
|
||||||
|
var transformation = setting.transformation.replace("AES128", "AES").replace("AES192", "AES").replace("AES256", "AES")
|
||||||
|
val ciphertext = encrypt(requestMsg, transformation, setting.key, setting.iv)
|
||||||
|
request.params("ciphertext", URLEncoder.encode(ciphertext, "UTF-8"))
|
||||||
|
request.params("iv", URLEncoder.encode(setting.iv, "UTF-8"))
|
||||||
|
} else {
|
||||||
|
request.upJson(requestMsg)
|
||||||
|
}
|
||||||
|
|
||||||
request.ignoreHttpsCert() //忽略https证书
|
request.ignoreHttpsCert() //忽略https证书
|
||||||
.keepJson(true)
|
.keepJson(true)
|
||||||
.timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s
|
.timeOut((SettingUtils.requestTimeout * 1000).toLong()) //超时时间10s
|
||||||
@ -106,5 +123,14 @@ class BarkUtils {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun encrypt(plainText: String, transformation: String, key: String, iv: String): String {
|
||||||
|
val cipher = Cipher.getInstance(transformation)
|
||||||
|
val keySpec = SecretKeySpec(key.toByteArray(), "AES")
|
||||||
|
val ivSpec = IvParameterSpec(iv.toByteArray())
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec)
|
||||||
|
val encryptedBytes = cipher.doFinal(plainText.toByteArray(Charsets.UTF_8))
|
||||||
|
return Base64.encode(encryptedBytes, Base64.NO_WRAP).toString()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -303,6 +303,74 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
style="@style/senderBarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="5dp"
|
||||||
|
android:text="@string/bark_encryption_algorithm"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.spinner.materialspinner.MaterialSpinner
|
||||||
|
android:id="@+id/sp_encryption_algorithm"
|
||||||
|
style="@style/Material.SpinnerStyle"
|
||||||
|
android:layout_marginStart="5dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
style="@style/senderBarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/bark_encryption_key"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||||
|
android:id="@+id/et_encryption_key"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:hint="@string/bark_encryption_key_tips"
|
||||||
|
android:singleLine="true"
|
||||||
|
app:met_clearButton="true" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
style="@style/senderBarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/bark_encryption_iv"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||||
|
android:id="@+id/et_encryption_iv"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:hint="@string/bark_encryption_iv_tips"
|
||||||
|
android:singleLine="true"
|
||||||
|
app:met_clearButton="true" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
@ -728,12 +728,16 @@
|
|||||||
<string name="bark_url_regex" formatted="false" tools:ignore="TypographyDashes"><![CDATA[^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]]]></string>
|
<string name="bark_url_regex" formatted="false" tools:ignore="TypographyDashes"><![CDATA[^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]]]></string>
|
||||||
<string name="bark_url_regex2" formatted="false" tools:ignore="TypographyDashes"><![CDATA[^[a-z]+://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]]]></string>
|
<string name="bark_url_regex2" formatted="false" tools:ignore="TypographyDashes"><![CDATA[^[a-z]+://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]]]></string>
|
||||||
<string name="bark_url_error">Url format error</string>
|
<string name="bark_url_error">Url format error</string>
|
||||||
<string name="bark_key">AES Key</string>
|
<string name="bark_encryption_algorithm">Encryption Algorithm</string>
|
||||||
<string name="bark_key_tips">Fill in 16 chars to enable push encryption</string>
|
<string name="bark_encryption_algorithm_none">NONE</string>
|
||||||
<string name="bark_iv">AES iv</string>
|
<string name="bark_encryption_key">AES Key</string>
|
||||||
<string name="bark_iv_tips">Fill in 16 chars to enable push encryption</string>
|
<string name="bark_encryption_key_tips">corresponding key on bark</string>
|
||||||
<string name="bark_key_regex" formatted="false" tools:ignore="TypographyDashes"><![CDATA[^[a-zA-Z0-9]{16}]]></string>
|
<string name="bark_encryption_iv">AES iv</string>
|
||||||
<string name="bark_key_error">AES Key and iv must be 16 characters</string>
|
<string name="bark_encryption_iv_tips">corresponding iv on bark</string>
|
||||||
|
<string name="bark_encryption_key_regex" formatted="false" tools:ignore="TypographyDashes"><![CDATA[^[a-zA-Z0-9]{16}]]></string>
|
||||||
|
<string name="bark_encryption_key_error1">AES Key and iv must be 16 characters</string>
|
||||||
|
<string name="bark_encryption_key_error2">AES Key and iv must be 24 characters</string>
|
||||||
|
<string name="bark_encryption_key_error3">AES Key and iv must be 32 characters</string>
|
||||||
|
|
||||||
<string name="from_email_hint">Fill in the username before @</string>
|
<string name="from_email_hint">Fill in the username before @</string>
|
||||||
<string name="from_email_full_hint">Fill in the format: AAA@BBB.CCC</string>
|
<string name="from_email_full_hint">Fill in the format: AAA@BBB.CCC</string>
|
||||||
|
@ -729,12 +729,16 @@
|
|||||||
<string name="bark_url_regex" formatted="false" tools:ignore="TypographyDashes"><![CDATA[^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]]]></string>
|
<string name="bark_url_regex" formatted="false" tools:ignore="TypographyDashes"><![CDATA[^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]]]></string>
|
||||||
<string name="bark_url_regex2" formatted="false" tools:ignore="TypographyDashes"><![CDATA[^[a-z]+://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]]]></string>
|
<string name="bark_url_regex2" formatted="false" tools:ignore="TypographyDashes"><![CDATA[^[a-z]+://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]]]></string>
|
||||||
<string name="bark_url_error">Url格式错误</string>
|
<string name="bark_url_error">Url格式错误</string>
|
||||||
<string name="bark_key">加密密钥</string>
|
<string name="bark_encryption_algorithm">加密算法</string>
|
||||||
<string name="bark_key_tips">填写16个字符,以启用推送加密</string>
|
<string name="bark_encryption_algorithm_none">不加密</string>
|
||||||
<string name="bark_iv">偏移向量</string>
|
<string name="bark_encryption_key">加密密钥</string>
|
||||||
<string name="bark_iv_tips">填写16个字符,以启用推送加密</string>
|
<string name="bark_encryption_key_tips">对应bark上的key</string>
|
||||||
<string name="bark_key_regex" formatted="false" tools:ignore="TypographyDashes"><![CDATA[^([a-zA-Z0-9]{16})? $]]></string>
|
<string name="bark_encryption_iv">偏移向量</string>
|
||||||
<string name="bark_key_error">加密密钥和偏移向量必须同时是16个字符</string>
|
<string name="bark_encryption_iv_tips">对应bark上的iv</string>
|
||||||
|
<string name="bark_encryption_key_regex" formatted="false" tools:ignore="TypographyDashes"><![CDATA[^([a-zA-Z0-9]{16})? $]]></string>
|
||||||
|
<string name="bark_encryption_key_error1">加密密钥和偏移向量都必须是16位</string>
|
||||||
|
<string name="bark_encryption_key_error2">加密密钥和偏移向量都必须是24位</string>
|
||||||
|
<string name="bark_encryption_key_error3">加密密钥和偏移向量都必须是32位</string>
|
||||||
|
|
||||||
<string name="from_email_hint">填写 @ 前面的用户名</string>
|
<string name="from_email_hint">填写 @ 前面的用户名</string>
|
||||||
<string name="from_email_full_hint">填写格式: AAA@BBB.CCC</string>
|
<string name="from_email_full_hint">填写格式: AAA@BBB.CCC</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user