You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
SmsForwarder/app/src/main/java/com/idormy/sms/forwarder/utils/HttpServerUtils.kt

229 lines
9.2 KiB
Kotlin

package com.idormy.sms.forwarder.utils
import android.text.TextUtils
import android.util.Base64
import android.util.Log
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.Core
import com.idormy.sms.forwarder.entity.CloneInfo
import com.idormy.sms.forwarder.entity.LocationInfo
import com.idormy.sms.forwarder.server.model.BaseRequest
import com.xuexiang.xui.utils.ResUtils.getString
import com.xuexiang.xutil.app.AppUtils
import com.yanzhenjie.andserver.error.HttpException
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
/**
* HttpServer工具类
*/
@Suppress("DEPRECATION")
class HttpServerUtils private constructor() {
companion object {
//是否启用HttpServer开机自启
var enableServerAutorun: Boolean by SharedPreference(SP_ENABLE_SERVER_AUTORUN, false)
//服务端签名密钥
var serverSignKey: String by SharedPreference(SP_SERVER_SIGN_KEY, "")
//服务端安全设置
var safetyMeasures: Int by SharedPreference(SP_SERVER_SAFETY_MEASURES, if (TextUtils.isEmpty(serverSignKey)) 0 else 1)
//服务端SM4密钥
var serverSm4Key: String by SharedPreference(SP_SERVER_SM4_KEY, "")
//服务端RSA公钥
var serverPublicKey: String by SharedPreference(SP_SERVER_PUBLIC_KEY, "")
//服务端RSA私钥
var serverPrivateKey: String by SharedPreference(SP_SERVER_PRIVATE_KEY, "")
//时间容差
var timeTolerance: Int by SharedPreference(SP_SERVER_TIME_TOLERANCE, 600)
//自定义web客户端目录
var serverWebPath: String by SharedPreference(SP_SERVER_WEB_PATH, "")
//服务地址
var serverAddress: String by SharedPreference(SP_SERVER_ADDRESS, "http://127.0.0.1:5000")
//服务地址历史记录
var serverHistory: String by SharedPreference(SP_SERVER_HISTORY, "")
//服务端配置
var serverConfig: String by SharedPreference(SP_SERVER_CONFIG, "")
//客户端签名密钥/RSA公钥
var clientSignKey: String by SharedPreference(SP_CLIENT_SIGN_KEY, "")
//服务端安全设置
var clientSafetyMeasures: Int by SharedPreference(SP_CLIENT_SAFETY_MEASURES, if (TextUtils.isEmpty(clientSignKey)) 0 else 1)
//是否启用一键克隆
var enableApiClone: Boolean by SharedPreference(SP_ENABLE_API_CLONE, true)
//是否启用远程发短信
var enableApiSmsSend: Boolean by SharedPreference(SP_ENABLE_API_SMS_SEND, true)
//是否启用远程查短信
var enableApiSmsQuery: Boolean by SharedPreference(SP_ENABLE_API_SMS_QUERY, true)
//是否启用远程查通话
var enableApiCallQuery: Boolean by SharedPreference(SP_ENABLE_API_CALL_QUERY, true)
//是否启用远程查话簿
var enableApiContactQuery: Boolean by SharedPreference(SP_ENABLE_API_CONTACT_QUERY, true)
//是否启用远程加话簿
var enableApiContactAdd: Boolean by SharedPreference(SP_ENABLE_API_CONTACT_ADD, true)
//是否启用远程查电量
var enableApiBatteryQuery: Boolean by SharedPreference(SP_ENABLE_API_BATTERY_QUERY, true)
//是否启用远程WOL
var enableApiWol: Boolean by SharedPreference(SP_ENABLE_API_WOL, true)
//是否启用远程找手机
var enableApiLocation: Boolean by SharedPreference(SP_ENABLE_API_LOCATION, false)
//远程找手机定位缓存
var apiLocationCache: LocationInfo by SharedPreference(SP_API_LOCATION_CACHE, LocationInfo())
//WOL历史记录
var wolHistory: String by SharedPreference(SP_WOL_HISTORY, "")
//计算签名
fun calcSign(timestamp: String, signSecret: String): String {
val stringToSign = "$timestamp\n" + signSecret
val mac = Mac.getInstance("HmacSHA256")
mac.init(SecretKeySpec(signSecret.toByteArray(StandardCharsets.UTF_8), "HmacSHA256"))
val signData = mac.doFinal(stringToSign.toByteArray(StandardCharsets.UTF_8))
return URLEncoder.encode(String(Base64.encode(signData, Base64.NO_WRAP)), "UTF-8")
}
//校验签名
@Throws(HttpException::class)
fun checkSign(req: BaseRequest<*>) {
val signSecret = serverSignKey
if (TextUtils.isEmpty(signSecret)) return
if (TextUtils.isEmpty(req.sign)) throw HttpException(500, getString(R.string.sign_required))
if (req.timestamp == 0L) throw HttpException(500, getString(R.string.timestamp_required))
val timestamp = System.currentTimeMillis()
val diffTime = kotlin.math.abs(timestamp - req.timestamp)
val tolerance = timeTolerance * 1000L
if (diffTime > tolerance) {
throw HttpException(500, String.format(getString(R.string.timestamp_verify_failed), timestamp, timeTolerance, diffTime))
}
val sign = calcSign(req.timestamp.toString(), signSecret)
if (sign != req.sign) {
Log.e("calcSign", sign)
Log.e("reqSign", req.sign.toString())
throw HttpException(500, getString(R.string.sign_verify_failed))
}
}
//判断版本是否一致
@Throws(HttpException::class)
fun compareVersion(cloneInfo: CloneInfo) {
val versionCodeRequest = cloneInfo.versionCode
if (versionCodeRequest == 0) throw HttpException(500, getString(R.string.version_code_required))
val versionCodeLocal = AppUtils.getAppVersionCode().toString().substring(1)
if (!versionCodeRequest.toString().endsWith(versionCodeLocal)) throw HttpException(500, getString(R.string.inconsistent_version))
}
//导出设置
fun exportSettings(): CloneInfo {
val cloneInfo = CloneInfo()
cloneInfo.versionCode = AppUtils.getAppVersionCode()
cloneInfo.versionName = AppUtils.getAppVersionName()
cloneInfo.settings = SharedPreference.exportPreference()
cloneInfo.senderList = Core.sender.getAllNonCache()
cloneInfo.ruleList = Core.rule.getAllNonCache()
cloneInfo.frpcList = Core.frpc.getAllNonCache()
cloneInfo.taskList = Core.task.getAllNonCache()
return cloneInfo
}
//还原设置
fun restoreSettings(cloneInfo: CloneInfo): Boolean {
return try {
//应用配置
SharedPreference.clearPreference()
SharedPreference.importPreference(cloneInfo.settings)
//需要排除的配置
SettingUtils.extraDeviceMark = ""
SettingUtils.subidSim1 = 0
SettingUtils.extraSim1 = ""
SettingUtils.subidSim2 = 0
SettingUtils.extraSim2 = ""
//删除消息与转发日志
Core.logs.deleteAll()
Core.msg.deleteAll()
//发送通道
Core.sender.deleteAll()
if (!cloneInfo.senderList.isNullOrEmpty()) {
for (sender in cloneInfo.senderList!!) {
Core.sender.insert(sender)
}
}
//转发规则
Core.rule.deleteAll()
if (!cloneInfo.ruleList.isNullOrEmpty()) {
for (rule in cloneInfo.ruleList!!) {
Core.rule.insert(rule)
}
}
//Frpc配置
Core.frpc.deleteAll()
if (!cloneInfo.frpcList.isNullOrEmpty()) {
for (frpc in cloneInfo.frpcList!!) {
Core.frpc.insert(frpc)
}
}
//Task配置
Core.task.deleteAll()
if (!cloneInfo.taskList.isNullOrEmpty()) {
for (task in cloneInfo.taskList!!) {
Core.task.insert(task)
}
}
true
} catch (e: Exception) {
e.printStackTrace()
throw HttpException(500, e.message)
//false
}
}
//返回统一结构报文
fun response(output: Any?): String {
val resp: MutableMap<String, Any> = mutableMapOf()
val timestamp = System.currentTimeMillis()
resp["timestamp"] = timestamp
if (output is String && output != "success") {
resp["code"] = HTTP_FAILURE_CODE
resp["msg"] = output
} else {
resp["code"] = HTTP_SUCCESS_CODE
resp["msg"] = "success"
if (output != null) {
resp["data"] = output
}
if (safetyMeasures == 1) {
resp["sign"] = calcSign(timestamp.toString(), serverSignKey)
}
}
return Gson().toJson(resp)
}
}
}