diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt index 5cdaf5d93..675fed2bf 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/V2rayConfig.kt @@ -5,6 +5,7 @@ import com.google.gson.GsonBuilder import com.google.gson.JsonPrimitive import com.google.gson.JsonSerializationContext import com.google.gson.JsonSerializer +import com.google.gson.annotations.SerializedName import com.google.gson.reflect.TypeToken import java.lang.reflect.Type @@ -19,7 +20,8 @@ data class V2rayConfig( val api: Any? = null, val transport: Any? = null, val reverse: Any? = null, - val fakedns: Any? = null) { + val fakedns: Any? = null, + val browserForwarder: Any? = null) { companion object { const val DEFAULT_PORT = 443 const val DEFAULT_SECURITY = "auto" @@ -34,7 +36,8 @@ data class V2rayConfig( data class LogBean(val access: String, val error: String, - var loglevel: String?) + var loglevel: String?, + val dnsLog: Boolean? = null) data class InboundBean( var tag: String, @@ -101,6 +104,7 @@ data class V2rayConfig( var level: Int = DEFAULT_LEVEL, val email: String? = null, val flow: String? = null, + val ivCheck: Boolean? = null, var users: List? = null) { @@ -121,18 +125,27 @@ data class V2rayConfig( var tlsSettings: TlsSettingsBean? = null, var quicSettings: QuicSettingBean? = null, var xtlsSettings: TlsSettingsBean? = null, - val grpcSettings: Any? = null, + var grpcSettings: GrpcSettingsBean? = null, val dsSettings: Any? = null, val sockopt: Any? = null ) { - data class TcpSettingsBean(var header: HeaderBean = HeaderBean()) { + data class TcpSettingsBean(var header: HeaderBean = HeaderBean(), + val acceptProxyProtocol: Boolean? = null) { data class HeaderBean(var type: String = "none", var request: RequestBean? = null, var response: Any? = null) { data class RequestBean(var path: List = ArrayList(), - var headers: HeadersBean = HeadersBean()) { - data class HeadersBean(var Host: List = ArrayList()) + var headers: HeadersBean = HeadersBean(), + val version: String? = null, + val method: String? = null) { + data class HeadersBean(var Host: List = ArrayList(), + @SerializedName("User-Agent") + val userAgent: List? = null, + @SerializedName("Accept-Encoding") + val acceptEncoding: List? = null, + val Connection: List? = null, + val Pragma: String? = null) } } } @@ -150,7 +163,10 @@ data class V2rayConfig( } data class WsSettingsBean(var path: String = "", - var headers: HeadersBean = HeadersBean()) { + var headers: HeadersBean = HeadersBean(), + val maxEarlyData: Int? = null, + val useBrowserForwarding: Boolean? = null, + val acceptProxyProtocol: Boolean? = null) { data class HeadersBean(var Host: String = "") } @@ -160,8 +176,14 @@ data class V2rayConfig( data class TlsSettingsBean(var allowInsecure: Boolean = false, var serverName: String = "", val alpn: List? = null, + val minVersion: String? = null, + val maxVersion: String? = null, + val preferServerCipherSuites: Boolean? = null, + val cipherSuites: String? = null, + val fingerprint: String? = null, val certificates: List? = null, - val disableSystemRoot: Boolean? = null) + val disableSystemRoot: Boolean? = null, + val enableSessionResumption: Boolean? = null) data class QuicSettingBean(var security: String = "none", var key: String = "", @@ -169,6 +191,9 @@ data class V2rayConfig( data class HeaderBean(var type: String = "none") } + data class GrpcSettingsBean(var serviceName: String = "", + val multiMode: Boolean? = null) + fun populateTransportSettings(transport: String, headerType: String?, host: String?, path: String?, seed: String?, quicSecurity: String?, key: String?): String { var sni = "" @@ -223,6 +248,12 @@ data class V2rayConfig( quicsetting.header.type = headerType ?: "none" quicSettings = quicsetting } + "grpc" -> { + val grpcSetting = GrpcSettingsBean() + grpcSetting.serviceName = path ?: "" + sni = host ?: "" + grpcSettings = grpcSetting + } } return sni } @@ -324,6 +355,12 @@ data class V2rayConfig( quicSetting.security, quicSetting.key) } + "grpc" -> { + val grpcSetting = streamSettings?.grpcSettings ?: return null + listOf("", + "", + grpcSetting.serviceName) + } else -> null } } @@ -335,6 +372,7 @@ data class V2rayConfig( var hosts: Map? = null, val clientIp: String? = null, val disableCache: Boolean? = null, + val queryStrategy: String? = null, val tag: String? = null ) { data class ServersBean(var address: String = "", diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt index eec16e033..fba5096e4 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt @@ -16,6 +16,7 @@ import android.util.Log import android.view.KeyEvent import android.view.Menu import android.view.MenuItem +import android.widget.Toast import com.tbruyelle.rxpermissions.RxPermissions import com.tencent.mmkv.MMKV import com.v2ray.ang.AppConfig @@ -28,13 +29,13 @@ import com.v2ray.ang.service.V2RayServiceManager import com.v2ray.ang.util.AngConfigManager import com.v2ray.ang.util.MmkvManager import com.v2ray.ang.util.Utils -import com.v2ray.ang.util.V2rayConfigUtil import com.v2ray.ang.viewmodel.MainViewModel import kotlinx.android.synthetic.main.activity_main.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import libv2ray.Libv2ray +import me.drakeet.support.toast.ToastCompat import rx.Observable import rx.android.schedulers.AndroidSchedulers import java.net.URL @@ -475,14 +476,11 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList toast(R.string.toast_none_data) return } - if (!V2rayConfigUtil.isValidConfig(server)) { - toast(R.string.toast_config_file_invalid) - return - } mainViewModel.appendCustomConfigServer(server) toast(R.string.toast_success) adapter.notifyItemInserted(mainViewModel.serverList.lastIndex) } catch (e: Exception) { + ToastCompat.makeText(this, "${getString(R.string.toast_malformed_josn)} ${e.cause?.message}", Toast.LENGTH_LONG).show() e.printStackTrace() return } diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt index 8db9793f6..bb8d0f5e3 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt @@ -5,6 +5,7 @@ import android.support.v7.app.AlertDialog import android.text.TextUtils import android.view.Menu import android.view.MenuItem +import android.widget.Toast import com.google.gson.Gson import com.tencent.mmkv.MMKV import com.v2ray.ang.R @@ -15,6 +16,7 @@ import com.v2ray.ang.extension.toast import com.v2ray.ang.util.MmkvManager import com.v2ray.ang.util.Utils import kotlinx.android.synthetic.main.activity_server_custom_config.* +import me.drakeet.support.toast.ToastCompat class ServerCustomConfigActivity : BaseActivity() { @@ -70,7 +72,7 @@ class ServerCustomConfigActivity : BaseActivity() { Gson().fromJson(tv_content.text.toString(), V2rayConfig::class.java) } catch (e: Exception) { e.printStackTrace() - toast(R.string.toast_malformed_josn) + ToastCompat.makeText(this, "${getString(R.string.toast_malformed_josn)} ${e.cause?.message}", Toast.LENGTH_LONG).show() return false } diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt index 7dc3aefbf..8ec7fe260 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt @@ -360,17 +360,4 @@ object V2rayConfigUtil { } return true } - - /** - * is valid config - */ - fun isValidConfig(conf: String): Boolean { - return try { - val jObj = JSONObject(conf) - //hasBound = (jObj.has("outbounds") and jObj.has("inbounds")) or (jObj.has("outbound") and jObj.has("inbound")) - jObj.has("outbounds") or jObj.has("outbound") - } catch (e: JSONException) { - false - } - } } diff --git a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml index 9a91f38a3..24d13e72f 100644 --- a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml @@ -43,10 +43,10 @@ 传输协议(network) 功能设置(不清楚则保持默认值) 伪装类型(type) - 伪装域名host(host/ws host/h2 host)/QUIC 加密方式 - path(ws path/h2 path)/QUIC 加密密钥 - 底层传输安全 - allowInsecure + 伪装域名(host)(host/ws host/h2 host)/QUIC 加密方式 + path(ws path/h2 path)/QUIC 加密密钥/kcp seed/grpc serviceName + 底层传输安全(tls) + 跳过证书验证(allowInsecure) 服务器地址 服务器端口 密码 diff --git a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml index 5303fdbbc..4c6b7436b 100644 --- a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml @@ -43,10 +43,10 @@ 網路 更多功能 標頭類型 - 要求主機(host/ws host/h2 host)/QUIC加密方式 - path(ws path/h2 path)/QUIC加密密鑰 - 傳輸層安全性 - allowInsecure + 要求主機(host)(host/ws host/h2 host)/QUIC加密方式 + path(ws path/h2 path)/QUIC加密密鑰/kcp seed/grpc serviceName + 傳輸層安全性(tls) + 跳過證書驗證(allowInsecure) 伺服器位址 伺服器埠 密碼 diff --git a/V2rayNG/app/src/main/res/values/arrays.xml b/V2rayNG/app/src/main/res/values/arrays.xml index 755bb1d66..3a690f7be 100644 --- a/V2rayNG/app/src/main/res/values/arrays.xml +++ b/V2rayNG/app/src/main/res/values/arrays.xml @@ -24,6 +24,7 @@ ws h2 quic + grpc diff --git a/V2rayNG/app/src/main/res/values/strings.xml b/V2rayNG/app/src/main/res/values/strings.xml index b45ed29ba..f15c8c8bc 100644 --- a/V2rayNG/app/src/main/res/values/strings.xml +++ b/V2rayNG/app/src/main/res/values/strings.xml @@ -44,7 +44,7 @@ more function head type request host(host/ws host/h2 host)/QUIC security - path(ws path/h2 path)/QUIC key + path(ws path/h2 path)/QUIC key/kcp seed/grpc serviceName tls allowInsecure address