Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
V4NSH4J
GitHub Repository: V4NSH4J/discord-mass-DM-GO
Path: blob/main/client/roundtripper.go
310 views
1
package client
2
3
import (
4
"context"
5
"errors"
6
"fmt"
7
"net"
8
9
"strings"
10
"sync"
11
12
http "github.com/Danny-Dasilva/fhttp"
13
http2 "github.com/Danny-Dasilva/fhttp/http2"
14
utls "github.com/Danny-Dasilva/utls"
15
"golang.org/x/net/proxy"
16
)
17
18
var errProtocolNegotiated = errors.New("protocol negotiated")
19
20
type roundTripper struct {
21
sync.Mutex
22
// fix typing
23
JA3 string
24
UserAgent string
25
26
Cookies []Cookie
27
cachedConnections map[string]net.Conn
28
cachedTransports map[string]http.RoundTripper
29
30
dialer proxy.ContextDialer
31
}
32
33
func (rt *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
34
// Fix this later for proper cookie parsing
35
for _, properties := range rt.Cookies {
36
req.AddCookie(&http.Cookie{
37
Name: properties.Name,
38
Value: properties.Value,
39
Path: properties.Path,
40
Domain: properties.Domain,
41
Expires: properties.JSONExpires.Time, //TODO: scuffed af
42
RawExpires: properties.RawExpires,
43
MaxAge: properties.MaxAge,
44
HttpOnly: properties.HTTPOnly,
45
Secure: properties.Secure,
46
Raw: properties.Raw,
47
Unparsed: properties.Unparsed,
48
})
49
}
50
req.Header.Set("User-Agent", rt.UserAgent)
51
addr := rt.getDialTLSAddr(req)
52
if _, ok := rt.cachedTransports[addr]; !ok {
53
if err := rt.getTransport(req, addr); err != nil {
54
return nil, err
55
}
56
}
57
return rt.cachedTransports[addr].RoundTrip(req)
58
}
59
60
func (rt *roundTripper) getTransport(req *http.Request, addr string) error {
61
switch strings.ToLower(req.URL.Scheme) {
62
case "http":
63
rt.cachedTransports[addr] = &http.Transport{DialContext: rt.dialer.DialContext, DisableKeepAlives: true}
64
return nil
65
case "https":
66
default:
67
return fmt.Errorf("invalid URL scheme: [%v]", req.URL.Scheme)
68
}
69
70
_, err := rt.dialTLS(context.Background(), "tcp", addr)
71
switch err {
72
case errProtocolNegotiated:
73
case nil:
74
// Should never happen.
75
panic("dialTLS returned no error when determining cachedTransports")
76
default:
77
return err
78
}
79
80
return nil
81
}
82
83
func (rt *roundTripper) dialTLS(ctx context.Context, network, addr string) (net.Conn, error) {
84
rt.Lock()
85
defer rt.Unlock()
86
87
// If we have the connection from when we determined the HTTPS
88
// cachedTransports to use, return that.
89
if conn := rt.cachedConnections[addr]; conn != nil {
90
delete(rt.cachedConnections, addr)
91
return conn, nil
92
}
93
rawConn, err := rt.dialer.DialContext(ctx, network, addr)
94
if err != nil {
95
return nil, err
96
}
97
98
var host string
99
if host, _, err = net.SplitHostPort(addr); err != nil {
100
host = addr
101
}
102
//////////////////
103
104
spec, err := StringToSpec(rt.JA3, rt.UserAgent)
105
if err != nil {
106
return nil, err
107
}
108
109
conn := utls.UClient(rawConn, &utls.Config{ServerName: host, InsecureSkipVerify: true}, // MinVersion: tls.VersionTLS10,
110
// MaxVersion: tls.VersionTLS13,
111
112
utls.HelloCustom)
113
114
if err := conn.ApplyPreset(spec); err != nil {
115
return nil, err
116
}
117
118
if err = conn.Handshake(); err != nil {
119
_ = conn.Close()
120
121
if err.Error() == "tls: CurvePreferences includes unsupported curve" {
122
//fix this
123
return nil, fmt.Errorf("conn.Handshake() error for tls 1.3 (please retry request): %+v", err)
124
}
125
return nil, fmt.Errorf("uTlsConn.Handshake() error: %+v", err)
126
}
127
128
//////////
129
if rt.cachedTransports[addr] != nil {
130
return conn, nil
131
}
132
133
// No http.Transport constructed yet, create one based on the results
134
// of ALPN.
135
switch conn.ConnectionState().NegotiatedProtocol {
136
case http2.NextProtoTLS:
137
parsedUserAgent := parseUserAgent(rt.UserAgent)
138
t2 := http2.Transport{DialTLS: rt.dialTLSHTTP2,
139
PushHandler: &http2.DefaultPushHandler{},
140
Navigator: parsedUserAgent,
141
}
142
rt.cachedTransports[addr] = &t2
143
default:
144
// Assume the remote peer is speaking HTTP 1.x + TLS.
145
rt.cachedTransports[addr] = &http.Transport{DialTLSContext: rt.dialTLS}
146
147
}
148
149
// Stash the connection just established for use servicing the
150
// actual request (should be near-immediate).
151
rt.cachedConnections[addr] = conn
152
153
return nil, errProtocolNegotiated
154
}
155
156
func (rt *roundTripper) dialTLSHTTP2(network, addr string, _ *utls.Config) (net.Conn, error) {
157
return rt.dialTLS(context.Background(), network, addr)
158
}
159
160
func (rt *roundTripper) getDialTLSAddr(req *http.Request) string {
161
host, port, err := net.SplitHostPort(req.URL.Host)
162
if err == nil {
163
return net.JoinHostPort(host, port)
164
}
165
return net.JoinHostPort(req.URL.Host, "443") // we can assume port is 443 at this point
166
}
167
168
func newRoundTripper(browser Browser, dialer ...proxy.ContextDialer) http.RoundTripper {
169
if len(dialer) > 0 {
170
171
return &roundTripper{
172
dialer: dialer[0],
173
174
JA3: browser.JA3,
175
UserAgent: browser.UserAgent,
176
Cookies: browser.Cookies,
177
cachedTransports: make(map[string]http.RoundTripper),
178
cachedConnections: make(map[string]net.Conn),
179
}
180
}
181
182
return &roundTripper{
183
dialer: proxy.Direct,
184
185
JA3: browser.JA3,
186
UserAgent: browser.UserAgent,
187
Cookies: browser.Cookies,
188
cachedTransports: make(map[string]http.RoundTripper),
189
cachedConnections: make(map[string]net.Conn),
190
}
191
}
192
193