File size: 4,557 Bytes
15f7aec
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
function proxyRequest({ url, proxy, method = 'GET', body = null, headers = {}, cookies = [], sessionHeaders = {} }) {
  return new Promise(async (resolve, reject) => {
    if (!url) return reject("Missing url parameter");
    
    const context = await global.browser
      .createBrowserContext({
        proxyServer: proxy ? `http://${proxy.host}:${proxy.port}` : undefined,
      })
      .catch(() => null);
    
    if (!context) return reject("Failed to create browser context");

    let isResolved = false;

    var cl = setTimeout(async () => {
      if (!isResolved) {
        await context.close();
        reject("Timeout Error");
      }
    }, global.timeOut || 60000);

    try {
      const page = await context.newPage();

      if (proxy?.username && proxy?.password)
        await page.authenticate({
          username: proxy.username,
          password: proxy.password,
        });

      const targetUrl = new URL(url);
      
      if (cookies && cookies.length > 0) {
        const cookiesToSet = cookies.map(cookie => ({
          name: cookie.name,
          value: cookie.value,
          domain: cookie.domain || targetUrl.hostname,
          path: cookie.path || '/',
          secure: cookie.secure !== undefined ? cookie.secure : targetUrl.protocol === 'https:',
          httpOnly: cookie.httpOnly || false,
          sameSite: cookie.sameSite || 'Lax'
        }));
        await page.setCookie(...cookiesToSet);
      }

      if (sessionHeaders && sessionHeaders['user-agent']) {
        await page.setUserAgent(sessionHeaders['user-agent']);
      }

      const sanitizedHeaders = { ...headers };
      const headersToRemove = ['host', 'content-length', 'connection', 'accept-encoding', 'transfer-encoding'];
      headersToRemove.forEach(h => {
        delete sanitizedHeaders[h];
        delete sanitizedHeaders[h.toLowerCase()];
      });

      if (sessionHeaders) {
        if (sessionHeaders['accept-language'] && !sanitizedHeaders['accept-language']) {
          sanitizedHeaders['accept-language'] = sessionHeaders['accept-language'];
        }
      }

      await page.goto(targetUrl.origin, { waitUntil: 'domcontentloaded', timeout: 30000 }).catch(() => {});

      const result = await page.evaluate(async (options) => {
        try {
          const fetchOptions = {
            method: options.method,
            headers: options.headers || {},
            credentials: 'include'
          };

          if (options.body && ['POST', 'PUT', 'PATCH'].includes(options.method.toUpperCase())) {
            fetchOptions.body = typeof options.body === 'string' 
              ? options.body 
              : JSON.stringify(options.body);
            if (typeof options.body === 'object' && !fetchOptions.headers['content-type']) {
              fetchOptions.headers['content-type'] = 'application/json';
            }
          }

          const response = await fetch(options.url, fetchOptions);
          
          const responseHeaders = {};
          response.headers.forEach((value, key) => {
            responseHeaders[key] = value;
          });

          let responseBody;
          const contentType = response.headers.get('content-type') || '';
          
          if (contentType.includes('application/json')) {
            responseBody = await response.json();
          } else {
            responseBody = await response.text();
          }

          return {
            status: response.status,
            statusText: response.statusText,
            headers: responseHeaders,
            body: responseBody,
            ok: response.ok
          };
        } catch (e) {
          return { error: e.message };
        }
      }, { url, method, body, headers: sanitizedHeaders });

      if (result.error) {
        await context.close();
        isResolved = true;
        clearTimeout(cl);
        return reject(result.error);
      }

      const updatedCookies = await page.cookies();
      
      const browserHeaders = await page.evaluate(() => {
        return {
          'user-agent': navigator.userAgent,
          'accept-language': navigator.language || navigator.languages.join(',')
        };
      });

      await context.close();
      isResolved = true;
      clearInterval(cl);

      resolve({
        response: result,
        cookies: updatedCookies,
        browserHeaders
      });

    } catch (e) {
      if (!isResolved) {
        await context.close();
        clearTimeout(cl);
        reject(e.message);
      }
    }
  });
}

module.exports = proxyRequest;