Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/36.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
"formatVersion": 1,
"database": {
"version": 36,
"identityHash": "2ad66cce1d4ba5df1fd06814cfaae7e9",
"identityHash": "a767e2240b7af68735ec4f7b90813e3c",
"entities": [
{
"tableName": "proxy_groups",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL, `frontProxy` INTEGER NOT NULL DEFAULT -1, `landingProxy` INTEGER NOT NULL DEFAULT -1)",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL, `frontProxy` INTEGER NOT NULL DEFAULT -1, `landingProxy` INTEGER NOT NULL DEFAULT -1, `groupUtlsFingerprint` TEXT NOT NULL DEFAULT '')",
"fields": [
{
"fieldPath": "id",
Expand Down Expand Up @@ -61,6 +61,13 @@
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "-1"
},
{
"fieldPath": "groupUtlsFingerprint",
"columnName": "groupUtlsFingerprint",
"affinity": "TEXT",
"notNull": true,
"defaultValue": "''"
}
],
"primaryKey": {
Expand Down Expand Up @@ -455,7 +462,7 @@
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '2ad66cce1d4ba5df1fd06814cfaae7e9')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a767e2240b7af68735ec4f7b90813e3c')"
]
}
}
1 change: 1 addition & 0 deletions app/src/main/java/io/nekohasekai/sagernet/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ object Key {
const val GROUP_LANDING_PROXY_OUTBOUND = "groupLandingOutbound"
const val GROUP_FRONT_PROXY = "groupFrontProxy"
const val GROUP_LANDING_PROXY = "groupLandingProxy"
const val GROUP_UTLS_FINGERPRINT = "groupUtlsFingerprint"

const val GROUP_SUBSCRIPTION = "groupSubscription"
const val SUBSCRIPTION_TYPE = "subscriptionType"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ object DataStore : OnPreferenceDataStoreChangeListener {
var landingProxyOutbound by profileCacheStore.long(Key.GROUP_LANDING_PROXY_OUTBOUND)
var frontProxy by profileCacheStore.stringToInt(Key.GROUP_FRONT_PROXY)
var landingProxy by profileCacheStore.stringToInt(Key.GROUP_LANDING_PROXY)
var groupUtlsFingerprint by profileCacheStore.string(Key.GROUP_UTLS_FINGERPRINT)

var serverConfig by profileCacheStore.string(Key.SERVER_CONFIG)

Expand Down
11 changes: 10 additions & 1 deletion app/src/main/java/io/nekohasekai/sagernet/database/ProxyGroup.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ data class ProxyGroup(
var subscription: SubscriptionBean? = null,
var order: Int = GroupOrder.ORIGIN,
@ColumnInfo(defaultValue = (-1L).toString()) var frontProxy: Long = -1L,
@ColumnInfo(defaultValue = (-1L).toString()) var landingProxy: Long = -1L
@ColumnInfo(defaultValue = (-1L).toString()) var landingProxy: Long = -1L,
@ColumnInfo(defaultValue = "") var groupUtlsFingerprint: String = ""
) : Serializable() {

@Transient
Expand Down Expand Up @@ -69,6 +70,7 @@ data class ProxyGroup(
output.writeInt(order)
output.writeLong(frontProxy)
output.writeLong(landingProxy)
output.writeString(groupUtlsFingerprint)
}
}

Expand Down Expand Up @@ -97,6 +99,13 @@ data class ProxyGroup(
frontProxy = input.readLong()
landingProxy = input.readLong()
}
if (version >= 1) {
try {
groupUtlsFingerprint = input.readString()
} catch (e: Exception) {
groupUtlsFingerprint = ""
}
}
}
}

Expand Down
14 changes: 14 additions & 0 deletions app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,10 @@ fun buildV2RayConfig(
val bean = proxyEntity.requireBean()
currentOutbound = OutboundObject()

// Получаем группу для применения группового uTLS
val proxyGroup = SagerDatabase.groupDao.getById(proxyEntity.groupId)
val groupUtls = proxyGroup?.groupUtlsFingerprint?.takeIf { it.isNotEmpty() }

val tagIn: String
var needGlobal: Boolean

Expand Down Expand Up @@ -888,6 +892,8 @@ fun buildV2RayConfig(
val overrideFingerprint = DataStore.experimentalFlagsProperties.getProperty("overrideUTLSFingerprintForTLS")
if (!overrideFingerprint.isNullOrEmpty()) {
fingerprint = overrideFingerprint
} else if (groupUtls != null) {
fingerprint = groupUtls
} else if (bean.utlsFingerprint.isNotEmpty()) {
fingerprint = bean.utlsFingerprint
}
Expand Down Expand Up @@ -918,6 +924,8 @@ fun buildV2RayConfig(
val overrideFingerprint = DataStore.experimentalFlagsProperties.getProperty("overrideUTLSFingerprintForREALITY")
if (!overrideFingerprint.isNullOrEmpty()) {
fingerprint = overrideFingerprint
} else if (groupUtls != null) {
fingerprint = groupUtls
} else if (bean.realityFingerprint.isNotEmpty()) {
fingerprint = bean.realityFingerprint
}
Expand Down Expand Up @@ -1616,6 +1624,8 @@ fun buildV2RayConfig(
val overrideFingerprint = DataStore.experimentalFlagsProperties.getProperty("overrideUTLSFingerprintForTLS")
if (!overrideFingerprint.isNullOrEmpty()) {
fingerprint = overrideFingerprint
} else if (groupUtls != null) {
fingerprint = groupUtls
} else if (bean.utlsFingerprint.isNotEmpty()) {
fingerprint = bean.utlsFingerprint
}
Expand Down Expand Up @@ -1643,6 +1653,8 @@ fun buildV2RayConfig(
val overrideFingerprint = DataStore.experimentalFlagsProperties.getProperty("overrideUTLSFingerprintForREALITY")
if (!overrideFingerprint.isNullOrEmpty()) {
fingerprint = overrideFingerprint
} else if (groupUtls != null) {
fingerprint = groupUtls
} else if (bean.realityFingerprint.isNotEmpty()) {
fingerprint = bean.realityFingerprint
}
Expand Down Expand Up @@ -1833,6 +1845,8 @@ fun buildV2RayConfig(
val overrideFingerprint = DataStore.experimentalFlagsProperties.getProperty("overrideUTLSFingerprintForTLS")
if (!overrideFingerprint.isNullOrEmpty()) {
fingerprint = overrideFingerprint
} else if (groupUtls != null) {
fingerprint = groupUtls
} else if (bean.utlsFingerprint.isNotEmpty()) {
fingerprint = bean.utlsFingerprint
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ class GroupSettingsActivity(
DataStore.landingProxyOutbound = landingProxy
DataStore.frontProxy = if (frontProxy >= 0) 1 else 0
DataStore.landingProxy = if (landingProxy >= 0) 1 else 0
DataStore.groupUtlsFingerprint = groupUtlsFingerprint ?: ""
}

fun ProxyGroup.serialize() {
Expand All @@ -116,6 +117,7 @@ class GroupSettingsActivity(

frontProxy = if (DataStore.frontProxy == 1) DataStore.frontProxyOutbound else -1
landingProxy = if (DataStore.landingProxy == 1) DataStore.landingProxyOutbound else -1
groupUtlsFingerprint = DataStore.groupUtlsFingerprint
if (type == GroupType.SUBSCRIPTION) {
subscription = SubscriptionBean().applyDefaultValues().apply {
type = DataStore.subscriptionType
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@
<string name="connection_test_url_test">URL test</string>
<string name="alter_id">Изменить ID</string>
<string name="url">URL</string>
<string name="utls_fingerprint">uTLS-отпечаток</string>
<string name="utls_fingerprint">Принудительный uTLS</string>
<string name="route_need_location_enabled">Правило маршрутизации `%s` требует доступа к вашему **Wi-Fi SSID**, но для этого требуется **включенное местоположение**</string>
<string name="route_need_fine_location">Правило маршрутизации `%s` требует доступа к вашему **Wi-Fi SSID**, но для этого требуется **разрешение на точное определение местоположения**</string>
<string name="bootstrap_dns">Загрузочный DNS</string>
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@
<string name="experimental_settings">Experimental settings</string>
<string name="experimental_authenticated_length">Make the length of each payload segment no longer malleable. This experiment requires the server and client use the same version of v2ray-core. More breaking updates on this experiment is expected.</string>
<string name="experimental_no_termination_signal">Do not send connection single duplex termination signal for TCP connection when transferred over VMess. This will break some applications.</string>
<string name="utls_fingerprint">uTLS fingerprint</string>
<string name="utls_fingerprint">Force uTLS</string>
<string name="group_order">Sort</string>
<string name="group_order_origin">By original order</string>
<string name="group_order_by_name">Alphabetically</string>
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/res/xml/group_preferences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@
app:key="groupLandingProxy"
app:title="@string/landing_proxy" />

<ListPreference
app:icon="@drawable/ic_baseline_fingerprint_24"
app:entries="@array/utls_entry"
app:entryValues="@array/utls_value"
app:key="groupUtlsFingerprint"
app:title="@string/utls_fingerprint"
app:useSimpleSummaryProvider="true" />

<PreferenceCategory
app:key="groupSubscription"
app:title="@string/subscription_settings">
Expand Down