diff --git a/.idea/misc.xml b/.idea/misc.xml
index 8a37a45..443bdfd 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -31,6 +31,7 @@
+
diff --git a/app/build.gradle b/app/build.gradle
index d971909..f7282fc 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -294,6 +294,10 @@ dependencies {
//https://github.com/fengyuecanzhu/Maple
implementation("me.fycz.maple:maple:2.0")
+
+ //加解密类库,有些书源使用
+ //noinspection GradleDependency,GradlePackageUpdate
+ implementation('cn.hutool:hutool-crypto:5.8.10')
}
greendao {
diff --git a/app/src/main/java/xyz/fycz/myreader/greendao/service/CacheManager.kt b/app/src/main/java/xyz/fycz/myreader/greendao/service/CacheManager.kt
index 5b0fa0d..0219964 100644
--- a/app/src/main/java/xyz/fycz/myreader/greendao/service/CacheManager.kt
+++ b/app/src/main/java/xyz/fycz/myreader/greendao/service/CacheManager.kt
@@ -19,6 +19,7 @@
package xyz.fycz.myreader.greendao.service
import android.database.Cursor
+import androidx.collection.LruCache
import xyz.fycz.myreader.application.App
import xyz.fycz.myreader.greendao.DbManager
import xyz.fycz.myreader.greendao.entity.Cache
@@ -31,6 +32,7 @@ import java.lang.Exception
object CacheManager {
private val queryTTFMap = hashMapOf>()
+ private val memoryLruCache = object : LruCache(100) {}
/**
* saveTime 单位为秒
@@ -49,6 +51,19 @@ object CacheManager {
}
}
+ fun putMemory(key: String, value: String) {
+ memoryLruCache.put(key, value)
+ }
+
+ //从内存中获取数据 使用lruCache
+ fun getFromMemory(key: String): String? {
+ return memoryLruCache.get(key)
+ }
+
+ fun deleteMemory(key: String) {
+ memoryLruCache.remove(key)
+ }
+
fun get(key: String): String? {
var str: String? = null
try {
@@ -94,6 +109,14 @@ object CacheManager {
return null
}
+ fun putFile(key: String, value: String, saveTime: Int = 0) {
+ ACache.get().put(key, value, saveTime)
+ }
+
+ fun getFile(key: String): String? {
+ return ACache.get().getAsString(key)
+ }
+
fun delete(key: String) {
DbManager.getDaoSession().cacheDao.deleteByKey(key)
ACache.get(App.getmContext()).remove(key)
diff --git a/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsEncodeUtils.kt b/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsEncodeUtils.kt
new file mode 100644
index 0000000..8d804aa
--- /dev/null
+++ b/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsEncodeUtils.kt
@@ -0,0 +1,496 @@
+/*
+ * This file is part of FYReader.
+ * FYReader is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * FYReader is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FYReader. If not, see .
+ *
+ * Copyright (C) 2020 - 2022 fengyuecanzhu
+ */
+
+package xyz.fycz.myreader.model.third3.analyzeRule
+
+import android.util.Base64
+import cn.hutool.crypto.digest.DigestUtil
+import cn.hutool.crypto.digest.HMac
+import cn.hutool.crypto.symmetric.SymmetricCrypto
+import xyz.fycz.myreader.util.utils.MD5Utils
+
+/**
+ * js加解密扩展类, 在js中通过java变量调用
+ * 添加方法,请更新文档/legado/app/src/main/assets/help/JsHelp.md
+ */
+interface JsEncodeUtils {
+
+ fun md5Encode(str: String): String {
+ return MD5Utils.md5Encode(str)
+ }
+
+ fun md5Encode16(str: String): String {
+ return MD5Utils.md5Encode16(str)
+ }
+
+
+ //******************对称加密解密************************//
+
+ /**
+ * 在js中这样使用
+ * java.createSymmetricCrypto(transformation, key, iv).decrypt(data)
+ * java.createSymmetricCrypto(transformation, key, iv).decryptStr(data)
+
+ * java.createSymmetricCrypto(transformation, key, iv).encrypt(data)
+ * java.createSymmetricCrypto(transformation, key, iv).encryptBase64(data)
+ * java.createSymmetricCrypto(transformation, key, iv).encryptHex(data)
+ */
+
+ /* 调用SymmetricCrypto key为null时使用随机密钥*/
+ fun createSymmetricCrypto(
+ transformation: String,
+ key: ByteArray?,
+ iv: ByteArray?
+ ): SymmetricCrypto {
+ val symmetricCrypto = SymmetricCrypto(transformation, key)
+ return if (iv != null && iv.isNotEmpty()) symmetricCrypto.setIv(iv) else symmetricCrypto
+ }
+
+ fun createSymmetricCrypto(
+ transformation: String,
+ key: ByteArray
+ ): SymmetricCrypto {
+ return createSymmetricCrypto(transformation, key, null)
+ }
+
+ fun createSymmetricCrypto(
+ transformation: String,
+ key: String
+ ): SymmetricCrypto {
+ return createSymmetricCrypto(transformation, key, null)
+ }
+
+ fun createSymmetricCrypto(
+ transformation: String,
+ key: String,
+ iv: String?
+ ): SymmetricCrypto {
+ return createSymmetricCrypto(
+ transformation, key.encodeToByteArray(), iv?.encodeToByteArray()
+ )
+ }
+
+ //******************对称加密解密old************************//
+
+ /////AES
+ /**
+ * AES 解码为 ByteArray
+ * @param str 传入的AES加密的数据
+ * @param key AES 解密的key
+ * @param transformation AES加密的方式
+ * @param iv ECB模式的偏移向量
+ */
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).decrypt(str)")
+ )
+ fun aesDecodeToByteArray(
+ str: String, key: String, transformation: String, iv: String
+ ): ByteArray? {
+ return createSymmetricCrypto(transformation, key, iv).decrypt(str)
+ }
+
+ /**
+ * AES 解码为 String
+ * @param str 传入的AES加密的数据
+ * @param key AES 解密的key
+ * @param transformation AES加密的方式
+ * @param iv ECB模式的偏移向量
+ */
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(str)")
+ )
+ fun aesDecodeToString(
+ str: String, key: String, transformation: String, iv: String
+ ): String? {
+ return createSymmetricCrypto(transformation, key, iv).decryptStr(str)
+ }
+
+ /**
+ * AES解码为String,算法参数经过Base64加密
+ *
+ * @param data 加密的字符串
+ * @param key Base64后的密钥
+ * @param mode 模式
+ * @param padding 补码方式
+ * @param iv Base64后的加盐
+ * @return 解密后的字符串
+ */
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(data)")
+ )
+ fun aesDecodeArgsBase64Str(
+ data: String,
+ key: String,
+ mode: String,
+ padding: String,
+ iv: String
+ ): String? {
+ return createSymmetricCrypto(
+ "AES/${mode}/${padding}",
+ Base64.decode(key, Base64.NO_WRAP),
+ Base64.decode(iv, Base64.NO_WRAP)
+ ).decryptStr(data)
+ }
+
+ /**
+ * 已经base64的AES 解码为 ByteArray
+ * @param str 传入的AES Base64加密的数据
+ * @param key AES 解密的key
+ * @param transformation AES加密的方式
+ * @param iv ECB模式的偏移向量
+ */
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).decrypt(str)")
+ )
+ fun aesBase64DecodeToByteArray(
+ str: String, key: String, transformation: String, iv: String
+ ): ByteArray? {
+ return createSymmetricCrypto(transformation, key, iv).decrypt(str)
+ }
+
+ /**
+ * 已经base64的AES 解码为 String
+ * @param str 传入的AES Base64加密的数据
+ * @param key AES 解密的key
+ * @param transformation AES加密的方式
+ * @param iv ECB模式的偏移向量
+ */
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(str)")
+ )
+ fun aesBase64DecodeToString(
+ str: String, key: String, transformation: String, iv: String
+ ): String? {
+ return createSymmetricCrypto(transformation, key, iv).decryptStr(str)
+ }
+
+ /**
+ * 加密aes为ByteArray
+ * @param data 传入的原始数据
+ * @param key AES加密的key
+ * @param transformation AES加密的方式
+ * @param iv ECB模式的偏移向量
+ */
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).decrypt(data)")
+ )
+ fun aesEncodeToByteArray(
+ data: String, key: String, transformation: String, iv: String
+ ): ByteArray? {
+ return createSymmetricCrypto(transformation, key, iv).decrypt(data)
+ }
+
+ /**
+ * 加密aes为String
+ * @param data 传入的原始数据
+ * @param key AES加密的key
+ * @param transformation AES加密的方式
+ * @param iv ECB模式的偏移向量
+ */
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(data)")
+ )
+ fun aesEncodeToString(
+ data: String, key: String, transformation: String, iv: String
+ ): String? {
+ return createSymmetricCrypto(transformation, key, iv).decryptStr(data)
+ }
+
+ /**
+ * 加密aes后Base64化的ByteArray
+ * @param data 传入的原始数据
+ * @param key AES加密的key
+ * @param transformation AES加密的方式
+ * @param iv ECB模式的偏移向量
+ */
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).encryptBase64(data).toByteArray()")
+ )
+ fun aesEncodeToBase64ByteArray(
+ data: String, key: String, transformation: String, iv: String
+ ): ByteArray? {
+ return createSymmetricCrypto(transformation, key, iv).encryptBase64(data).toByteArray()
+ }
+
+ /**
+ * 加密aes后Base64化的String
+ * @param data 传入的原始数据
+ * @param key AES加密的key
+ * @param transformation AES加密的方式
+ * @param iv ECB模式的偏移向量
+ */
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).encryptBase64(data)")
+ )
+ fun aesEncodeToBase64String(
+ data: String, key: String, transformation: String, iv: String
+ ): String? {
+ return createSymmetricCrypto(transformation, key, iv).encryptBase64(data)
+ }
+
+
+ /**
+ * AES加密并转为Base64,算法参数经过Base64加密
+ *
+ * @param data 被加密的字符串
+ * @param key Base64后的密钥
+ * @param mode 模式
+ * @param padding 补码方式
+ * @param iv Base64后的加盐
+ * @return 加密后的Base64
+ */
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).encryptBase64(data)")
+ )
+ fun aesEncodeArgsBase64Str(
+ data: String,
+ key: String,
+ mode: String,
+ padding: String,
+ iv: String
+ ): String? {
+ return createSymmetricCrypto("AES/${mode}/${padding}", key, iv).encryptBase64(data)
+ }
+
+ /////DES
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(data)")
+ )
+ fun desDecodeToString(
+ data: String, key: String, transformation: String, iv: String
+ ): String? {
+ return createSymmetricCrypto(transformation, key, iv).decryptStr(data)
+ }
+
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(data)")
+ )
+ fun desBase64DecodeToString(
+ data: String, key: String, transformation: String, iv: String
+ ): String? {
+ return createSymmetricCrypto(transformation, key, iv).decryptStr(data)
+ }
+
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).encrypt(data)")
+ )
+ fun desEncodeToString(
+ data: String, key: String, transformation: String, iv: String
+ ): String? {
+ return String(createSymmetricCrypto(transformation, key, iv).encrypt(data))
+ }
+
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).encryptBase64(data)")
+ )
+ fun desEncodeToBase64String(
+ data: String, key: String, transformation: String, iv: String
+ ): String? {
+ return createSymmetricCrypto(transformation, key, iv).encryptBase64(data)
+ }
+
+ //////3DES
+ /**
+ * 3DES解密
+ *
+ * @param data 加密的字符串
+ * @param key 密钥
+ * @param mode 模式
+ * @param padding 补码方式
+ * @param iv 加盐
+ * @return 解密后的字符串
+ */
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(data)")
+ )
+ fun tripleDESDecodeStr(
+ data: String,
+ key: String,
+ mode: String,
+ padding: String,
+ iv: String
+ ): String? {
+ return createSymmetricCrypto("DESede/${mode}/${padding}", key, iv).decryptStr(data)
+ }
+
+ /**
+ * 3DES解密,算法参数经过Base64加密
+ *
+ * @param data 加密的字符串
+ * @param key Base64后的密钥
+ * @param mode 模式
+ * @param padding 补码方式
+ * @param iv Base64后的加盐
+ * @return 解密后的字符串
+ */
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).decryptStr(data)")
+ )
+ fun tripleDESDecodeArgsBase64Str(
+ data: String,
+ key: String,
+ mode: String,
+ padding: String,
+ iv: String
+ ): String? {
+ return createSymmetricCrypto(
+ "DESede/${mode}/${padding}",
+ Base64.decode(key, Base64.NO_WRAP),
+ iv.encodeToByteArray()
+ ).decryptStr(data)
+ }
+
+
+ /**
+ * 3DES加密并转为Base64
+ *
+ * @param data 被加密的字符串
+ * @param key 密钥
+ * @param mode 模式
+ * @param padding 补码方式
+ * @param iv 加盐
+ * @return 加密后的Base64
+ */
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).encryptBase64(data)")
+ )
+ fun tripleDESEncodeBase64Str(
+ data: String,
+ key: String,
+ mode: String,
+ padding: String,
+ iv: String
+ ): String? {
+ return createSymmetricCrypto("DESede/${mode}/${padding}", key, iv)
+ .encryptBase64(data)
+ }
+
+ /**
+ * 3DES加密并转为Base64,算法参数经过Base64加密
+ *
+ * @param data 被加密的字符串
+ * @param key Base64后的密钥
+ * @param mode 模式
+ * @param padding 补码方式
+ * @param iv Base64后的加盐
+ * @return 加密后的Base64
+ */
+ @Deprecated(
+ "过于繁琐弃用",
+ ReplaceWith("createSymmetricCrypto(transformation, key, iv).encryptBase64(data)")
+ )
+ fun tripleDESEncodeArgsBase64Str(
+ data: String,
+ key: String,
+ mode: String,
+ padding: String,
+ iv: String
+ ): String? {
+ return createSymmetricCrypto(
+ "DESede/${mode}/${padding}",
+ Base64.decode(key, Base64.NO_WRAP),
+ iv.encodeToByteArray()
+ ).encryptBase64(data)
+ }
+
+//******************消息摘要/散列消息鉴别码************************//
+
+ /**
+ * 生成摘要,并转为16进制字符串
+ *
+ * @param data 被摘要数据
+ * @param algorithm 签名算法
+ * @return 16进制字符串
+ */
+ fun digestHex(
+ data: String,
+ algorithm: String,
+ ): String {
+ return DigestUtil.digester(algorithm).digestHex(data)
+ }
+
+ /**
+ * 生成摘要,并转为Base64字符串
+ *
+ * @param data 被摘要数据
+ * @param algorithm 签名算法
+ * @return Base64字符串
+ */
+ fun digestBase64Str(
+ data: String,
+ algorithm: String,
+ ): String {
+ return Base64.encodeToString(DigestUtil.digester(algorithm).digest(data), Base64.NO_WRAP)
+ }
+
+ /**
+ * 生成散列消息鉴别码,并转为16进制字符串
+ *
+ * @param data 被摘要数据
+ * @param algorithm 签名算法
+ * @param key 密钥
+ * @return 16进制字符串
+ */
+ @Suppress("FunctionName")
+ fun HMacHex(
+ data: String,
+ algorithm: String,
+ key: String
+ ): String {
+ return HMac(algorithm, key.toByteArray()).digestHex(data)
+ }
+
+ /**
+ * 生成散列消息鉴别码,并转为Base64字符串
+ *
+ * @param data 被摘要数据
+ * @param algorithm 签名算法
+ * @param key 密钥
+ * @return Base64字符串
+ */
+ @Suppress("FunctionName")
+ fun HMacBase64(
+ data: String,
+ algorithm: String,
+ key: String
+ ): String {
+ return Base64.encodeToString(
+ HMac(algorithm, key.toByteArray()).digest(data),
+ Base64.NO_WRAP
+ )
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt b/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt
index 948c090..98bd8b9 100644
--- a/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt
+++ b/app/src/main/java/xyz/fycz/myreader/model/third3/analyzeRule/JsExtensions.kt
@@ -22,6 +22,7 @@ import android.net.Uri
import android.util.Base64
import android.util.Log
import androidx.annotation.Keep
+import cn.hutool.core.util.HexUtil
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
@@ -34,7 +35,9 @@ import xyz.fycz.myreader.greendao.service.CacheManager
import xyz.fycz.myreader.greendao.service.CookieStore
import xyz.fycz.myreader.model.third3.BaseSource
import xyz.fycz.myreader.model.third3.Debug
+import xyz.fycz.myreader.model.third3.NoStackTraceException
import xyz.fycz.myreader.model.third3.http.*
+import xyz.fycz.myreader.util.ToastUtils
import xyz.fycz.myreader.util.ZipUtils
import xyz.fycz.myreader.util.utils.*
import java.io.ByteArrayInputStream
@@ -54,7 +57,7 @@ import java.util.zip.ZipInputStream
*/
@Keep
@Suppress("unused")
-interface JsExtensions {
+interface JsExtensions : JsEncodeUtils {
val TAG: String?
get() = JsExtensions::class.simpleName
@@ -143,11 +146,50 @@ interface JsExtensions {
html = html,
javaScript = js,
headerMap = getSource()?.getHeaderMap(true),
- tag = getSource()?.getKey()
+ tag = getSource()?.getKey()
).getStrResponse().body
}
}
+ /**
+ * 可从网络,本地文件(阅读私有缓存目录和书籍保存位置支持相对路径)导入JavaScript脚本
+ */
+ fun importScript(path: String): String {
+ val result = when {
+ path.startsWith("http") -> cacheFile(path) ?: ""
+ path.isUri() -> String(DocumentUtil.readBytes(App.getmContext(), Uri.parse(path)))
+ path.startsWith("/storage") -> FileUtils.readText(path)
+ else -> readTxtFile(path)
+ }
+ if (result.isBlank()) throw NoStackTraceException("$path 内容获取失败或者为空")
+ return result
+ }
+
+ /**
+ * 缓存以文本方式保存的文件 如.js .txt等
+ * @param urlStr 网络文件的链接
+ * @return 返回缓存后的文件内容
+ */
+ fun cacheFile(urlStr: String): String? {
+ return cacheFile(urlStr, 0)
+ }
+
+ /**
+ * 缓存以文本方式保存的文件 如.js .txt等
+ * @param saveTime 缓存时间,单位:秒
+ */
+ fun cacheFile(urlStr: String, saveTime: Int): String? {
+ val key = md5Encode16(urlStr)
+ val cache = CacheManager.getFile(key)
+ if (cache.isNullOrBlank()) {
+ log("首次下载 $urlStr")
+ val value = ajax(urlStr) ?: return null
+ CacheManager.putFile(key, value, saveTime)
+ return value
+ }
+ return cache
+ }
+
/**
* 实现16进制字符串转文件
* @param content 需要转成文件的16进制字符串
@@ -174,20 +216,45 @@ interface JsExtensions {
* js实现重定向拦截,网络访问get
*/
fun get(urlStr: String, headers: Map): Connection.Response {
- return Jsoup.connect(urlStr)
+ val response = Jsoup.connect(urlStr)
.sslSocketFactory(SSLHelper.unsafeSSLSocketFactory)
.ignoreContentType(true)
.followRedirects(false)
.headers(headers)
.method(Connection.Method.GET)
.execute()
+ val cookies = response.cookies()
+ CookieStore.mapToCookie(cookies)?.let {
+ val domain = NetworkUtils.getSubDomain(urlStr)
+ CacheManager.putMemory("${domain}_cookieJar", it)
+ }
+ return response
+ }
+
+ /**
+ * js实现重定向拦截,网络访问head,不返回Response Body更省流量
+ */
+ fun head(urlStr: String, headers: Map): Connection.Response {
+ val response = Jsoup.connect(urlStr)
+ .sslSocketFactory(SSLHelper.unsafeSSLSocketFactory)
+ .ignoreContentType(true)
+ .followRedirects(false)
+ .headers(headers)
+ .method(Connection.Method.HEAD)
+ .execute()
+ val cookies = response.cookies()
+ CookieStore.mapToCookie(cookies)?.let {
+ val domain = NetworkUtils.getSubDomain(urlStr)
+ CacheManager.putMemory("${domain}_cookieJar", it)
+ }
+ return response
}
/**
* 网络访问post
*/
fun post(urlStr: String, body: String, headers: Map): Connection.Response {
- return Jsoup.connect(urlStr)
+ val response = Jsoup.connect(urlStr)
.sslSocketFactory(SSLHelper.unsafeSSLSocketFactory)
.ignoreContentType(true)
.followRedirects(false)
@@ -195,6 +262,12 @@ interface JsExtensions {
.headers(headers)
.method(Connection.Method.POST)
.execute()
+ val cookies = response.cookies()
+ CookieStore.mapToCookie(cookies)?.let {
+ val domain = NetworkUtils.getSubDomain(urlStr)
+ CacheManager.putMemory("${domain}_cookieJar", it)
+ }
+ return response
}
/**
@@ -243,12 +316,19 @@ interface JsExtensions {
return EncoderUtils.base64Encode(str, flags)
}
- fun md5Encode(str: String): String {
- return MD5Utils.md5Encode(str)
+ /* HexString 解码为字节数组 */
+ fun hexDecodeToByteArray(hex: String): ByteArray? {
+ return HexUtil.decodeHex(hex)
+ }
+
+ /* hexString 解码为utf8String*/
+ fun hexDecodeToString(hex: String): String? {
+ return HexUtil.decodeHexStr(hex)
}
- fun md5Encode16(str: String): String {
- return MD5Utils.md5Encode16(str)
+ /* utf8 编码为hexString */
+ fun hexEncodeToString(utf8: String): String? {
+ return HexUtil.encodeHexStr(utf8)
}
/**
@@ -501,174 +581,48 @@ interface JsExtensions {
}
/**
- * 输出调试日志
+ * 弹窗提示
*/
- fun log(msg: String): String {
- getSource()?.let {
- Debug.log(it.getKey(), msg)
- } ?: Debug.log(msg)
- if (App.isDebug()) {
- Log.d(TAG + "-" + getSource()?.getKey(), msg)
- }
- return msg
+ fun toast(msg: Any?) {
+ ToastUtils.showInfo("${getSource()?.getTag()}: ${msg.toString()}")
}
/**
- * 生成UUID
+ * 弹窗提示 停留时间较长
*/
- fun randomUUID(): String {
- return UUID.randomUUID().toString()
+ fun longToast(msg: Any?) {
+ toast(msg)
}
/**
- * AES 解码为 ByteArray
- * @param str 传入的AES加密的数据
- * @param key AES 解密的key
- * @param transformation AES加密的方式
- * @param iv ECB模式的偏移向量
- */
- fun aesDecodeToByteArray(
- str: String, key: String, transformation: String, iv: String
- ): ByteArray? {
- return try {
- EncoderUtils.decryptAES(
- data = str.encodeToByteArray(),
- key = key.encodeToByteArray(),
- transformation,
- iv.encodeToByteArray()
- )
- } catch (e: Exception) {
- Log.e(TAG, e.toString())
- log(e.localizedMessage ?: "aesDecodeToByteArrayERROR")
- null
- }
- }
-
- /**
- * AES 解码为 String
- * @param str 传入的AES加密的数据
- * @param key AES 解密的key
- * @param transformation AES加密的方式
- * @param iv ECB模式的偏移向量
- */
-
- fun aesDecodeToString(
- str: String, key: String, transformation: String, iv: String
- ): String? {
- return aesDecodeToByteArray(str, key, transformation, iv)?.let { String(it) }
- }
-
- /**
- * 已经base64的AES 解码为 ByteArray
- * @param str 传入的AES Base64加密的数据
- * @param key AES 解密的key
- * @param transformation AES加密的方式
- * @param iv ECB模式的偏移向量
- */
-
- fun aesBase64DecodeToByteArray(
- str: String, key: String, transformation: String, iv: String
- ): ByteArray? {
- return try {
- EncoderUtils.decryptBase64AES(
- str.encodeToByteArray(),
- key.encodeToByteArray(),
- transformation,
- iv.encodeToByteArray()
- )
- } catch (e: Exception) {
- Log.e(TAG, e.toString())
- log(e.localizedMessage ?: "aesDecodeToByteArrayERROR")
- null
- }
- }
-
- /**
- * 已经base64的AES 解码为 String
- * @param str 传入的AES Base64加密的数据
- * @param key AES 解密的key
- * @param transformation AES加密的方式
- * @param iv ECB模式的偏移向量
- */
-
- fun aesBase64DecodeToString(
- str: String, key: String, transformation: String, iv: String
- ): String? {
- return aesBase64DecodeToByteArray(str, key, transformation, iv)?.let { String(it) }
- }
-
- /**
- * 加密aes为ByteArray
- * @param data 传入的原始数据
- * @param key AES加密的key
- * @param transformation AES加密的方式
- * @param iv ECB模式的偏移向量
+ * 输出调试日志
*/
- fun aesEncodeToByteArray(
- data: String, key: String, transformation: String, iv: String
- ): ByteArray? {
- return try {
- EncoderUtils.encryptAES(
- data.encodeToByteArray(),
- key = key.encodeToByteArray(),
- transformation,
- iv.encodeToByteArray()
- )
- } catch (e: Exception) {
- Log.e(TAG, e.toString())
- log(e.localizedMessage ?: "aesEncodeToByteArrayERROR")
- null
+ fun log(msg: String): String {
+ getSource()?.let {
+ Debug.log(it.getKey(), msg)
+ } ?: Debug.log(msg)
+ if (App.isDebug()) {
+ Log.d(TAG + "-" + getSource()?.getKey(), msg)
}
+ return msg
}
/**
- * 加密aes为String
- * @param data 传入的原始数据
- * @param key AES加密的key
- * @param transformation AES加密的方式
- * @param iv ECB模式的偏移向量
- */
- fun aesEncodeToString(
- data: String, key: String, transformation: String, iv: String
- ): String? {
- return aesEncodeToByteArray(data, key, transformation, iv)?.let { String(it) }
- }
-
- /**
- * 加密aes后Base64化的ByteArray
- * @param data 传入的原始数据
- * @param key AES加密的key
- * @param transformation AES加密的方式
- * @param iv ECB模式的偏移向量
+ * 输出对象类型
*/
- fun aesEncodeToBase64ByteArray(
- data: String, key: String, transformation: String, iv: String
- ): ByteArray? {
- return try {
- EncoderUtils.encryptAES2Base64(
- data.encodeToByteArray(),
- key.encodeToByteArray(),
- transformation,
- iv.encodeToByteArray()
- )
- } catch (e: Exception) {
- Log.e(TAG, e.toString())
- log(e.localizedMessage ?: "aesEncodeToBase64ByteArrayERROR")
- null
+ fun logType(any: Any?) {
+ if (any == null) {
+ log("null")
+ } else {
+ log(any.javaClass.name)
}
}
/**
- * 加密aes后Base64化的String
- * @param data 传入的原始数据
- * @param key AES加密的key
- * @param transformation AES加密的方式
- * @param iv ECB模式的偏移向量
+ * 生成UUID
*/
- fun aesEncodeToBase64String(
- data: String, key: String, transformation: String, iv: String
- ): String? {
- return aesEncodeToBase64ByteArray(data, key, transformation, iv)?.let { String(it) }
+ fun randomUUID(): String {
+ return UUID.randomUUID().toString()
}
fun android(): String {
diff --git a/app/src/main/java/xyz/fycz/myreader/util/utils/StringExtensions.kt b/app/src/main/java/xyz/fycz/myreader/util/utils/StringExtensions.kt
index 0182804..87d191a 100644
--- a/app/src/main/java/xyz/fycz/myreader/util/utils/StringExtensions.kt
+++ b/app/src/main/java/xyz/fycz/myreader/util/utils/StringExtensions.kt
@@ -23,6 +23,7 @@ package xyz.fycz.myreader.util.utils
import android.icu.text.Collator
import android.icu.util.ULocale
import android.net.Uri
+import android.text.Editable
import java.io.File
import java.util.*
@@ -30,14 +31,19 @@ fun String?.safeTrim() = if (this.isNullOrBlank()) null else this.trim()
fun String?.isContentScheme(): Boolean = this?.startsWith("content://") == true
+fun String.toEditable(): Editable = Editable.Factory.getInstance().newEditable(this)
+
fun String.parseToUri(): Uri {
- return if (isContentScheme()) {
- Uri.parse(this)
- } else {
+ return if (isUri()) Uri.parse(this) else {
Uri.fromFile(File(this))
}
}
+fun String?.isUri(): Boolean {
+ this ?: return false
+ return this.startsWith("file://", true) || isContentScheme()
+}
+
fun String?.isAbsUrl() =
this?.let {
it.startsWith("http://", true) || it.startsWith("https://", true)
@@ -65,8 +71,22 @@ fun String?.isJsonArray(): Boolean =
str.startsWith("[") && str.endsWith("]")
} ?: false
-fun String.splitNotBlank(vararg delimiter: String): Array = run {
- this.split(*delimiter).map { it.trim() }.filterNot { it.isBlank() }.toTypedArray()
+fun String?.isXml(): Boolean =
+ this?.run {
+ val str = this.trim()
+ str.startsWith("<") && str.endsWith(">")
+ } ?: false
+
+fun String?.isTrue(nullIsTrue: Boolean = false): Boolean {
+ if (this.isNullOrBlank() || this == "null") {
+ return nullIsTrue
+ }
+ return !this.trim().matches("(?i)^(false|no|not|0)$".toRegex())
+}
+
+fun String.splitNotBlank(vararg delimiter: String, limit: Int = 0): Array = run {
+ this.split(*delimiter, limit = limit).map { it.trim() }.filterNot { it.isBlank() }
+ .toTypedArray()
}
fun String.splitNotBlank(regex: Regex, limit: Int = 0): Array = run {
@@ -97,3 +117,4 @@ fun String.toStringArray(): Array {
}
}
+