Spaces:
Running
Running
Update index.js
Browse files
index.js
CHANGED
@@ -5,256 +5,236 @@ const cheerio = require('cheerio');
|
|
5 |
const app = express();
|
6 |
const port = process.env.PORT || 3000;
|
7 |
|
8 |
-
// Global
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
const domainStatus = data.match(/Domain Status:\s*(.*)/)?.[1]?.trim();
|
21 |
-
const frozenStatus = data.match(/Frozen Status:\s*(.*)/)?.[1]?.trim();
|
22 |
-
const transferStatus = data.match(/Transfer Status:\s*(.*)/)?.[1]?.trim();
|
23 |
-
|
24 |
-
// Registrant details (in this case they are hidden)
|
25 |
-
const registrant = data.match(/Registrant:\n([\s\S]*?)\n\n/)?.[1]?.trim().split('\n').map(line => line.trim());
|
26 |
-
|
27 |
-
// Registrar details
|
28 |
-
const nicHandle = data.match(/NIC Handle\s*:\s*(.*)/)?.[1]?.trim();
|
29 |
-
const registrarName = data.match(/Organization Name\s*:\s*(.*)/)?.[1]?.trim();
|
30 |
-
const registrarAddress = data.match(/Address\s*:\s*(.*)/)?.[1]?.trim();
|
31 |
-
const registrarPhone = data.match(/Phone\s*:\s*(.*)/)?.[1]?.trim();
|
32 |
-
const registrarFax = data.match(/Fax\s*:\s*(.*)/)?.[1]?.trim();
|
33 |
-
|
34 |
-
// Domain servers
|
35 |
-
const nameservers = data.match(/Domain Servers:\n([\s\S]*?)\n\n/)?.[1]?.trim().split('\n');
|
36 |
-
|
37 |
-
// Additional info (Created and Expiry dates)
|
38 |
-
const createdDate = data.match(/Created on.*:\s*(.*)/)?.[1]?.trim();
|
39 |
-
const expiresDate = data.match(/Expires on.*:\s*(.*)/)?.[1]?.trim();
|
40 |
|
41 |
-
|
42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
|
|
|
|
|
|
|
|
|
44 |
return {
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
};
|
62 |
};
|
63 |
|
64 |
-
|
|
|
|
|
|
|
|
|
65 |
try {
|
66 |
const response = await axios({
|
67 |
method: 'get',
|
68 |
url: 'https://www.trabis.gov.tr/whois',
|
69 |
headers: {
|
70 |
-
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9
|
71 |
-
'accept-language': 'en,tr;q=0.9
|
72 |
-
'cache-control': '
|
73 |
-
'
|
74 |
-
|
75 |
-
|
76 |
-
'sec-ch-ua': '"Microsoft Edge";v="129", "Not=A?Brand";v="8", "Chromium";v="129"',
|
77 |
-
'sec-ch-ua-mobile': '?0',
|
78 |
-
'sec-ch-ua-platform': '"Windows"',
|
79 |
-
'sec-fetch-dest': 'document',
|
80 |
-
'sec-fetch-mode': 'navigate',
|
81 |
-
'sec-fetch-site': 'same-origin',
|
82 |
-
'sec-fetch-user': '?1',
|
83 |
-
'upgrade-insecure-requests': '1',
|
84 |
-
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0'
|
85 |
-
}
|
86 |
});
|
87 |
|
88 |
-
console.log('Response status:', response.status);
|
89 |
-
|
90 |
-
// Extract _token value and set it as a global variable
|
91 |
const $ = cheerio.load(response.data);
|
92 |
-
token = $('#search-domain-form > input[type=hidden]:nth-child(1)').val();
|
93 |
-
|
94 |
-
|
95 |
-
// Extract and format cookies, then set as a global variable
|
96 |
-
const rawCookies = response.headers['set-cookie'];
|
97 |
-
if (rawCookies) {
|
98 |
-
cookies = rawCookies.map(cookie => cookie.split(';')[0]).join('; ');
|
99 |
-
console.log('Cookies formatted and set globally');
|
100 |
-
} else {
|
101 |
-
console.log('No cookies found in the response');
|
102 |
-
}
|
103 |
-
|
104 |
-
// Log the global values
|
105 |
-
console.log('\nGlobal _token:', token);
|
106 |
-
console.log('Global cookies:', cookies);
|
107 |
|
|
|
108 |
} catch (error) {
|
109 |
-
console.error(
|
110 |
-
}
|
111 |
-
}
|
112 |
-
|
113 |
-
setInterval(sendRequestAndSetGlobals, 3600000);
|
114 |
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
const endTime = Date.now();
|
120 |
-
totalTime += endTime - startTime;
|
121 |
-
averageResponseTime = (totalTime / requestsCount).toFixed(2);
|
122 |
-
|
123 |
-
// track domains queried
|
124 |
-
if (req.query.domain) {
|
125 |
-
const domain = req.query.domain;
|
126 |
-
if (!domainsQueried[domain]) {
|
127 |
-
domainsQueried[domain] = 1;
|
128 |
-
} else {
|
129 |
-
domainsQueried[domain]++;
|
130 |
}
|
|
|
131 |
}
|
132 |
-
}
|
133 |
-
|
134 |
-
app.get('/stats', (req, res) => {
|
135 |
-
const stats = {
|
136 |
-
requestsCount,
|
137 |
-
averageResponseTime: parseFloat(averageResponseTime),
|
138 |
-
uptime: parseFloat(process.uptime().toFixed(2)),
|
139 |
-
domainsQueried: Object.keys(domainsQueried).map((domain) => ({
|
140 |
-
domain,
|
141 |
-
count: domainsQueried[domain],
|
142 |
-
})),
|
143 |
-
};
|
144 |
-
|
145 |
-
res.json(stats);
|
146 |
-
});
|
147 |
|
148 |
-
|
149 |
-
|
150 |
|
151 |
-
|
152 |
-
|
153 |
-
}
|
154 |
-
|
155 |
try {
|
156 |
const response = await axios.post(
|
157 |
'https://www.trabis.gov.tr/search-domain',
|
158 |
-
new URLSearchParams({
|
159 |
-
_token: token,
|
160 |
-
domain: domain
|
161 |
-
}),
|
162 |
{
|
163 |
headers: {
|
164 |
-
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9
|
165 |
-
'accept-language': 'en,tr;q=0.9,en-GB;q=0.8,en-US;q=0.7',
|
166 |
-
'cache-control': 'max-age=0',
|
167 |
'content-type': 'application/x-www-form-urlencoded',
|
168 |
-
'cookie': cookies,
|
169 |
'origin': 'https://www.trabis.gov.tr',
|
170 |
-
'priority': 'u=0, i',
|
171 |
'referer': 'https://www.trabis.gov.tr/',
|
172 |
-
'
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
'sec-fetch-mode': 'navigate',
|
177 |
-
'sec-fetch-site': 'same-origin',
|
178 |
-
'sec-fetch-user': '?1',
|
179 |
-
'upgrade-insecure-requests': '1',
|
180 |
-
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0'
|
181 |
-
}
|
182 |
}
|
183 |
);
|
184 |
|
185 |
-
|
186 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
187 |
|
188 |
const keywords = {
|
189 |
-
Belgeli:
|
190 |
-
Belgesiz:
|
191 |
-
kullanımdadır:
|
192 |
-
başvurulmuş:
|
193 |
-
tahsis:
|
194 |
};
|
195 |
|
196 |
-
|
197 |
-
const text = $('body').text();
|
198 |
-
keywords.Belgeli = text.includes('Belgeli');
|
199 |
-
keywords.Belgesiz = text.includes('Belgesiz');
|
200 |
-
keywords.kullanımdadır = text.includes('kullanımdadır');
|
201 |
-
keywords.başvurulmuş = text.includes('başvuruldu');
|
202 |
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
keywords.tahsis = true;
|
207 |
-
const dateMatch = text.match(/(\d{2}\/\d{2}\/\d{4}) tarihinden itibaren/);
|
208 |
-
if (dateMatch) {
|
209 |
-
reassignmentDate = dateMatch[1];
|
210 |
-
}
|
211 |
}
|
212 |
|
213 |
-
if (
|
214 |
-
|
|
|
215 |
}
|
216 |
|
217 |
-
|
218 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
219 |
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
res.json({
|
234 |
-
domain,
|
235 |
-
status: keywords,
|
236 |
-
...(reassignmentDate && { reassignmentDate })
|
237 |
-
});
|
238 |
}
|
|
|
|
|
|
|
|
|
239 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
240 |
} catch (error) {
|
241 |
-
|
242 |
-
|
243 |
-
|
|
|
244 |
}
|
245 |
});
|
246 |
|
247 |
-
// default router
|
248 |
app.get('/', (req, res) => {
|
249 |
res.status(200).json({ success: true });
|
250 |
-
})
|
251 |
|
252 |
-
//404 not found
|
253 |
app.get('*', (req, res) => {
|
254 |
-
res.status(404).json({error: 'Page not found'});
|
255 |
-
})
|
256 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
257 |
app.listen(port, async () => {
|
258 |
-
|
259 |
-
|
|
|
|
|
|
|
|
|
|
|
260 |
});
|
|
|
5 |
const app = express();
|
6 |
const port = process.env.PORT || 3000;
|
7 |
|
8 |
+
// Global state with better structure
|
9 |
+
const globals = {
|
10 |
+
token: '',
|
11 |
+
cookies: '',
|
12 |
+
stats: {
|
13 |
+
requestsCount: 0,
|
14 |
+
totalTime: 0,
|
15 |
+
domainsQueried: {},
|
16 |
+
averageResponseTime: 0,
|
17 |
+
lastTokenRefresh: null
|
18 |
+
}
|
19 |
+
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
+
// Precompiled regex patterns for better performance
|
22 |
+
const regexPatterns = {
|
23 |
+
domainName: /Domain Name:\s*(.*)/,
|
24 |
+
domainStatus: /Domain Status:\s*(.*)/,
|
25 |
+
frozenStatus: /Frozen Status:\s*(.*)/,
|
26 |
+
transferStatus: /Transfer Status:\s*(.*)/,
|
27 |
+
registrant: /Registrant:\n([\s\S]*?)\n\n/,
|
28 |
+
nicHandle: /NIC Handle\s*:\s*(.*)/,
|
29 |
+
registrarName: /Organization Name\s*:\s*(.*)/,
|
30 |
+
registrarAddress: /Address\s*:\s*(.*)/,
|
31 |
+
registrarPhone: /Phone\s*:\s*(.*)/,
|
32 |
+
registrarFax: /Fax\s*:\s*(.*)/,
|
33 |
+
nameservers: /Domain Servers:\n([\s\S]*?)\n\n/,
|
34 |
+
createdDate: /Created on.*:\s*(.*)/,
|
35 |
+
expiresDate: /Expires on.*:\s*(.*)/,
|
36 |
+
lastUpdateTime: /Last Update Time:\s*(.*)/,
|
37 |
+
reassignmentDate: /(\d{2}\/\d{2}\/\d{4}) tarihinden itibaren/
|
38 |
+
};
|
39 |
|
40 |
+
// Optimized data extraction function
|
41 |
+
const extractData = (data) => {
|
42 |
+
const extract = (pattern) => pattern.exec(data)?.[1]?.trim();
|
43 |
+
|
44 |
return {
|
45 |
+
domainName: extract(regexPatterns.domainName),
|
46 |
+
domainStatus: extract(regexPatterns.domainStatus),
|
47 |
+
frozenStatus: extract(regexPatterns.frozenStatus),
|
48 |
+
transferStatus: extract(regexPatterns.transferStatus),
|
49 |
+
registrant: extract(regexPatterns.registrant)?.split('\n').map(line => line.trim()),
|
50 |
+
registrar: {
|
51 |
+
nicHandle: extract(regexPatterns.nicHandle),
|
52 |
+
registrarName: extract(regexPatterns.registrarName),
|
53 |
+
registrarAddress: extract(regexPatterns.registrarAddress),
|
54 |
+
registrarPhone: extract(regexPatterns.registrarPhone),
|
55 |
+
registrarFax: extract(regexPatterns.registrarFax)
|
56 |
+
},
|
57 |
+
nameservers: extract(regexPatterns.nameservers)?.split('\n'),
|
58 |
+
createdDate: extract(regexPatterns.createdDate),
|
59 |
+
expiresDate: extract(regexPatterns.expiresDate),
|
60 |
+
lastUpdateTime: extract(regexPatterns.lastUpdateTime)
|
61 |
};
|
62 |
};
|
63 |
|
64 |
+
// Optimized token refresh with retries
|
65 |
+
async function refreshToken(retryCount = 0) {
|
66 |
+
const maxRetries = 3;
|
67 |
+
const baseDelay = 1000;
|
68 |
+
|
69 |
try {
|
70 |
const response = await axios({
|
71 |
method: 'get',
|
72 |
url: 'https://www.trabis.gov.tr/whois',
|
73 |
headers: {
|
74 |
+
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9',
|
75 |
+
'accept-language': 'en,tr;q=0.9',
|
76 |
+
'cache-control': 'no-cache',
|
77 |
+
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
78 |
+
},
|
79 |
+
timeout: 5000
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
});
|
81 |
|
|
|
|
|
|
|
82 |
const $ = cheerio.load(response.data);
|
83 |
+
globals.token = $('#search-domain-form > input[type=hidden]:nth-child(1)').val();
|
84 |
+
globals.cookies = response.headers['set-cookie']?.map(cookie => cookie.split(';')[0]).join('; ') || '';
|
85 |
+
globals.stats.lastTokenRefresh = Date.now();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
|
87 |
+
return true;
|
88 |
} catch (error) {
|
89 |
+
console.error(`Token refresh attempt ${retryCount + 1} failed:`, error.message);
|
|
|
|
|
|
|
|
|
90 |
|
91 |
+
if (retryCount < maxRetries) {
|
92 |
+
const delay = baseDelay * Math.pow(2, retryCount);
|
93 |
+
await new Promise(resolve => setTimeout(resolve, delay));
|
94 |
+
return refreshToken(retryCount + 1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
}
|
96 |
+
throw error;
|
97 |
}
|
98 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
|
100 |
+
// Automatic token refresh every hour
|
101 |
+
setInterval(refreshToken, 3600000);
|
102 |
|
103 |
+
// Optimized WHOIS request processing
|
104 |
+
async function processWhoisRequest(domain) {
|
|
|
|
|
105 |
try {
|
106 |
const response = await axios.post(
|
107 |
'https://www.trabis.gov.tr/search-domain',
|
108 |
+
new URLSearchParams({ _token: globals.token, domain }),
|
|
|
|
|
|
|
109 |
{
|
110 |
headers: {
|
111 |
+
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9',
|
|
|
|
|
112 |
'content-type': 'application/x-www-form-urlencoded',
|
113 |
+
'cookie': globals.cookies,
|
114 |
'origin': 'https://www.trabis.gov.tr',
|
|
|
115 |
'referer': 'https://www.trabis.gov.tr/',
|
116 |
+
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
117 |
+
},
|
118 |
+
timeout: 10000,
|
119 |
+
validateStatus: status => status < 500 // Accept all status codes below 500
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
}
|
121 |
);
|
122 |
|
123 |
+
// Handle invalid token
|
124 |
+
if (response.status === 419) {
|
125 |
+
await refreshToken();
|
126 |
+
return processWhoisRequest(domain);
|
127 |
+
}
|
128 |
+
|
129 |
+
const $ = cheerio.load(response.data);
|
130 |
+
const text = $('body').text();
|
131 |
+
|
132 |
+
if (text.includes("Hatalı")) {
|
133 |
+
throw new Error('Invalid domain (Only TR Domains)');
|
134 |
+
}
|
135 |
|
136 |
const keywords = {
|
137 |
+
Belgeli: text.includes('Belgeli'),
|
138 |
+
Belgesiz: text.includes('Belgesiz'),
|
139 |
+
kullanımdadır: text.includes('kullanımdadır'),
|
140 |
+
başvurulmuş: text.includes('başvuruldu'),
|
141 |
+
tahsis: text.includes('yeniden tahsis listesinde')
|
142 |
};
|
143 |
|
144 |
+
let result = { domain, status: keywords };
|
|
|
|
|
|
|
|
|
|
|
145 |
|
146 |
+
if (keywords.tahsis) {
|
147 |
+
const dateMatch = regexPatterns.reassignmentDate.exec(text);
|
148 |
+
if (dateMatch) result.reassignmentDate = dateMatch[1];
|
|
|
|
|
|
|
|
|
|
|
149 |
}
|
150 |
|
151 |
+
if (keywords.kullanımdadır) {
|
152 |
+
const whoisText = $('#main > div > div.Sub-page-content > div > div > section > div:nth-child(4) > pre').text();
|
153 |
+
result.whoisData = extractData(whoisText);
|
154 |
}
|
155 |
|
156 |
+
return result;
|
157 |
+
} catch (error) {
|
158 |
+
if (error.response?.status === 419) {
|
159 |
+
await refreshToken();
|
160 |
+
return processWhoisRequest(domain);
|
161 |
+
}
|
162 |
+
throw error;
|
163 |
+
}
|
164 |
+
}
|
165 |
|
166 |
+
// Performance tracking middleware
|
167 |
+
app.use((req, res, next) => {
|
168 |
+
const startTime = Date.now();
|
169 |
+
globals.stats.requestsCount++;
|
170 |
+
|
171 |
+
res.on('finish', () => {
|
172 |
+
const duration = Date.now() - startTime;
|
173 |
+
globals.stats.totalTime += duration;
|
174 |
+
globals.stats.averageResponseTime = globals.stats.totalTime / globals.stats.requestsCount;
|
175 |
+
|
176 |
+
if (req.query.domain) {
|
177 |
+
globals.stats.domainsQueried[req.query.domain] =
|
178 |
+
(globals.stats.domainsQueried[req.query.domain] || 0) + 1;
|
|
|
|
|
|
|
|
|
|
|
179 |
}
|
180 |
+
});
|
181 |
+
|
182 |
+
next();
|
183 |
+
});
|
184 |
|
185 |
+
// Routes
|
186 |
+
app.get('/stats', (req, res) => {
|
187 |
+
res.json({
|
188 |
+
requestsCount: globals.stats.requestsCount,
|
189 |
+
averageResponseTime: parseFloat(globals.stats.averageResponseTime.toFixed(2)),
|
190 |
+
uptime: parseFloat(process.uptime().toFixed(2)),
|
191 |
+
lastTokenRefresh: globals.stats.lastTokenRefresh,
|
192 |
+
domainsQueried: Object.entries(globals.stats.domainsQueried).map(([domain, count]) => ({
|
193 |
+
domain,
|
194 |
+
count
|
195 |
+
}))
|
196 |
+
});
|
197 |
+
});
|
198 |
+
|
199 |
+
app.get('/whois', async (req, res) => {
|
200 |
+
const { domain } = req.query;
|
201 |
+
|
202 |
+
if (!domain) {
|
203 |
+
return res.status(400).json({ error: 'Domain is required' });
|
204 |
+
}
|
205 |
+
|
206 |
+
try {
|
207 |
+
const result = await processWhoisRequest(domain);
|
208 |
+
res.json(result);
|
209 |
} catch (error) {
|
210 |
+
console.error('Error processing request:', error);
|
211 |
+
res.status(error.response?.status || 500).json({
|
212 |
+
error: error.message || 'An error occurred'
|
213 |
+
});
|
214 |
}
|
215 |
});
|
216 |
|
|
|
217 |
app.get('/', (req, res) => {
|
218 |
res.status(200).json({ success: true });
|
219 |
+
});
|
220 |
|
|
|
221 |
app.get('*', (req, res) => {
|
222 |
+
res.status(404).json({ error: 'Page not found' });
|
223 |
+
});
|
224 |
|
225 |
+
// Graceful shutdown
|
226 |
+
process.on('SIGTERM', () => {
|
227 |
+
console.log('Received SIGTERM. Performing graceful shutdown...');
|
228 |
+
process.exit(0);
|
229 |
+
});
|
230 |
+
|
231 |
+
// Initialize server
|
232 |
app.listen(port, async () => {
|
233 |
+
try {
|
234 |
+
await refreshToken();
|
235 |
+
console.log(`Server running on port ${port}`);
|
236 |
+
} catch (error) {
|
237 |
+
console.error('Failed to start server:', error);
|
238 |
+
process.exit(1);
|
239 |
+
}
|
240 |
});
|