Add HYSTERIA2 for v2fly

This commit is contained in:
2dust
2024-09-25 14:29:50 +08:00
parent 97c467af41
commit cfa709c651
21 changed files with 201 additions and 29 deletions
@@ -146,4 +146,6 @@ object AppConfig {
const val VLESS = "vless://"
const val TROJAN = "trojan://"
const val WIREGUARD = "wireguard://"
const val TUIC = "tuic://"
const val HYSTERIA2 = "hysteria2://"
}
@@ -11,6 +11,8 @@ enum class EConfigType(val value: Int, val protocolScheme: String) {
VLESS(5, AppConfig.VLESS),
TROJAN(6, AppConfig.TROJAN),
WIREGUARD(7, AppConfig.WIREGUARD),
// TUIC(8, AppConfig.TUIC),
HYSTERIA2(9, AppConfig.HYSTERIA2),
HTTP(10, AppConfig.HTTP);
companion object {
@@ -16,7 +16,8 @@ data class ServerConfig(
companion object {
fun create(configType: EConfigType): ServerConfig {
when (configType) {
EConfigType.VMESS, EConfigType.VLESS ->
EConfigType.VMESS,
EConfigType.VLESS ->
return ServerConfig(
configType = configType,
outboundBean = V2rayConfig.OutboundBean(
@@ -38,7 +39,8 @@ data class ServerConfig(
EConfigType.SHADOWSOCKS,
EConfigType.SOCKS,
EConfigType.HTTP,
EConfigType.TROJAN ->
EConfigType.TROJAN,
EConfigType.HYSTERIA2 ->
return ServerConfig(
configType = configType,
outboundBean = V2rayConfig.OutboundBean(
@@ -147,8 +147,6 @@ data class V2rayConfig(
val ivCheck: Boolean? = null,
var users: List<SocksUsersBean>? = null
) {
data class SocksUsersBean(
var user: String = "",
var pass: String = "",
@@ -177,6 +175,7 @@ data class V2rayConfig(
var quicSettings: QuicSettingBean? = null,
var realitySettings: TlsSettingsBean? = null,
var grpcSettings: GrpcSettingsBean? = null,
var hy2steriaSettings: Hy2steriaSettingsBean? = null,
val dsSettings: Any? = null,
var sockopt: SockoptBean? = null
) {
@@ -295,6 +294,18 @@ data class V2rayConfig(
var health_check_timeout: Int? = null
)
data class Hy2steriaSettingsBean(
var password: String? = null,
var use_udp_extension: Boolean? = true,
var congestion: Hy2CongestionBean? = null
) {
data class Hy2CongestionBean(
var type: String? = "bbr",
var up_mbps: Int? = null,
var down_mbps: Int? = null,
)
}
fun populateTransportSettings(
transport: String, headerType: String?, host: String?, path: String?, seed: String?,
quicSecurity: String?, key: String?, mode: String?, serviceName: String?,
@@ -427,6 +438,7 @@ data class V2rayConfig(
|| protocol.equals(EConfigType.SOCKS.name, true)
|| protocol.equals(EConfigType.HTTP.name, true)
|| protocol.equals(EConfigType.TROJAN.name, true)
|| protocol.equals(EConfigType.HYSTERIA2.name, true)
) {
return settings?.servers?.get(0)?.address
} else if (protocol.equals(EConfigType.WIREGUARD.name, true)) {
@@ -444,6 +456,7 @@ data class V2rayConfig(
|| protocol.equals(EConfigType.SOCKS.name, true)
|| protocol.equals(EConfigType.HTTP.name, true)
|| protocol.equals(EConfigType.TROJAN.name, true)
|| protocol.equals(EConfigType.HYSTERIA2.name, true)
) {
return settings?.servers?.get(0)?.port
} else if (protocol.equals(EConfigType.WIREGUARD.name, true)) {
@@ -465,10 +478,12 @@ data class V2rayConfig(
return settings?.vnext?.get(0)?.users?.get(0)?.id
} else if (protocol.equals(EConfigType.SHADOWSOCKS.name, true)
|| protocol.equals(EConfigType.TROJAN.name, true)
|| protocol.equals(EConfigType.HYSTERIA2.name, true)
) {
return settings?.servers?.get(0)?.password
} else if (protocol.equals(EConfigType.SOCKS.name, true)
|| protocol.equals(EConfigType.HTTP.name, true)) {
|| protocol.equals(EConfigType.HTTP.name, true)
) {
return settings?.servers?.get(0)?.users?.get(0)?.pass
} else if (protocol.equals(EConfigType.WIREGUARD.name, true)) {
return settings?.secretKey
@@ -597,6 +612,7 @@ data class V2rayConfig(
) {
data class RulesBean(
var type: String = "field",
var ip: ArrayList<String>? = null,
var domain: ArrayList<String>? = null,
var outboundTag: String = "",
@@ -51,7 +51,7 @@ object V2RayServiceManager {
set(value) {
field = value
Seq.setContext(value?.get()?.getService()?.applicationContext)
Libv2ray.initV2Env(Utils.userAssetPath(value?.get()?.getService()), Utils.getDeviceIdForXUDPBaseKey())
Libv2ray.initV2Env(Utils.userAssetPath(value?.get()?.getService()))//, Utils.getDeviceIdForXUDPBaseKey())
}
var currentConfig: ServerConfig? = null
@@ -24,7 +24,7 @@ class V2RayTestService : Service() {
override fun onCreate() {
super.onCreate()
Seq.setContext(this)
Libv2ray.initV2Env(Utils.userAssetPath(this), Utils.getDeviceIdForXUDPBaseKey())
Libv2ray.initV2Env(Utils.userAssetPath(this)) //Utils.getDeviceIdForXUDPBaseKey())
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
@@ -292,6 +292,11 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
true
}
R.id.import_manually_hysteria2 -> {
importManually(EConfigType.HYSTERIA2.value)
true
}
R.id.import_config_custom_clipboard -> {
importConfigCustomClipboard()
true
@@ -134,6 +134,7 @@ class ServerActivity : BaseActivity() {
EConfigType.VLESS -> setContentView(R.layout.activity_server_vless)
EConfigType.TROJAN -> setContentView(R.layout.activity_server_trojan)
EConfigType.WIREGUARD -> setContentView(R.layout.activity_server_wireguard)
EConfigType.HYSTERIA2 -> setContentView(R.layout.activity_server_hysteria2)
}
sp_network?.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
@@ -411,7 +412,10 @@ class ServerActivity : BaseActivity() {
&& config.configType != EConfigType.HTTP
&& TextUtils.isEmpty(et_id.text.toString())
) {
if (config.configType == EConfigType.TROJAN || config.configType == EConfigType.SHADOWSOCKS) {
if (config.configType == EConfigType.TROJAN
|| config.configType == EConfigType.SHADOWSOCKS
|| config.configType == EConfigType.HYSTERIA2
) {
toast(R.string.server_lab_id3)
} else {
toast(R.string.server_lab_id)
@@ -443,8 +447,10 @@ class ServerActivity : BaseActivity() {
wireguard?.peers?.get(0)?.let { _ ->
savePeer(wireguard, port)
}
config.outboundBean?.streamSettings?.let {
saveStreamSettings(it)
val sni = saveStreamSettings(it)
saveTls(it, sni)
}
if (config.subscriptionId.isEmpty() && !subscriptionId.isNullOrEmpty()) {
config.subscriptionId = subscriptionId.orEmpty()
@@ -493,7 +499,7 @@ class ServerActivity : BaseActivity() {
socksUsersBean.pass = et_id.text.toString().trim()
server.users = listOf(socksUsersBean)
}
} else if (config.configType == EConfigType.TROJAN) {
} else if (config.configType == EConfigType.TROJAN || config.configType == EConfigType.HYSTERIA2) {
server.password = et_id.text.toString().trim()
}
}
@@ -515,21 +521,13 @@ class ServerActivity : BaseActivity() {
wireguard.mtu = Utils.parseInt(et_local_mtu?.text.toString())
}
private fun saveStreamSettings(streamSetting: V2rayConfig.OutboundBean.StreamSettingsBean) {
val network = sp_network?.selectedItemPosition ?: return
val type = sp_header_type?.selectedItemPosition ?: return
val requestHost = et_request_host?.text?.toString()?.trim() ?: return
val path = et_path?.text?.toString()?.trim() ?: return
val sniField = et_sni?.text?.toString()?.trim() ?: return
val allowInsecureField = sp_allow_insecure?.selectedItemPosition ?: return
val streamSecurity = sp_stream_security?.selectedItemPosition ?: return
val utlsIndex = sp_stream_fingerprint?.selectedItemPosition ?: return
val alpnIndex = sp_stream_alpn?.selectedItemPosition ?: return
val publicKey = et_public_key?.text?.toString()?.trim() ?: return
val shortId = et_short_id?.text?.toString()?.trim() ?: return
val spiderX = et_spider_x?.text?.toString()?.trim() ?: return
private fun saveStreamSettings(streamSetting: V2rayConfig.OutboundBean.StreamSettingsBean): String? {
val network = sp_network?.selectedItemPosition ?: return null
val type = sp_header_type?.selectedItemPosition ?: return null
val requestHost = et_request_host?.text?.toString()?.trim() ?: return null
val path = et_path?.text?.toString()?.trim() ?: return null
var sni = streamSetting.populateTransportSettings(
val sni = streamSetting.populateTransportSettings(
transport = networks[network],
headerType = transportTypes(networks[network])[type],
host = requestHost,
@@ -541,10 +539,21 @@ class ServerActivity : BaseActivity() {
serviceName = path,
authority = requestHost,
)
if (sniField.isNotBlank()) {
sni = sniField
}
val allowInsecure = if (allowinsecures[allowInsecureField].isBlank()) {
return sni
}
private fun saveTls(streamSetting: V2rayConfig.OutboundBean.StreamSettingsBean, sni: String?) {
val streamSecurity = sp_stream_security?.selectedItemPosition ?: return
val sniField = et_sni?.text?.toString()?.trim()
val allowInsecureField = sp_allow_insecure?.selectedItemPosition
val utlsIndex = sp_stream_fingerprint?.selectedItemPosition ?: 0
val alpnIndex = sp_stream_alpn?.selectedItemPosition ?: 0
val publicKey = et_public_key?.text?.toString()
val shortId = et_short_id?.text?.toString()
val spiderX = et_spider_x?.text?.toString()
val allowInsecure = if (allowInsecureField == null || allowinsecures[allowInsecureField].isBlank()) {
settingsStorage?.decodeBool(PREF_ALLOW_INSECURE) ?: false
} else {
allowinsecures[allowInsecureField].toBoolean()
@@ -553,7 +562,7 @@ class ServerActivity : BaseActivity() {
streamSetting.populateTlsSettings(
streamSecurity = streamSecuritys[streamSecurity],
allowInsecure = allowInsecure,
sni = sni,
sni = sniField ?: sni ?: "",
fingerprint = uTlsItems[utlsIndex],
alpns = alpns[alpnIndex],
publicKey = publicKey,
@@ -14,6 +14,7 @@ import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
import com.v2ray.ang.dto.*
import com.v2ray.ang.util.MmkvManager.settingsStorage
import com.v2ray.ang.util.fmt.Hysteria2Fmt
import com.v2ray.ang.util.fmt.ShadowsocksFmt
import com.v2ray.ang.util.fmt.SocksFmt
import com.v2ray.ang.util.fmt.TrojanFmt
@@ -50,6 +51,8 @@ object AngConfigManager {
VlessFmt.parseVless(str)
} else if (str.startsWith(EConfigType.WIREGUARD.protocolScheme)) {
WireguardFmt.parseWireguard(str)
} else if (str.startsWith(EConfigType.HYSTERIA2.protocolScheme)) {
Hysteria2Fmt.parseHysteria2(str)
} else {
null
}
@@ -92,6 +95,7 @@ object AngConfigManager {
EConfigType.VLESS -> VlessFmt.toUri(config)
EConfigType.TROJAN -> TrojanFmt.toUri(config)
EConfigType.WIREGUARD -> WireguardFmt.toUri(config)
EConfigType.HYSTERIA2 -> Hysteria2Fmt.toUri(config)
}
} catch (e: Exception) {
e.printStackTrace()
@@ -380,6 +380,7 @@ object V2rayConfigUtil {
|| protocol.equals(EConfigType.HTTP.name, true)
|| protocol.equals(EConfigType.TROJAN.name, true)
|| protocol.equals(EConfigType.WIREGUARD.name, true)
|| protocol.equals(EConfigType.HYSTERIA2.name, true)
) {
muxEnabled = false
} else if (protocol.equals(EConfigType.VLESS.name, true)
@@ -0,0 +1,73 @@
package com.v2ray.ang.util.fmt
import android.text.TextUtils
import com.v2ray.ang.AppConfig
import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.ServerConfig
import com.v2ray.ang.dto.V2rayConfig
import com.v2ray.ang.extension.idnHost
import com.v2ray.ang.util.MmkvManager.settingsStorage
import com.v2ray.ang.util.Utils
import java.net.URI
object Hysteria2Fmt {
fun parseHysteria2(str: String): ServerConfig {
var allowInsecure = settingsStorage?.decodeBool(AppConfig.PREF_ALLOW_INSECURE) ?: false
val config = ServerConfig.create(EConfigType.HYSTERIA2)
val uri = URI(Utils.fixIllegalUrl(str))
config.remarks = Utils.urlDecode(uri.fragment.orEmpty())
val queryParam = uri.rawQuery.split("&")
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
config.outboundBean?.streamSettings?.populateTlsSettings(
V2rayConfig.TLS,
if ((queryParam["allowInsecure"].orEmpty()) == "1") true else allowInsecure,
queryParam["sni"] ?: uri.idnHost,
null,
queryParam["alpn"],
null,
null,
null
)
config.outboundBean?.settings?.servers?.get(0)?.let { server ->
server.address = uri.idnHost
server.port = uri.port
server.password = uri.userInfo
}
return config
}
fun toUri(config: ServerConfig): String {
val outbound = config.getProxyOutbound() ?: return ""
val streamSetting = outbound.streamSettings ?: V2rayConfig.OutboundBean.StreamSettingsBean()
val remark = "#" + Utils.urlEncode(config.remarks)
val dicQuery = HashMap<String, String>()
dicQuery["security"] = streamSetting.security.ifEmpty { "none" }
streamSetting.tlsSettings?.let { tlsSetting ->
dicQuery["insecure"] = if (tlsSetting.allowInsecure) "1" else "0"
if (!TextUtils.isEmpty(tlsSetting.serverName)) {
dicQuery["sni"] = tlsSetting.serverName
}
if (!tlsSetting.alpn.isNullOrEmpty() && tlsSetting.alpn.isNotEmpty()) {
dicQuery["alpn"] = Utils.removeWhiteSpace(tlsSetting.alpn.joinToString()).orEmpty()
}
}
val query = "?" + dicQuery.toList().joinToString(
separator = "&",
transform = { it.first + "=" + it.second })
val url = String.format(
"%s@%s:%s",
outbound.getPassword(),
Utils.getIpv6Address(outbound.getServerAddress()),
outbound.getServerPort()
)
return url + query + remark
}
}
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.ServerActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/layout_margin_top_height">
<include layout="@layout/layout_address_port" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/layout_margin_top_height"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/server_lab_id3" />
<EditText
android:id="@+id/et_id"
android:layout_width="match_parent"
android:layout_height="@dimen/edit_height"
android:inputType="text" />
</LinearLayout>
<include layout="@layout/layout_tls" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/layout_margin_top_height"
android:layout_marginBottom="@dimen/layout_margin_top_height"
android:orientation="vertical" />
</LinearLayout>
</ScrollView>
@@ -48,6 +48,10 @@
android:id="@+id/import_manually_wireguard"
android:title="@string/menu_item_import_config_manually_wireguard"
app:showAsAction="never" />
<item
android:id="@+id/import_manually_hysteria2"
android:title="@string/menu_item_import_config_manually_hysteria2"
app:showAsAction="never" />
<item
android:title="@string/menu_item_import_config_custom"
@@ -32,6 +32,7 @@
<string name="menu_item_import_config_manually_http">Type manually[HTTP]</string>
<string name="menu_item_import_config_manually_trojan">الكتابة يدويًا [Trojan]</string>
<string name="menu_item_import_config_manually_wireguard">الكتابة يدويًا [Wireguard]</string>
<string name="menu_item_import_config_manually_hysteria2">Type manually[Hysteria2]</string>
<string name="menu_item_import_config_custom">تكوين مخصص</string>
<string name="menu_item_import_config_custom_clipboard">استيراد تكوين مخصص من الحافظة</string>
<string name="menu_item_import_config_custom_local">استيراد تكوين مخصص من الجهاز</string>
@@ -32,6 +32,7 @@
<string name="menu_item_import_config_manually_http">Type manually[HTTP]</string>
<string name="menu_item_import_config_manually_trojan">ম্যানুয়ালি টাইপ করুন [Trojan]</string>
<string name="menu_item_import_config_manually_wireguard">ম্যানুয়ালি টাইপ করুন [Wireguard]</string>
<string name="menu_item_import_config_manually_hysteria2">Type manually[Hysteria2]</string>
<string name="menu_item_import_config_custom">কাস্টম কনফিগারেশন</string>
<string name="menu_item_import_config_custom_clipboard">ক্লিপবোর্ড থেকে কাস্টম কনফিগারেশন আমদানি করুন</string>
<string name="menu_item_import_config_custom_local">স্থানীয়ভাবে কাস্টম কনফিগারেশন আমদানি করুন</string>
@@ -31,6 +31,7 @@
<string name="menu_item_import_config_manually_http">Type manually[HTTP]</string>
<string name="menu_item_import_config_manually_trojan">تایپ دستی[Trojan]</string>
<string name="menu_item_import_config_manually_wireguard">[Wireguard]تایپ دستی</string>
<string name="menu_item_import_config_manually_hysteria2">Type manually[Hysteria2]</string>
<string name="menu_item_import_config_custom">کانفیگ سفارشی</string>
<string name="menu_item_import_config_custom_clipboard">کانفیگ سفارشی را از کلیپ‌بورد وارد کنید</string>
<string name="menu_item_import_config_custom_local">کانفیگ سفارشی را به صورت محلی وارد کنید</string>
@@ -31,6 +31,7 @@
<string name="menu_item_import_config_manually_http">Ручной ввод HTTP</string>
<string name="menu_item_import_config_manually_trojan">Ручной ввод Trojan</string>
<string name="menu_item_import_config_manually_wireguard">Ручной ввод WireGuard</string>
<string name="menu_item_import_config_manually_hysteria2">Type manually[Hysteria2]</string>
<string name="menu_item_import_config_custom">Другой профиль</string>
<string name="menu_item_import_config_custom_clipboard">Импорт из буфера обмена</string>
<string name="menu_item_import_config_custom_local">Импорт из файла</string>
@@ -31,6 +31,7 @@
<string name="menu_item_import_config_manually_http">Type manually[HTTP]</string>
<string name="menu_item_import_config_manually_trojan">Nhập thủ công [Trojan]</string>
<string name="menu_item_import_config_manually_wireguard">Nhập thủ công [WireGuard]</string>
<string name="menu_item_import_config_manually_hysteria2">Type manually[Hysteria2]</string>
<string name="menu_item_import_config_custom">Nâng cao / Cấu hình tùy chỉnh</string>
<string name="menu_item_import_config_custom_clipboard">Nhập cấu hình tùy chỉnh từ Clipboard</string>
<string name="menu_item_import_config_custom_local">Nhập cấu hình tùy chỉnh từ Tệp</string>
@@ -31,6 +31,7 @@
<string name="menu_item_import_config_manually_http">手动输入[HTTP]</string>
<string name="menu_item_import_config_manually_trojan">手动输入[Trojan]</string>
<string name="menu_item_import_config_manually_wireguard">手动输入[Wireguard]</string>
<string name="menu_item_import_config_manually_hysteria2">手动输入[Hysteria2]</string>
<string name="menu_item_import_config_custom">自定义配置</string>
<string name="menu_item_import_config_custom_clipboard">从剪贴板导入自定义配置</string>
<string name="menu_item_import_config_custom_local">从本地导入自定义配置</string>
@@ -31,6 +31,7 @@
<string name="menu_item_import_config_manually_http">手動鍵入 [HTTP]</string>
<string name="menu_item_import_config_manually_trojan">手動鍵入 [Trojan]</string>
<string name="menu_item_import_config_manually_wireguard">手動鍵入 [Wireguard]</string>
<string name="menu_item_import_config_manually_hysteria2">手動鍵入 [Hysteria2]</string>
<string name="menu_item_import_config_custom">自訂配置</string>
<string name="menu_item_import_config_custom_clipboard">從剪貼簿匯入自訂配置</string>
<string name="menu_item_import_config_custom_local">從本地匯入自訂配置</string>
@@ -32,6 +32,7 @@
<string name="menu_item_import_config_manually_http">Type manually[HTTP]</string>
<string name="menu_item_import_config_manually_trojan">Type manually[Trojan]</string>
<string name="menu_item_import_config_manually_wireguard">Type manually[Wireguard]</string>
<string name="menu_item_import_config_manually_hysteria2">Type manually[Hysteria2]</string>
<string name="menu_item_import_config_custom">Custom config</string>
<string name="menu_item_import_config_custom_clipboard">Import custom config from Clipboard</string>
<string name="menu_item_import_config_custom_local">Import custom config from locally</string>