-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
256 lines (236 loc) · 9.74 KB
/
index.js
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
// sprocess.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
require('dotenv').config({ path: '.env.local' });
const { MongoClient } = require('mongodb');
const fetch = require('node-fetch');
const dns = require('dns');
const dnsPromises = dns.promises;
const nodemailer = require('nodemailer');
const url = process.env.MONGODB_URL;
const client = new MongoClient(url);
const dbName = 'solun_proj';
const user_collection = 'users';
const user_domain_collection = 'user_domains';
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function sendMail(to, subject, html) {
let transporter = nodemailer.createTransport({
host: 'ms.solun.pm',
port: 465,
secure: true,
auth: {
user: 'admin@solun.pm',
pass: process.env.SOLUN_ADMIN_PASSWORD
}
});
let info = await transporter.sendMail({
from: '"Solun Support" <support@solun.pm>',
to: to,
subject: subject,
html: html
});
console.log('Message sent: %s', info.messageId);
}
function logInColor(message, status) {
const color = status === 'Correct' ? '\x1b[32m' : '\x1b[31m';
console.log(color, message, '\x1b[0m');
}
async function verifyDNSRecords(db, domain, dnsRecords) {
let allRecordsCorrect = true;
for (let record of dnsRecords) {
switch (record.type) {
case 'MX':
try {
const mxRecords = await dnsPromises.resolveMx(record.name);
//console.log('Expected MX:', record.data);
//console.log('Actual MX:', mxRecords[0]?.exchange);
if (!mxRecords || mxRecords[0].exchange != record.data) {
allRecordsCorrect = false;
logInColor('MX Check: Wrong', 'Wrong');
} else {
logInColor('MX Check: Correct', 'Correct');
}
} catch (err) {
allRecordsCorrect = false;
console.log('Error at querying MX Record');
}
break;
case 'CNAME':
try {
logInColor('CNAME Check: Skipped', 'Correct');
//const cnameRecords = await dnsPromises.resolveCname(record.name);
//console.log('Expected CNAME:', record.data);
//console.log('Actual CNAME:', cnameRecords[0]);
//if (!cnameRecords || cnameRecords[0] != record.data) {
// allRecordsCorrect = false;
// logInColor('CNAME Check: Wrong', 'Wrong');
//} else {
// logInColor('CNAME Check: Correct', 'Correct');
//}
}
catch (err) {
allRecordsCorrect = false;
console.log('Error at querying CNAME Record');
}
break;
case 'TXT':
try {
logInColor('TXT & DKIM Check: Skipped', 'Correct');
//const txtRecords = await dnsPromises.resolveTxt(record.name);
//if (record.name.includes('dkim')) { // Only apply this check for DKIM records
// let combinedTxtRecord = txtRecords.flat().join(''); // Combine all parts
//console.log('Expected TXT:', record.data);
//console.log('Actual TXT:', combinedTxtRecord);
// if (combinedTxtRecord !== record.data) {
// allRecordsCorrect = false;
// logInColor('DKIM Check: Wrong', 'Wrong');
// } else {
// logInColor('DKIM Check: Correct', 'Correct');
// }
//} else { // For non-DKIM TXT records
// let matchFound = false;
//console.log('Expected TXT:', record.data);
// for (let txtRecord of txtRecords.flat()) {
// //console.log('Actual TXT:', txtRecord);
// if (txtRecord === record.data) {
// matchFound = true;
// }
// }
// if (!matchFound) {
// allRecordsCorrect = false;
// logInColor('TXT Check: Wrong', 'Wrong');
// } else {
// logInColor('TXT Check: Correct', 'Correct');
// }
// }
}
catch (err) {
allRecordsCorrect = false;
console.log('Error at querying TXT records');
}
break;
case 'SRV':
try {
logInColor('SRV Check: Skipped', 'Correct');
//const srvRecords = await dnsPromises.resolveSrv(record.name);
//console.log('Expected SRV:', record.data.replace(' 443', ''));
//console.log('Actual SRV:', srvRecords[0]?.name);
//if (!srvRecords || srvRecords[0].name != record.data.replace(' 443', '')) {
// allRecordsCorrect = false;
// logInColor('SRV Check: Wrong', 'Wrong');
//} else {
// logInColor('SRV Check: Correct', 'Correct');
//}
}
catch (err) {
allRecordsCorrect = false;
console.log('Error at querying SRV Record');
}
break;
}
}
if (allRecordsCorrect) {
if(domain.verification_status === 'pending') {
const domains = db.collection(user_domain_collection);
await domains.updateOne({ domain: domain.domain }, { $set: { verification_status: 'active' } });
const user = await db.collection(user_collection).findOne({ user_id: domain.user_id });
const htmlContent = `
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
</head>
<body>
<div style="color: #334155; padding: 20px; font-family: Arial, sans-serif;">
<h1>Hello ${user.username},</h1>
<p style="font-size: 1.25rem; color: #1E3A8A;">Your domain ${domain.domain} is now active! <i class="fas fa-check-circle" style="color: #10B981;"></i></p>
<p style="font-size: 1rem; color: #1F2937;">Thank you for using Solun!</p>
<p style="font-size: 1rem; color: #64748B;">You can now create mailboxes and aliases for this domain in the Solun Dashboard. Enjoy!</p>
<p style="font-size: 1rem; color: #64748B;">If you need any assistance, please do not hesitate to reply to this email. We're here to help!</p>
</div>
</body>
</html>
`;
await sendMail(user.fqe, 'Your Domain is Active', htmlContent);
}
} else {
console.log("### DNS Records Incorrect for Domain:", domain.domain, "###")
const domains = db.collection(user_domain_collection);
if(domain.verification_status === 'active') {
const user = await db.collection(user_collection).findOne({ user_id: domain.user_id });
const htmlContent = `
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
</head>
<body>
<div style="color: #334155; padding: 20px; font-family: Arial, sans-serif;">
<h1>Hello ${user.username},</h1>
<p style="font-size: 1.25rem; color: #1E3A8A;">Your domain ${domain.domain} no longer complies with the Solun DNS records! <i class="fas fa-exclamation-circle" style="color: #EF4444;"></i></p>
<p style="font-size: 1rem; color: #1F2937;">We have paused it in your Solun account. To re-add it, please go to the dashboard and enter the DNS entries stored there.</p>
<p style="font-size: 1rem; color: #64748B;">It will be removed automatically after a few days, along with all your mailboxes and data - but we will warn you again before that happens.</p>
<p style="font-size: 1rem; color: #64748B;">If you need any assistance, please do not hesitate to reply to this email. We're here to help!</p>
</div>
</body>
</html>
`;
await sendMail(user.fqe, 'Your Domain is Inactive', htmlContent);
}
await domains.updateOne({ domain: domain.domain }, { $set: { verification_status: 'pending' } });
}
}
async function run() {
try {
await client.connect();
const db = client.db(dbName);
const users = db.collection(user_collection);
const domains = db.collection(user_domain_collection);
const cursor = domains.find({
verification_status: {
$in: ['pending', 'active']
}
}).sort({ verification_status: -1 });
while (await cursor.hasNext()) {
const domain = await cursor.next();
const user = await users.findOne({ user_id: domain.user_id });
console.log("### Domain:", domain.domain, "###");
console.log("### Owner:", user.fqe, "###");
console.log("### Verification Status:", domain.verification_status, "###");
console.log("### Created At:", new Date(domain.createdAt).toLocaleString(), "###");
await fetch(process.env.API_URL + '/user/domain/get_dns_records', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'authorization': process.env.API_KEY
},
body: JSON.stringify({
domain: domain.domain
})
})
.then(res => res.json())
.then(async json => {
await verifyDNSRecords(db, domain, json);
})
.catch(err => console.log(err));
if (await cursor.hasNext()) {
console.log('----------------------------------------');
console.log('Waiting for next Domain...');
console.log('----------------------------------------');
await sleep(120000); // 2 minutes
}
}
} finally {
console.log("### Script End @", new Date(), "###");
if (client) {
await client.close();
}
}
}
console.log("### Solun Check DNS ###");
console.log("### Script Start @", new Date(), "###");
run().catch(console.dir);
setInterval(async () => {
console.log("### Script Restart @", new Date(), "###");
await run().catch(console.dir);
}, 15 * 60 * 1000); // 15 minutes