2024-12-03 22:36:16 -05:00
|
|
|
const express = require('express');
|
|
|
|
const bodyParser = require('body-parser');
|
|
|
|
const path = require('path');
|
2024-12-20 00:31:24 -05:00
|
|
|
const fs = require('fs');
|
2024-12-14 12:35:18 -05:00
|
|
|
const session = require('express-session');
|
|
|
|
const { Sequelize, DataTypes } = require('sequelize');
|
2024-12-31 20:11:41 -05:00
|
|
|
const axios = require('axios');
|
|
|
|
const NodeCache = require('node-cache');
|
|
|
|
const cache = new NodeCache({ stdTTL: 1800 });
|
2024-12-03 22:36:16 -05:00
|
|
|
|
2024-12-14 12:35:18 -05:00
|
|
|
require('dotenv').config();
|
2024-12-03 22:36:16 -05:00
|
|
|
const app = express();
|
|
|
|
|
|
|
|
app.set('view engine', 'ejs');
|
|
|
|
app.set('views', path.join(__dirname, 'src'));
|
|
|
|
|
|
|
|
app.use(bodyParser.urlencoded({ extended: false }));
|
|
|
|
app.use(express.static(path.join(__dirname, 'public')));
|
2024-12-14 12:35:18 -05:00
|
|
|
app.use(session({
|
|
|
|
secret: process.env.SESSION_SECRET,
|
|
|
|
resave: false,
|
|
|
|
saveUninitialized: true
|
|
|
|
}));
|
|
|
|
|
|
|
|
const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASSWORD, {
|
2024-12-28 13:05:50 -06:00
|
|
|
host: process.env.DB_HOST || '127.0.0.1', // pulls from .env or defaults to localhost
|
|
|
|
port: process.env.DB_PORT || 3306, // pulls from .env or defaults to 3306
|
2024-12-14 12:35:18 -05:00
|
|
|
dialect: 'mysql'
|
|
|
|
});
|
|
|
|
|
|
|
|
sequelize.authenticate()
|
|
|
|
.then(() => console.log('Database connected'))
|
|
|
|
.catch(err => console.log('Error: ' + err));
|
|
|
|
|
|
|
|
const Request = sequelize.define('Request', {
|
|
|
|
fullName: DataTypes.STRING,
|
|
|
|
email: DataTypes.STRING,
|
|
|
|
reason: DataTypes.TEXT,
|
|
|
|
telegram: DataTypes.STRING,
|
|
|
|
status: {
|
|
|
|
type: DataTypes.STRING,
|
|
|
|
defaultValue: 'Pending'
|
|
|
|
}
|
|
|
|
});
|
2024-12-03 22:36:16 -05:00
|
|
|
|
2024-12-31 20:11:41 -05:00
|
|
|
async function fetchDomainData() {
|
|
|
|
const cachedData = cache.get('domainData');
|
|
|
|
if (cachedData) {
|
|
|
|
return cachedData;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const response = await axios.get('https://user.p0ntus.com/api/v1/get/domain/all', {
|
|
|
|
headers: {
|
|
|
|
'accept': 'application/json',
|
|
|
|
'X-API-Key': process.env.MC_API_KEY
|
|
|
|
}
|
|
|
|
});
|
|
|
|
const domainData = response.data;
|
|
|
|
cache.set('domainData', domainData);
|
|
|
|
return domainData;
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Error fetching domain data:', error);
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-06 20:33:38 -05:00
|
|
|
function getDomains() {
|
|
|
|
const domainsPath = path.join(__dirname, 'domains.txt');
|
|
|
|
try {
|
|
|
|
const domains = fs.readFileSync(domainsPath, 'utf-8').split('\n').filter(Boolean);
|
|
|
|
return domains;
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Error reading domains.txt:', error);
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-28 13:05:50 -06:00
|
|
|
// Sync DB models
|
2024-12-14 12:35:18 -05:00
|
|
|
sequelize.sync();
|
|
|
|
|
2024-12-31 20:11:41 -05:00
|
|
|
app.get('/', async (req, res) => {
|
|
|
|
const domainData = await fetchDomainData();
|
|
|
|
const domainCount = Array.isArray(domainData) ? domainData.length : 0;
|
|
|
|
const accountCount = Array.isArray(domainData) ? domainData.reduce((acc, domain) => acc + domain.mboxes_in_domain, 0) : 0;
|
|
|
|
const totalData = Array.isArray(domainData) ? domainData.reduce((acc, domain) => acc + parseInt(domain.bytes_total), 0) / (1024 * 1024) : 0;
|
|
|
|
|
|
|
|
res.render('index', {
|
|
|
|
currentPage: 'home',
|
|
|
|
domainCount,
|
|
|
|
accountCount,
|
|
|
|
totalData: totalData.toFixed(2) // Round to 2 decimal places
|
|
|
|
});
|
2024-12-03 22:36:16 -05:00
|
|
|
});
|
|
|
|
|
2024-12-04 20:34:11 -05:00
|
|
|
app.get('/services', (req, res) => {
|
|
|
|
res.render('services', { currentPage: 'services' });
|
|
|
|
});
|
|
|
|
|
|
|
|
app.get('/donate', (req, res) => {
|
|
|
|
const donations = JSON.parse(fs.readFileSync('donations.json', 'utf8'));
|
|
|
|
res.render('donate', {
|
|
|
|
currentPage: 'donate',
|
|
|
|
bitcoin: donations.bitcoin,
|
|
|
|
litecoin: donations.litecoin,
|
|
|
|
ethereum: donations.ethereum,
|
2024-12-20 00:48:37 -05:00
|
|
|
monero: donations.monero,
|
|
|
|
solana: donations.solana,
|
2024-12-04 20:34:11 -05:00
|
|
|
current: donations.current,
|
|
|
|
goal: donations.goal
|
|
|
|
});
|
2024-12-03 22:36:16 -05:00
|
|
|
});
|
|
|
|
|
2024-12-05 10:11:58 -05:00
|
|
|
app.get('/privacy', (req, res) => {
|
|
|
|
res.render('privacy', { currentPage: 'privacy' });
|
|
|
|
});
|
|
|
|
|
2024-12-28 13:05:50 -06:00
|
|
|
// Guide routes
|
|
|
|
// TODO: Improve how guides are routed to be simpler
|
|
|
|
|
2024-12-08 18:14:58 -05:00
|
|
|
app.get('/guides', (req, res) => {
|
|
|
|
res.render('guides', { currentPage: 'guides' });
|
|
|
|
});
|
|
|
|
|
|
|
|
app.get('/guides/user', (req, res) => {
|
|
|
|
res.render('guides/user/index', { currentPage: 'guides' });
|
|
|
|
});
|
|
|
|
|
|
|
|
app.get('/guides/webmail', (req, res) => {
|
|
|
|
res.render('guides/webmail/index', { currentPage: 'guides' });
|
|
|
|
});
|
|
|
|
|
|
|
|
app.get('/guides/vaultwarden/android', (req, res) => {
|
|
|
|
res.render('guides/vaultwarden/android', { currentPage: 'guides' });
|
|
|
|
});
|
|
|
|
|
|
|
|
app.get('/guides/vaultwarden/chrome', (req, res) => {
|
|
|
|
res.render('guides/vaultwarden/chrome', { currentPage: 'guides' });
|
|
|
|
});
|
|
|
|
|
|
|
|
app.get('/guides/vaultwarden/firefox', (req, res) => {
|
|
|
|
res.render('guides/vaultwarden/firefox', { currentPage: 'guides' });
|
|
|
|
});
|
|
|
|
|
2024-12-14 12:35:18 -05:00
|
|
|
app.get('/register', (req, res) => {
|
2025-01-06 20:33:38 -05:00
|
|
|
const domains = getDomains();
|
|
|
|
res.render('register', { domains });
|
2024-12-14 12:35:18 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
app.post('/register', async (req, res) => {
|
2025-01-06 20:33:38 -05:00
|
|
|
const { fullName, email, domain, reason, telegram } = req.body;
|
2024-12-27 03:37:32 -06:00
|
|
|
const crit = /^[a-zA-Z0-9.-]+$/; // regex (see also: public/js/register.js)
|
2025-01-06 20:33:38 -05:00
|
|
|
|
2024-12-27 03:37:32 -06:00
|
|
|
if (!crit.test(email) || /\s/.test(email) || email !== email.toLowerCase()) {
|
|
|
|
return res.render('error/500');
|
|
|
|
}
|
2025-01-06 20:33:38 -05:00
|
|
|
|
|
|
|
const fullEmail = `${email}@${domain}`;
|
|
|
|
|
|
|
|
try {
|
|
|
|
await Request.create({ fullName, email: fullEmail, reason, telegram });
|
|
|
|
res.render('reg-success', { currentPage: 'register' });
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Error creating request:', error);
|
|
|
|
res.render('error/500');
|
|
|
|
}
|
2024-12-14 12:35:18 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
app.get('/request', async (req, res) => {
|
2025-01-06 20:33:38 -05:00
|
|
|
console.log("Found!");
|
2024-12-14 12:35:18 -05:00
|
|
|
const { email } = req.query;
|
2025-01-06 20:33:38 -05:00
|
|
|
const domains = getDomains();
|
2024-12-14 12:35:18 -05:00
|
|
|
|
|
|
|
if (!email) {
|
2025-01-06 20:33:38 -05:00
|
|
|
return res.render('error/email', { domains });
|
2024-12-14 12:35:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const request = await Request.findOne({ where: { email } });
|
|
|
|
if (!request) {
|
2025-01-06 20:33:38 -05:00
|
|
|
return res.status(404).render('error/notfoundemail', { email, domain });
|
|
|
|
}
|
|
|
|
res.render('request', { request, domains });
|
|
|
|
} catch (error) {
|
|
|
|
console.error(error);
|
|
|
|
res.render('error/500');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
app.post('/request', async (req, res) => {
|
|
|
|
console.log("Found!");
|
|
|
|
const { email, domain } = req.body;
|
|
|
|
const fullEmail = `${email}@${domain}`;
|
|
|
|
const domains = getDomains();
|
|
|
|
|
|
|
|
if (!email || !domain) {
|
|
|
|
return res.render('error/email', { domains });
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const request = await Request.findOne({ where: { email: fullEmail } });
|
|
|
|
const domains = getDomains();
|
|
|
|
if (!request) {
|
|
|
|
return res.render('error/notfoundemail', { email, domain });
|
2024-12-14 12:35:18 -05:00
|
|
|
}
|
2025-01-06 20:33:38 -05:00
|
|
|
res.render('request', { request, domains });
|
2024-12-14 12:35:18 -05:00
|
|
|
} catch (error) {
|
|
|
|
console.error(error);
|
2025-01-06 20:33:38 -05:00
|
|
|
res.render('error/500');
|
2024-12-14 12:35:18 -05:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
function checkAdminAuth(req, res, next) {
|
|
|
|
if (req.session.admin) {
|
|
|
|
next();
|
|
|
|
} else {
|
2024-12-15 16:06:55 -05:00
|
|
|
res.redirect('/admin');
|
2024-12-14 12:35:18 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-28 13:05:50 -06:00
|
|
|
// Admin routes
|
|
|
|
|
2024-12-14 12:35:18 -05:00
|
|
|
app.get('/admin', (req, res) => {
|
2024-12-15 16:06:55 -05:00
|
|
|
if (req.session.admin) {
|
|
|
|
return res.redirect('/admin/dashboard');
|
|
|
|
}
|
2024-12-28 13:05:50 -06:00
|
|
|
res.render('admin/login', { currentPage: 'admin', error: null });
|
2024-12-14 12:35:18 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
app.post('/admin', (req, res) => {
|
|
|
|
const { username, password } = req.body;
|
|
|
|
if (username === process.env.ADMIN_USERNAME && password === process.env.ADMIN_PASSWORD) {
|
|
|
|
req.session.admin = true;
|
|
|
|
res.redirect('/admin/dashboard');
|
|
|
|
} else {
|
2024-12-28 13:05:50 -06:00
|
|
|
res.render('admin/login', { error: 'An error occurred.' });
|
2024-12-14 12:35:18 -05:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
app.get('/admin/dashboard', checkAdminAuth, async (req, res) => {
|
|
|
|
const requests = await Request.findAll();
|
2024-12-31 01:41:07 -05:00
|
|
|
res.render('admin/dash', { requests, currentPage: 'admin', user: process.env.ADMIN_USERNAME });
|
2024-12-14 12:35:18 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
app.post('/admin/update-status', checkAdminAuth, async (req, res) => {
|
|
|
|
const { id, status } = req.body;
|
|
|
|
await Request.update({ status }, { where: { id } });
|
2024-12-17 10:53:19 -05:00
|
|
|
res.redirect('/admin/dashboard');
|
2024-12-14 12:35:18 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
app.post('/admin/delete-request', checkAdminAuth, async (req, res) => {
|
|
|
|
const { id } = req.body;
|
|
|
|
await Request.destroy({ where: { id } });
|
|
|
|
res.redirect('/admin/dashboard');
|
|
|
|
});
|
|
|
|
|
2024-12-31 01:41:07 -05:00
|
|
|
app.get('/admin/edit/:id', checkAdminAuth, async (req, res) => {
|
|
|
|
const { id } = req.params;
|
|
|
|
const request = await Request.findByPk(id);
|
|
|
|
if (!request) {
|
|
|
|
return res.status(404).render('error/404');
|
|
|
|
}
|
|
|
|
res.render('admin/edit', { request, currentPage: 'admin' });
|
|
|
|
});
|
|
|
|
|
|
|
|
app.post('/admin/edit', checkAdminAuth, async (req, res) => {
|
|
|
|
const { id, fullName, email, reason, telegram } = req.body;
|
|
|
|
await Request.update({ fullName, email, reason, telegram }, { where: { id } });
|
|
|
|
res.redirect('/admin/dashboard');
|
|
|
|
});
|
|
|
|
|
2024-12-28 13:05:50 -06:00
|
|
|
// Start server on internal port defined in .env
|
|
|
|
app.listen(process.env.INTERNAL_PORT, () => {
|
|
|
|
console.log(`Server started on port ${process.env.INTERNAL_PORT}`);
|
2024-12-03 22:36:16 -05:00
|
|
|
});
|