namespace ServiceLib.Handler.Fmt; public class VmessFmt : BaseFmt { public static ProfileItem? Resolve(string str, out string msg) { msg = ResUI.ConfigurationFormatIncorrect; ProfileItem? item; if (str.IndexOf('@') > 0) { item = ResolveStdVmess(str) ?? ResolveVmess(str, out msg); } else { item = ResolveVmess(str, out msg); } return item; } public static string? ToUri(ProfileItem? item) { if (item == null) { return null; } var vmessQRCode = new VmessQRCode { // vmess link keeps shared transport keys; map from new transport model on export. v = 2, ps = item.Remarks.TrimEx(), add = item.Address, port = item.Port, id = item.Password, aid = int.TryParse(item.GetProtocolExtra()?.AlterId, out var result) ? result : 0, scy = item.GetProtocolExtra().VmessSecurity ?? "", net = item.GetNetwork() == nameof(ETransport.raw) ? Global.RawNetworkAlias : item.Network, type = item.GetNetwork() switch { nameof(ETransport.raw) => item.GetTransportExtra().RawHeaderType, nameof(ETransport.kcp) => item.GetTransportExtra().KcpHeaderType, nameof(ETransport.xhttp) => item.GetTransportExtra().XhttpMode, nameof(ETransport.grpc) => item.GetTransportExtra().GrpcMode, _ => Global.None, }, host = item.GetNetwork() switch { nameof(ETransport.raw) => item.GetTransportExtra().Host, nameof(ETransport.ws) => item.GetTransportExtra().Host, nameof(ETransport.httpupgrade) => item.GetTransportExtra().Host, nameof(ETransport.xhttp) => item.GetTransportExtra().Host, nameof(ETransport.grpc) => item.GetTransportExtra().GrpcAuthority, _ => null, }, path = item.GetNetwork() switch { nameof(ETransport.raw) => item.GetTransportExtra().Path, nameof(ETransport.kcp) => item.GetTransportExtra().KcpSeed, nameof(ETransport.ws) => item.GetTransportExtra().Path, nameof(ETransport.httpupgrade) => item.GetTransportExtra().Path, nameof(ETransport.xhttp) => item.GetTransportExtra().Path, nameof(ETransport.grpc) => item.GetTransportExtra().GrpcServiceName, _ => null, }, tls = item.StreamSecurity, sni = item.Sni, alpn = item.Alpn, fp = item.Fingerprint, insecure = item.GetAllowInsecure() ? "1" : "0", vcn = item.VerifyPeerCertByName, pcs = item.CertSha }; var url = JsonUtils.Serialize(vmessQRCode); url = Utils.Base64Encode(url); url = $"{Global.ProtocolShares[EConfigType.VMess]}{url}"; return url; } private static ProfileItem? ResolveVmess(string result, out string msg) { msg = string.Empty; var item = new ProfileItem { ConfigType = EConfigType.VMess }; result = result[Global.ProtocolShares[EConfigType.VMess].Length..]; result = Utils.Base64Decode(result); var vmessQRCode = JsonUtils.Deserialize(result); if (vmessQRCode == null) { msg = ResUI.FailedConversionConfiguration; return null; } item.Network = Global.DefaultNetwork; var transport = new TransportExtraItem { RawHeaderType = Global.None, }; //item.ConfigVersion = vmessQRCode.v; item.Remarks = Utils.ToString(vmessQRCode.ps); item.Address = Utils.ToString(vmessQRCode.add); item.Port = vmessQRCode.port; item.Password = Utils.ToString(vmessQRCode.id); item.SetProtocolExtra(new ProtocolExtraItem { AlterId = vmessQRCode.aid.ToString(), VmessSecurity = vmessQRCode.scy.IsNullOrEmpty() ? Global.DefaultSecurity : vmessQRCode.scy, }); if (vmessQRCode.net.IsNotEmpty()) { item.Network = vmessQRCode.net == Global.RawNetworkAlias ? nameof(ETransport.raw) : vmessQRCode.net; } if (vmessQRCode.type.IsNotEmpty()) { transport = item.GetNetwork() switch { nameof(ETransport.raw) => transport with { RawHeaderType = vmessQRCode.type }, nameof(ETransport.kcp) => transport with { KcpHeaderType = vmessQRCode.type }, nameof(ETransport.xhttp) => transport with { XhttpMode = vmessQRCode.type }, nameof(ETransport.grpc) => transport with { GrpcMode = vmessQRCode.type }, _ => transport, }; } transport = item.GetNetwork() switch { nameof(ETransport.raw) => transport with { Host = Utils.ToString(vmessQRCode.host), Path = Utils.ToString(vmessQRCode.path) }, nameof(ETransport.kcp) => transport with { KcpSeed = Utils.ToString(vmessQRCode.path) }, nameof(ETransport.ws) => transport with { Host = Utils.ToString(vmessQRCode.host), Path = Utils.ToString(vmessQRCode.path) }, nameof(ETransport.httpupgrade) => transport with { Host = Utils.ToString(vmessQRCode.host), Path = Utils.ToString(vmessQRCode.path) }, nameof(ETransport.xhttp) => transport with { Host = Utils.ToString(vmessQRCode.host), Path = Utils.ToString(vmessQRCode.path) }, nameof(ETransport.grpc) => transport with { GrpcAuthority = Utils.ToString(vmessQRCode.host), GrpcServiceName = Utils.ToString(vmessQRCode.path) }, _ => transport, }; item.SetTransportExtra(transport); item.StreamSecurity = Utils.ToString(vmessQRCode.tls); item.Sni = Utils.ToString(vmessQRCode.sni); item.Alpn = Utils.ToString(vmessQRCode.alpn); item.Fingerprint = Utils.ToString(vmessQRCode.fp); item.AllowInsecure = vmessQRCode.insecure == "1" ? Global.StringTrue : string.Empty; item.VerifyPeerCertByName = Utils.ToString(vmessQRCode.vcn); item.CertSha = Utils.ToString(vmessQRCode.pcs); return item; } public static ProfileItem? ResolveStdVmess(string str) { var item = new ProfileItem { ConfigType = EConfigType.VMess, }; var url = Utils.TryUri(str); if (url == null) { return null; } item.Address = url.IdnHost; item.Port = url.Port; item.Remarks = url.GetComponents(UriComponents.Fragment, UriFormat.Unescaped); item.Password = Utils.UrlDecode(url.UserInfo); item.SetProtocolExtra(new ProtocolExtraItem { VmessSecurity = Global.DefaultSecurity, }); var query = Utils.ParseQueryString(url.Query); ResolveUriQuery(query, ref item); return item; } }