1package conf
2
3import (
4	"sort"
5
6	"github.com/golang/protobuf/proto"
7
8	"github.com/v2fly/v2ray-core/v4/transport/internet/headers/http"
9	"github.com/v2fly/v2ray-core/v4/transport/internet/headers/noop"
10	"github.com/v2fly/v2ray-core/v4/transport/internet/headers/srtp"
11	"github.com/v2fly/v2ray-core/v4/transport/internet/headers/tls"
12	"github.com/v2fly/v2ray-core/v4/transport/internet/headers/utp"
13	"github.com/v2fly/v2ray-core/v4/transport/internet/headers/wechat"
14	"github.com/v2fly/v2ray-core/v4/transport/internet/headers/wireguard"
15)
16
17type NoOpAuthenticator struct{}
18
19func (NoOpAuthenticator) Build() (proto.Message, error) {
20	return new(noop.Config), nil
21}
22
23type NoOpConnectionAuthenticator struct{}
24
25func (NoOpConnectionAuthenticator) Build() (proto.Message, error) {
26	return new(noop.ConnectionConfig), nil
27}
28
29type SRTPAuthenticator struct{}
30
31func (SRTPAuthenticator) Build() (proto.Message, error) {
32	return new(srtp.Config), nil
33}
34
35type UTPAuthenticator struct{}
36
37func (UTPAuthenticator) Build() (proto.Message, error) {
38	return new(utp.Config), nil
39}
40
41type WechatVideoAuthenticator struct{}
42
43func (WechatVideoAuthenticator) Build() (proto.Message, error) {
44	return new(wechat.VideoConfig), nil
45}
46
47type WireguardAuthenticator struct{}
48
49func (WireguardAuthenticator) Build() (proto.Message, error) {
50	return new(wireguard.WireguardConfig), nil
51}
52
53type DTLSAuthenticator struct{}
54
55func (DTLSAuthenticator) Build() (proto.Message, error) {
56	return new(tls.PacketConfig), nil
57}
58
59type AuthenticatorRequest struct {
60	Version string                 `json:"version"`
61	Method  string                 `json:"method"`
62	Path    StringList             `json:"path"`
63	Headers map[string]*StringList `json:"headers"`
64}
65
66func sortMapKeys(m map[string]*StringList) []string {
67	var keys []string
68	for key := range m {
69		keys = append(keys, key)
70	}
71	sort.Strings(keys)
72	return keys
73}
74
75func (v *AuthenticatorRequest) Build() (*http.RequestConfig, error) {
76	config := &http.RequestConfig{
77		Uri: []string{"/"},
78		Header: []*http.Header{
79			{
80				Name:  "Host",
81				Value: []string{"www.baidu.com", "www.bing.com"},
82			},
83			{
84				Name: "User-Agent",
85				Value: []string{
86					"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36",
87					"Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46",
88				},
89			},
90			{
91				Name:  "Accept-Encoding",
92				Value: []string{"gzip, deflate"},
93			},
94			{
95				Name:  "Connection",
96				Value: []string{"keep-alive"},
97			},
98			{
99				Name:  "Pragma",
100				Value: []string{"no-cache"},
101			},
102		},
103	}
104
105	if len(v.Version) > 0 {
106		config.Version = &http.Version{Value: v.Version}
107	}
108
109	if len(v.Method) > 0 {
110		config.Method = &http.Method{Value: v.Method}
111	}
112
113	if len(v.Path) > 0 {
114		config.Uri = append([]string(nil), (v.Path)...)
115	}
116
117	if len(v.Headers) > 0 {
118		config.Header = make([]*http.Header, 0, len(v.Headers))
119		headerNames := sortMapKeys(v.Headers)
120		for _, key := range headerNames {
121			value := v.Headers[key]
122			if value == nil {
123				return nil, newError("empty HTTP header value: " + key).AtError()
124			}
125			config.Header = append(config.Header, &http.Header{
126				Name:  key,
127				Value: append([]string(nil), (*value)...),
128			})
129		}
130	}
131
132	return config, nil
133}
134
135type AuthenticatorResponse struct {
136	Version string                 `json:"version"`
137	Status  string                 `json:"status"`
138	Reason  string                 `json:"reason"`
139	Headers map[string]*StringList `json:"headers"`
140}
141
142func (v *AuthenticatorResponse) Build() (*http.ResponseConfig, error) {
143	config := &http.ResponseConfig{
144		Header: []*http.Header{
145			{
146				Name:  "Content-Type",
147				Value: []string{"application/octet-stream", "video/mpeg"},
148			},
149			{
150				Name:  "Transfer-Encoding",
151				Value: []string{"chunked"},
152			},
153			{
154				Name:  "Connection",
155				Value: []string{"keep-alive"},
156			},
157			{
158				Name:  "Pragma",
159				Value: []string{"no-cache"},
160			},
161			{
162				Name:  "Cache-Control",
163				Value: []string{"private", "no-cache"},
164			},
165		},
166	}
167
168	if len(v.Version) > 0 {
169		config.Version = &http.Version{Value: v.Version}
170	}
171
172	if len(v.Status) > 0 || len(v.Reason) > 0 {
173		config.Status = &http.Status{
174			Code:   "200",
175			Reason: "OK",
176		}
177		if len(v.Status) > 0 {
178			config.Status.Code = v.Status
179		}
180		if len(v.Reason) > 0 {
181			config.Status.Reason = v.Reason
182		}
183	}
184
185	if len(v.Headers) > 0 {
186		config.Header = make([]*http.Header, 0, len(v.Headers))
187		headerNames := sortMapKeys(v.Headers)
188		for _, key := range headerNames {
189			value := v.Headers[key]
190			if value == nil {
191				return nil, newError("empty HTTP header value: " + key).AtError()
192			}
193			config.Header = append(config.Header, &http.Header{
194				Name:  key,
195				Value: append([]string(nil), (*value)...),
196			})
197		}
198	}
199
200	return config, nil
201}
202
203type Authenticator struct {
204	Request  AuthenticatorRequest  `json:"request"`
205	Response AuthenticatorResponse `json:"response"`
206}
207
208func (v *Authenticator) Build() (proto.Message, error) {
209	config := new(http.Config)
210	requestConfig, err := v.Request.Build()
211	if err != nil {
212		return nil, err
213	}
214	config.Request = requestConfig
215
216	responseConfig, err := v.Response.Build()
217	if err != nil {
218		return nil, err
219	}
220	config.Response = responseConfig
221
222	return config, nil
223}
224