Add project files.
This commit is contained in:
commit
0a12c6baa0
41 changed files with 2698 additions and 0 deletions
101
src/app.js
Normal file
101
src/app.js
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
// Load environment variables
|
||||
const env = require('./utils/env');
|
||||
|
||||
// Import modules
|
||||
const express = require('express');
|
||||
const helmet = require('helmet');
|
||||
const cors = require('cors');
|
||||
const compression = require('compression');
|
||||
const rateLimit = require('express-rate-limit');
|
||||
const expressWinston = require('express-winston');
|
||||
const { logger } = require('./utils/logger');
|
||||
const path = require('path');
|
||||
|
||||
// Import routes
|
||||
const authRouter = require('./routes/auth');
|
||||
const billingRouter = require('./routes/billing');
|
||||
const gatewayRouter = require('./routes/gateway');
|
||||
const loginRouter = require('./routes/launcher/login');
|
||||
const registerRouter = require('./routes/launcher/register');
|
||||
const codeVerificationRouter = require('./routes/launcher/codeVerification');
|
||||
const passwordResetEmailRouter = require('./routes/launcher/passwordResetEmail');
|
||||
const passwordChangeRouter = require('./routes/launcher/changePassword');
|
||||
const verificationEmailRouter = require('./routes/launcher/verificationEmail');
|
||||
const launcherUpdaterRouter = require('./routes/launcher/launcherUpdater');
|
||||
|
||||
// Set up rate limiter
|
||||
const limiter = rateLimit({
|
||||
windowMs: 60 * 1000, // 1 minute
|
||||
max: 60, // limit each IP to 60 requests per minute
|
||||
message: 'Too many requests from this IP, please try again later'
|
||||
});
|
||||
|
||||
const app = express();
|
||||
|
||||
// Set up middleware
|
||||
const middleware = [
|
||||
cors(),
|
||||
compression(),
|
||||
express.json(),
|
||||
express.urlencoded({ extended: false }),
|
||||
];
|
||||
|
||||
if (process.env.ENABLE_HELMET === 'true') {
|
||||
middleware.unshift(helmet());
|
||||
}
|
||||
|
||||
app.use(...middleware);
|
||||
|
||||
const authPort = process.env.AUTH_PORT || 8070;
|
||||
const billingPort = process.env.BILLING_PORT || 8080;
|
||||
|
||||
// Set up routes
|
||||
app.use('/serverApi/auth', limiter, authRouter).listen(authPort, '127.0.0.1');
|
||||
app.use('/serverApi/billing', limiter , billingRouter).listen(billingPort, '127.0.0.1');
|
||||
app.use('/serverApi/gateway', limiter , gatewayRouter);
|
||||
app.use('/accountApi/register', limiter , registerRouter);
|
||||
app.use('/accountApi/login', limiter , loginRouter);
|
||||
app.use('/accountApi/codeVerification', limiter , codeVerificationRouter);
|
||||
app.use('/accountApi/sendPasswordResetEmail', limiter , passwordResetEmailRouter);
|
||||
app.use('/accountApi/changePassword', limiter , passwordChangeRouter);
|
||||
app.use('/accountApi/sendVerificationEmail', limiter , verificationEmailRouter);
|
||||
app.use('/launcherApi/launcherUpdater', launcherUpdaterRouter);
|
||||
|
||||
// Serve static files from public folder
|
||||
app.use(express.static('../public'));
|
||||
|
||||
// Serve static files for the launcher
|
||||
app.get('/launcher/news', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, '../public/launcher/news/news-panel.html'));
|
||||
});
|
||||
|
||||
app.get('/launcher/agreement', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, '../public/launcher/news/agreement.html'));
|
||||
});
|
||||
|
||||
app.get('/favicon.ico', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, '../public/launcher/news/favicon.ico'));
|
||||
});
|
||||
|
||||
app.use('/launcher/news/images', express.static(path.join(__dirname, '../public/launcher/news/images')));
|
||||
app.use('/launcher/news', express.static(path.join(__dirname, '../public/launcher/news')));
|
||||
app.use('/launcher/patch', express.static(path.join(__dirname, '../public/launcher/patch')));
|
||||
|
||||
|
||||
// Set up error handling middleware
|
||||
app.use((err, req, res, next) => {
|
||||
if (env.LOG_LEVEL && env.LOG_LEVEL === 'error') {
|
||||
logger.error(err.stack);
|
||||
} else {
|
||||
logger.info(err.stack);
|
||||
}
|
||||
res.status(500).send('Something went wrong' + err.stack);
|
||||
});
|
||||
|
||||
// Start server
|
||||
const port = process.env.PORT || 3000;
|
||||
app.listen(port, '0.0.0.0', () => {
|
||||
logger.info(`API listening on *:${port}`);
|
||||
logger.info(`Auth API listening on 127.0.0.1:${authPort}`);
|
||||
logger.info(`Billing API listening on 127.0.0.1:${billingPort}`);
|
||||
});
|
||||
114
src/mailer/mailer.js
Normal file
114
src/mailer/mailer.js
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
const nodemailer = require('nodemailer');
|
||||
const handlebars = require('handlebars');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { mailerLogger } = require('../utils/logger');
|
||||
|
||||
// Load the email templates
|
||||
const emailTemplates = {
|
||||
confirmation: fs.readFileSync(path.join(__dirname, 'templates', 'confirmationTemplate.hbs'), 'utf-8'),
|
||||
verification: fs.readFileSync(path.join(__dirname, 'templates', 'verificationTemplate.hbs'), 'utf-8'),
|
||||
passwordReset: fs.readFileSync(path.join(__dirname, 'templates', 'passwordResetTemplate.hbs'), 'utf-8'),
|
||||
passwordChanged: fs.readFileSync(path.join(__dirname, 'templates', 'passwordChangedTemplate.hbs'), 'utf-8')
|
||||
};
|
||||
|
||||
// Compile the email templates
|
||||
const compiledTemplates = {
|
||||
confirmation: handlebars.compile(emailTemplates.confirmation),
|
||||
verification: handlebars.compile(emailTemplates.verification),
|
||||
passwordReset: handlebars.compile(emailTemplates.passwordReset),
|
||||
passwordChanged: handlebars.compile(emailTemplates.passwordChanged)
|
||||
};
|
||||
|
||||
// SMTP transport configuration
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: process.env.SMTP_HOST,
|
||||
port: process.env.SMTP_PORT,
|
||||
secure: process.env.SMTP_ENCRYPTION === 'ssl' || process.env.SMTP_ENCRYPTION === 'tls',
|
||||
auth: {
|
||||
user: process.env.SMTP_USERNAME,
|
||||
pass: process.env.SMTP_PASSWORD
|
||||
}
|
||||
});
|
||||
|
||||
function sendConfirmationEmail(email, windyCode) {
|
||||
const template = compiledTemplates.confirmation;
|
||||
const emailContent = template({ windyCode });
|
||||
|
||||
const mailOptions = {
|
||||
from: `"${process.env.SMTP_FROMNAME}" <${process.env.SMTP_USERNAME}>`,
|
||||
to: email,
|
||||
subject: '[Rusty Hearts] Account Creation Confirmation',
|
||||
html: emailContent
|
||||
};
|
||||
|
||||
transporter.sendMail(mailOptions, (error, info) => {
|
||||
if (error) {
|
||||
mailerLogger.error('[Mailer] Error sending confirmation email: ' + error.message);
|
||||
} else {
|
||||
mailerLogger.info('[Mailer] Confirmation email sent: ' + info.response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sendVerificationEmail(email, verificationCode) {
|
||||
const template = compiledTemplates.verification;
|
||||
const emailContent = template({ verificationCode });
|
||||
|
||||
const mailOptions = {
|
||||
from: `"${process.env.SMTP_FROMNAME}" <${process.env.SMTP_USERNAME}>`,
|
||||
to: email,
|
||||
subject: '[Rusty Hearts] Account Creation',
|
||||
html: emailContent
|
||||
};
|
||||
|
||||
transporter.sendMail(mailOptions, (error, info) => {
|
||||
if (error) {
|
||||
mailerLogger.error('[Mailer] Error sending verification email: ' + error.message);
|
||||
} else {
|
||||
mailerLogger.info('[Mailer] Verification email sent: ' + info.response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sendPasswordResetEmail(email, verificationCode) {
|
||||
const template = compiledTemplates.passwordReset;
|
||||
const emailContent = template({ verificationCode });
|
||||
|
||||
const mailOptions = {
|
||||
from: `"${process.env.SMTP_FROMNAME}" <${process.env.SMTP_USERNAME}>`,
|
||||
to: email,
|
||||
subject: '[Rusty Hearts] Password Reset Request',
|
||||
html: emailContent
|
||||
};
|
||||
|
||||
transporter.sendMail(mailOptions, (error, info) => {
|
||||
if (error) {
|
||||
mailerLogger.error('[Mailer] Error sending password reset email: ' + error.message);
|
||||
} else {
|
||||
mailerLogger.info('[Mailer] Password reset email sent: ' + info.response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sendPasswordChangedEmail(email, windyCode) {
|
||||
const template = compiledTemplates.passwordChanged;
|
||||
const emailContent = template({ windyCode });
|
||||
|
||||
const mailOptions = {
|
||||
from: `"${process.env.SMTP_FROMNAME}" <${process.env.SMTP_USERNAME}>`,
|
||||
to: email,
|
||||
subject: '[Rusty Hearts] Account Password Changed',
|
||||
html: emailContent
|
||||
};
|
||||
|
||||
transporter.sendMail(mailOptions, (error, info) => {
|
||||
if (error) {
|
||||
mailerLogger.error('[Mailer] Error sending password changed email: ' + error.message);
|
||||
} else {
|
||||
mailerLogger.info('[Mailer] Password changed email sent: ' + info.response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {sendConfirmationEmail, sendVerificationEmail, sendPasswordResetEmail, sendPasswordChangedEmail};
|
||||
14
src/mailer/templates/confirmationTemplate.hbs
Normal file
14
src/mailer/templates/confirmationTemplate.hbs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Welcome to Rusty Hearts!</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Welcome to Rusty Hearts</h1>
|
||||
<p>Dear {{windyCode}},</p>
|
||||
<p>Thank you for creating an account with Rusty Hearts! We are thrilled to have you as part of our community.</p>
|
||||
<p>You are now ready to login and start playing Rusty Hearts. As you embark on your journey, remember to have fun and enjoy the game!</p>
|
||||
<p>If you have any questions or need assistance with anything, please do not hesitate to contact our support team. We are always here to help you.</p>
|
||||
<p>Thank you again for choosing Rusty Hearts. We look forward to seeing you in the game!</p>
|
||||
<p>Best regards,<br>Rusty Hearts Team</p>
|
||||
</body>
|
||||
</html>
|
||||
16
src/mailer/templates/passwordChangedTemplate.hbs
Normal file
16
src/mailer/templates/passwordChangedTemplate.hbs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>[Rusty Hearts] Account Password Changed</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Hello, {{windyCode}}</p>
|
||||
<p>We're writing to let you know that the password for your Rusty Hearts account has been changed. If you made this change yourself, you can disregard this message.</p>
|
||||
<p>However, if you didn't change your password or if you're unsure if someone else has gained access to your account, we recommend taking immediate action to secure your account. Here are some steps you can take:</p>
|
||||
<ul>
|
||||
<li>Change your password again and make sure it's strong and unique</li>
|
||||
<li>Contact our support team if you need further assistance or if you believe your account has been compromised</li>
|
||||
</ul>
|
||||
<p>Best regards,<br>Rusty Hearts Team</p>
|
||||
</body>
|
||||
</html>
|
||||
17
src/mailer/templates/passwordResetTemplate.hbs
Normal file
17
src/mailer/templates/passwordResetTemplate.hbs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>[Rusty Hearts] Password Reset Request</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Hello {{windycode}},</p>
|
||||
<p>We received a request to reset your Rusty Hearts account password. To proceed with the password reset, please enter the verification code below:</p>
|
||||
<div style="background-color: #f2f2f2; border: 1px solid #000; padding: 10px;">
|
||||
{{verificationCode}}
|
||||
</div>
|
||||
<p>This code will expire in 10 minutes for security reasons. If you do not enter the code within this timeframe, you may need to request a new one.</p>
|
||||
<p>If you did not initiate this password reset or do not recognize this email, please disregard it and contact our support team immediately to protect your account.</p>
|
||||
<p>Thank you for playing Rusty Hearts!</p>
|
||||
<p>Best regards,<br>Rusty Hearts Team</p>
|
||||
</body>
|
||||
</html>
|
||||
17
src/mailer/templates/verificationTemplate.hbs
Normal file
17
src/mailer/templates/verificationTemplate.hbs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>[Rusty Hearts] Account Creation</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Hello,</p>
|
||||
<p>Thank you for registering your email address with your Rusty Hearts account. To complete the registration process, please enter the verification code below:</p>
|
||||
<div style="background-color: #f2f2f2; border: 1px solid #000; padding: 10px;">
|
||||
{{verificationCode}}
|
||||
</div>
|
||||
<p>This code will expire in 10 minutes for security reasons. If you do not enter the code within this timeframe, you may need to request a new one.</p>
|
||||
<p>If you did not initiate this registration or do not recognize this email, please disregard it and contact our support team immediately.</p>
|
||||
<p>Thank you for playing Rusty Hearts!</p>
|
||||
<p>Best regards,<br>Rusty Hearts Team</p>
|
||||
</body>
|
||||
</html>
|
||||
77
src/routes/auth.js
Normal file
77
src/routes/auth.js
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const bcrypt = require('bcrypt');
|
||||
const xml2js = require('xml2js');
|
||||
const parser = new xml2js.Parser();
|
||||
const sql = require('mssql');
|
||||
const router = express.Router();
|
||||
const { authLogger } = require('../utils/logger');
|
||||
|
||||
// Set up database connection
|
||||
const { connAccount } = require('../utils/dbConfig');
|
||||
|
||||
// Route for handling login requests
|
||||
router.post('/', bodyParser.text({
|
||||
type: '*/xml'
|
||||
}), async (req, res) => {
|
||||
try {
|
||||
const xml = req.body;
|
||||
const result = await parser.parseStringPromise(xml);
|
||||
const loginRequest = result['login-request'];
|
||||
const account = loginRequest.account[0];
|
||||
const password = loginRequest.password[0];
|
||||
const game = loginRequest.game[0];
|
||||
const ip = loginRequest.ip[0];
|
||||
|
||||
authLogger.info(`[Auth] Account [${account}] is trying to login from [${ip}]`);
|
||||
|
||||
// Create a connection pool for the database
|
||||
const pool = await connAccount;
|
||||
|
||||
// Get the account information from the database
|
||||
const {
|
||||
recordset
|
||||
} = await pool
|
||||
.request()
|
||||
.input('Identifier', sql.VarChar(50), account)
|
||||
.execute('GetAccount');
|
||||
|
||||
// Check if the account exists
|
||||
const row = recordset[0];
|
||||
if (!row || row.Result !== 'AccountExists') {
|
||||
authLogger.info(`[Auth] Account [${account}] login failed from [${ip}]`);
|
||||
return res.send('<status>failed</status>');
|
||||
}
|
||||
|
||||
// Verify the password using bcrypt
|
||||
const passwordMatch = await bcrypt.compare(password, row.AccountPwd);
|
||||
|
||||
// Authenticate the user and update the database
|
||||
const {
|
||||
recordset: authRecordset
|
||||
} = await pool
|
||||
.request()
|
||||
.input('Identifier', sql.VarChar(50), account)
|
||||
.input('password_verify_result', sql.Bit, passwordMatch ? 1 : 0)
|
||||
.input('LastLoginIP', sql.VarChar(50), ip)
|
||||
.execute('AuthenticateUser');
|
||||
|
||||
const authRow = authRecordset[0];
|
||||
if (!authRow || authRow.Result !== 'LoginSuccess') {
|
||||
authLogger.info(`[Auth] Account [${account}] login failed from [${ip}]`);
|
||||
return res.send('<status>failed</status>');
|
||||
}
|
||||
|
||||
// Send the authentication response
|
||||
const response = `<userid>${authRow.AuthID}</userid><user-type>F</user-type><status>success</status>`;
|
||||
res.set('Content-Type', 'text/xml; charset=utf-8');
|
||||
res.send(response);
|
||||
|
||||
authLogger.info(`[Auth] Account [${account}] successfully logged in from [${ip}]`);
|
||||
} catch (error) {
|
||||
authLogger.error('Error handling login request: ' + error.message);
|
||||
res.status(500).send('<status>failed</status>');
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
122
src/routes/billing.js
Normal file
122
src/routes/billing.js
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
const express = require('express');
|
||||
const bodyParser = require('body-parser');
|
||||
const xml2js = require('xml2js');
|
||||
const parser = new xml2js.Parser();
|
||||
const sql = require('mssql');
|
||||
const router = express.Router();
|
||||
const { billingLogger} = require('../utils/logger');;
|
||||
|
||||
// Set up database connection
|
||||
const { connAccount } = require('../utils/dbConfig');
|
||||
|
||||
// Route for handling billing requests
|
||||
router.post('/', bodyParser.text({
|
||||
type: '*/xml'
|
||||
}), async (req, res) => {
|
||||
try {
|
||||
const xml = req.body;
|
||||
const result = await parser.parseStringPromise(xml);
|
||||
const name = result['currency-request'] ? 'currency-request' : 'item-purchase-request';
|
||||
const request = result[name];
|
||||
const userid = request.userid[0];
|
||||
const server = request.server[0];
|
||||
|
||||
billingLogger.info(`[Billing] Received [${name}] from user [${userid}]`);
|
||||
|
||||
// Create a connection pool for the database
|
||||
const pool = await connAccount;
|
||||
|
||||
switch (name) {
|
||||
case 'currency-request':
|
||||
const {
|
||||
recordset
|
||||
} = await pool
|
||||
.request()
|
||||
.input('UserId', sql.VarChar(50), userid)
|
||||
.input('ServerId', sql.VarChar(50), server)
|
||||
.execute('GetCurrency');
|
||||
|
||||
const row = recordset[0];
|
||||
|
||||
if (row && row.Result === 'Success') {
|
||||
const response = `<result><balance>${row.Zen}</balance></result>`;
|
||||
res.set('Content-Type', 'text/xml; charset=utf-8');
|
||||
res.send(response);
|
||||
} else {
|
||||
res.send('<status>failed</status>');
|
||||
return res.status(400).send(row.Result);
|
||||
}
|
||||
break;
|
||||
case 'item-purchase-request':
|
||||
const charid = request.charid[0];
|
||||
const uniqueid = request.uniqueid[0];
|
||||
const amount = request.amount[0];
|
||||
const itemid = request.itemid[0];
|
||||
const itemcount = request.count[0];
|
||||
|
||||
const {
|
||||
recordset: currencyRecordset
|
||||
} = await pool
|
||||
.request()
|
||||
.input('UserId', sql.VarChar(50), userid)
|
||||
.input('ServerId', sql.VarChar(50), server)
|
||||
.execute('GetCurrency');
|
||||
|
||||
const currencyRow = currencyRecordset[0];
|
||||
|
||||
if (currencyRow && currencyRow.Result === 'Success') {
|
||||
const balance = currencyRow.Zen;
|
||||
|
||||
if (amount > 0) {
|
||||
if (amount > balance) {
|
||||
res.send('<status>failed</status>');
|
||||
billingLogger.info(`[Billing] Item purchase with id [${uniqueid}] from user [${userid}] failed. Not enough Zen [${balance}]. charid: [${charid}] itemid: [${itemid}] itemcount: [${itemcount}] price: [${amount}]`);
|
||||
} else {
|
||||
const newbalance = balance - amount;
|
||||
|
||||
await pool
|
||||
.request()
|
||||
.input('UserId', sql.VarChar(50), userid)
|
||||
.input('ServerId', sql.VarChar(50), server)
|
||||
.input('NewBalance', sql.BigInt, newbalance)
|
||||
.execute('SetCurrency');
|
||||
|
||||
await pool
|
||||
.request()
|
||||
.input('userid', sql.VarChar(50), userid)
|
||||
.input('charid', sql.VarChar(50), charid)
|
||||
.input('uniqueid', sql.VarChar(50), uniqueid)
|
||||
.input('amount', sql.BigInt, amount)
|
||||
.input('itemid', sql.VarChar(50), itemid)
|
||||
.input('itemcount', sql.Int, itemcount)
|
||||
.execute('SetBillingLog');
|
||||
|
||||
billingLogger.info(`[Billing] Item purchase with id [${uniqueid}] from user [${userid}] success. charid: [${charid}] itemid: [${itemid}] itemcount: [${itemcount}] price: [${amount}]`);
|
||||
billingLogger.info(`[Billing] Item purchase from user [${userid}] success. New zen balance: [${newbalance}]`);
|
||||
|
||||
const response = `<result><status>success</status><new-balance>${newbalance}</new-balance></result>`;
|
||||
res.set('Content-Type', 'text/xml; charset=utf-8');
|
||||
res.send(response);
|
||||
}
|
||||
} else {
|
||||
const response = `<result><balance>${currencyRow.Zen}</balance></result>`;
|
||||
res.set('Content-Type', 'text/xml; charset=utf-8');
|
||||
res.send(response);
|
||||
}
|
||||
} else {
|
||||
res.send('<status>failed</status>');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
res.send('<status>failed</status>');
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
billingLogger.error(`[Billing] Error handling request: $ {
|
||||
error.message
|
||||
}`);
|
||||
res.status(500).send('<status>failed</status>');
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
54
src/routes/gateway.js
Normal file
54
src/routes/gateway.js
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const net = require('net');
|
||||
|
||||
// Define the gateway route
|
||||
router.get('/', (req, res) => {
|
||||
const ip = process.env.GATESERVER_IP;
|
||||
const port = process.env.GATESERVER_PORT || '50001';
|
||||
|
||||
// Generate the XML content with the IP and port values
|
||||
const xml = `<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<network>
|
||||
<gateserver ip="${ip}" port="${port}" />
|
||||
</network>`;
|
||||
|
||||
res.set('Content-Type', 'application/xml');
|
||||
|
||||
res.send(xml);
|
||||
});
|
||||
|
||||
// Define the gateway info route
|
||||
router.get('/info', (req, res) => {
|
||||
const gatewayRoute = `1|${req.protocol}://${req.headers.host}/serverApi/gateway|${req.protocol}://${req.headers.host}/serverApi/gateway|`;
|
||||
res.send(gatewayRoute);
|
||||
});
|
||||
|
||||
// Define the gateway status route
|
||||
router.get('/status', async (req, res) => {
|
||||
const ip = process.env.GATESERVER_IP;
|
||||
const port = process.env.GATESERVER_PORT || '50001';
|
||||
|
||||
const timeout = 2000;
|
||||
|
||||
// Create a new socket and connect to the gateserver
|
||||
const socket = new net.Socket();
|
||||
socket.setTimeout(timeout);
|
||||
socket.connect(port, ip);
|
||||
|
||||
// Handle the socket events to check the connection status
|
||||
socket.on('connect', () => {
|
||||
res.status(200).json({ status: 'online' });
|
||||
socket.destroy();
|
||||
});
|
||||
socket.on('timeout', () => {
|
||||
res.status(408).json({ status: 'offline' });
|
||||
socket.destroy();
|
||||
});
|
||||
socket.on('error', () => {
|
||||
res.status(503).json({ status: 'offline' });
|
||||
socket.destroy();
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
108
src/routes/launcher/changePassword.js
Normal file
108
src/routes/launcher/changePassword.js
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
const sql = require('mssql');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const bcrypt = require('bcrypt');
|
||||
const crypto = require('crypto');
|
||||
const { logger, accountLogger } = require('../../utils/logger');
|
||||
const { sendPasswordChangedEmail } = require('../../mailer/mailer');
|
||||
const Joi = require('joi');
|
||||
|
||||
// Set up database connection
|
||||
const { connAccount } = require('../../utils/dbConfig');
|
||||
|
||||
// Joi schema for request body validation
|
||||
const schema = Joi.object({
|
||||
email: Joi.string().email().required(),
|
||||
password: Joi.string().required(),
|
||||
verification_code: Joi.string().pattern(new RegExp('^[0-9]+$')).required()
|
||||
});
|
||||
|
||||
// Route for registering an account
|
||||
router.post('/', async (req, res) => {
|
||||
try {
|
||||
// Validate request body
|
||||
const { error, value } = schema.validate(req.body);
|
||||
if (error) {
|
||||
return res.status(400).send(error.details[0].message);
|
||||
}
|
||||
|
||||
const email = value.email;
|
||||
const password = value.password;
|
||||
const verificationCode = value.verification_code;
|
||||
|
||||
// Use a prepared statement to get the verification code
|
||||
const pool = await connAccount;
|
||||
const request = pool.request();
|
||||
request.input('Email', sql.VarChar, email);
|
||||
request.input('VerificationCode', sql.VarChar, verificationCode);
|
||||
request.input('VerificationCodeType', sql.VarChar, 'Password');
|
||||
const inputResult = await request.execute('GetVerificationCode');
|
||||
const inputRow = inputResult.recordset[0];
|
||||
|
||||
if (inputRow && inputRow.Result === 'ValidVerificationCode') {
|
||||
|
||||
// Use a prepared statement to retrieve the account information
|
||||
const pool = await connAccount;
|
||||
const request = pool.request();
|
||||
request.input('Identifier', sql.VarChar, email);
|
||||
const getResult = await request.execute('GetAccount');
|
||||
const getRow = getResult.recordset[0];
|
||||
|
||||
if (getRow && getRow.Result === 'AccountExists') {
|
||||
const windyCode = getRow.WindyCode
|
||||
const hash = getRow.AccountPwd;
|
||||
|
||||
// Verify the password
|
||||
const md5_password = crypto
|
||||
.createHash('md5')
|
||||
.update(windyCode + password)
|
||||
.digest('hex');
|
||||
const password_verify_result = await bcrypt.compare(
|
||||
md5_password,
|
||||
hash
|
||||
);
|
||||
if (password_verify_result === true) {
|
||||
return res.status(400).send('SamePassword');
|
||||
} else {
|
||||
|
||||
const passwordHash = await bcrypt.hash(md5_password, 10);
|
||||
|
||||
// Use a prepared statement to update the password
|
||||
const pool = await connAccount;
|
||||
const request = pool.request();
|
||||
request.input('Email', sql.VarChar, email);
|
||||
request.input('AccountPwd', sql.VarChar, passwordHash);
|
||||
const updateResult = await request.execute('UpdateAccountPassword');
|
||||
const updateRow = updateResult.recordset[0];
|
||||
|
||||
if (updateRow && updateRow.Result === 'PasswordChanged') {
|
||||
accountLogger.info(`[Account] Password for [${windyCode}] changed successfully`);
|
||||
sendPasswordChangedEmail(email, windyCode);
|
||||
|
||||
const pool = await connAccount;
|
||||
const request = pool.request();
|
||||
request.input('Email', sql.VarChar, email);
|
||||
const clearResult = await request.execute('ClearVerificationCode');
|
||||
const clearRow = clearResult.recordset[0];
|
||||
|
||||
return res.status(200).send('PasswordChanged');
|
||||
} else {
|
||||
accountLogger.info(`[Account] Password change for [${windyCode}] failed: ${row.Result}`);
|
||||
return res.status(400).send(updateRow.Result);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
return res.status(400).send(getRow.Result);
|
||||
}
|
||||
} else {
|
||||
return res.status(400).send(inputRow.Result);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
logger.error('[Account] Database query failed: ' + error.message);
|
||||
return res.status(500).send('[Account] Database query failed: ' + error.message);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
53
src/routes/launcher/codeVerification.js
Normal file
53
src/routes/launcher/codeVerification.js
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
const sql = require('mssql');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { logger } = require('../../utils/logger');
|
||||
const Joi = require('joi');
|
||||
|
||||
// Set up database connection
|
||||
const { connAccount } = require('../../utils/dbConfig');
|
||||
|
||||
// Joi schema for request body validation
|
||||
const schema = Joi.object({
|
||||
email: Joi.string().email().required(),
|
||||
verification_code_type: Joi.string().required(),
|
||||
verification_code: Joi.string().pattern(new RegExp('^[0-9]+$')).required()
|
||||
});
|
||||
|
||||
// Route for registering an account
|
||||
router.post('/', async (req, res) => {
|
||||
try {
|
||||
// Validate request body
|
||||
const { error, value } = schema.validate(req.body);
|
||||
if (error) {
|
||||
return res.status(400).send(error.details[0].message);
|
||||
}
|
||||
const email = req.body.email;
|
||||
const verificationCode = req.body.verification_code;
|
||||
const verificationCodeType = req.body.verification_code_type;
|
||||
|
||||
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
||||
return res.status(400).send('InvalidEmailFormat');
|
||||
}
|
||||
|
||||
if (!/^\d+$/.test(verificationCode)) {
|
||||
return res.status(400).send('InvalidVerificationCodeFormat');
|
||||
}
|
||||
|
||||
// Use a prepared statement to check verification code
|
||||
const pool = await connAccount;
|
||||
const request = pool.request();
|
||||
request.input('Email', sql.VarChar, email);
|
||||
request.input('VerificationCode', sql.VarChar, verificationCode);
|
||||
request.input('VerificationCodeType', sql.VarChar, verificationCodeType);
|
||||
const result = await request.execute('GetVerificationCode');
|
||||
const row = result.recordset[0];
|
||||
|
||||
return res.status(200).send(row.Result);
|
||||
} catch (error) {
|
||||
logger.error('Database query failed: ' + error.message);
|
||||
return res.status(500).send('Database query failed: ' + error.message);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
41
src/routes/launcher/launcherUpdater.js
Normal file
41
src/routes/launcher/launcherUpdater.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
const express = require('express');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { logger } = require('../../utils/logger');
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// Endpoint to get the launcher version from the launcher_info.ini file
|
||||
router.get('/getLauncherVersion', (req, res) => {
|
||||
const launcherInfoPath = path.join(__dirname, '..', '..', '..', 'public', 'launcher', 'launcher_update', 'launcher_info.ini');
|
||||
fs.readFile(launcherInfoPath, 'utf8', (err, data) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return res.status(500).send('Error reading launcher_info.ini');
|
||||
}
|
||||
const versionRegex = /version=(.*)/i;
|
||||
const match = data.match(versionRegex);
|
||||
if (match) {
|
||||
const launcherVersion = match[1];
|
||||
return res.json({ version: launcherVersion });
|
||||
}
|
||||
return res.status(500).send('Invalid launcher_info.ini format');
|
||||
});
|
||||
});
|
||||
|
||||
// Endpoint to download the new launcher version from the launcher_update folder
|
||||
router.post('/updateLauncherVersion', (req, res) => {
|
||||
const launcherUpdatePath = path.join(__dirname, '..', '..', '..', 'public', 'launcher', 'launcher_update');
|
||||
const version = req.body.version;
|
||||
if (!req.body.version) {
|
||||
return res.status(400).send('Missing version parameter');
|
||||
}
|
||||
const file = path.join(launcherUpdatePath, `launcher_${version}.zip`);
|
||||
if (!fs.existsSync(file)) {
|
||||
return res.status(404).send(`File ${file} not found`);
|
||||
logger.error(`[Launcher Updater] File ${file} not found`);
|
||||
}
|
||||
res.download(file);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
100
src/routes/launcher/login.js
Normal file
100
src/routes/launcher/login.js
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
const sql = require('mssql');
|
||||
const bcrypt = require('bcrypt');
|
||||
const crypto = require('crypto');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { logger, accountLogger } = require('../../utils/logger');
|
||||
const Joi = require('joi');
|
||||
|
||||
// Set up database connection
|
||||
const { connAccount } = require('../../utils/dbConfig');
|
||||
|
||||
// Define the validation schema for the request body
|
||||
const schema = Joi.object({
|
||||
account: Joi.string().required(),
|
||||
password: Joi.string().required(),
|
||||
});
|
||||
|
||||
router.post('/', async (req, res) => {
|
||||
try {
|
||||
// Validate the request body against the schema
|
||||
const { error, value } = schema.validate(req.body);
|
||||
if (error) {
|
||||
return res.status(400).send(error.details[0].message);
|
||||
}
|
||||
|
||||
const account = value.account;
|
||||
const password = value.password;
|
||||
const userIp = req.ip;
|
||||
|
||||
// Check the format of the account identifier
|
||||
if (
|
||||
!/^[A-Za-z0-9_-]{6,50}$/.test(account) &&
|
||||
!/^[\w\d._%+-]+@[\w\d.-]+\.[\w]{2,}$/i.test(account)
|
||||
) {
|
||||
return res.status(400).json({ Result: 'InvalidUsernameFormat' });
|
||||
}
|
||||
|
||||
// Use a prepared statement to retrieve the account information
|
||||
const pool = await connAccount;
|
||||
const request = pool.request();
|
||||
request.input('Identifier', sql.VarChar, account);
|
||||
const result = await request.execute('GetAccount');
|
||||
const row = result.recordset[0];
|
||||
|
||||
if (row && row.Result === 'AccountExists') {
|
||||
const windyCode = row.WindyCode;
|
||||
const hash = row.AccountPwd;
|
||||
|
||||
// Verify the password
|
||||
const md5_password = crypto
|
||||
.createHash('md5')
|
||||
.update(windyCode + password)
|
||||
.digest('hex');
|
||||
const password_verify_result = await bcrypt.compare(
|
||||
md5_password,
|
||||
hash
|
||||
);
|
||||
|
||||
const authRequest = pool.request();
|
||||
authRequest.input('Identifier', sql.VarChar, account);
|
||||
authRequest.input(
|
||||
'password_verify_result',
|
||||
sql.Bit,
|
||||
password_verify_result
|
||||
);
|
||||
authRequest.input('LastLoginIP', sql.VarChar, userIp);
|
||||
const authResult = await authRequest.execute('AuthenticateUser');
|
||||
const authRow = authResult.recordset[0];
|
||||
|
||||
if (authRow && authRow.Result === 'LoginSuccess') {
|
||||
accountLogger.info(
|
||||
`[Account] Launcher Login: Account [${windyCode}] successfully logged in from [${userIp}]`
|
||||
);
|
||||
return res.status(200).json({
|
||||
Result: authRow.Result,
|
||||
Token: authRow.Token,
|
||||
WindyCode: authRow.WindyCode,
|
||||
});
|
||||
} else {
|
||||
accountLogger.info(
|
||||
`[Account] Launcher Login: Account [${windyCode}] login failed: ${authRow.Result} `
|
||||
);
|
||||
return res.status(400).json({
|
||||
Result: authRow.Result,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return res.status(400).json({ Result: 'AccountNotFound' });
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
'[Account] Launcher Login: Database query failed: ' + error.message
|
||||
);
|
||||
return res
|
||||
.status(500)
|
||||
.send('Database query failed: ' + error.message);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
74
src/routes/launcher/passwordResetEmail.js
Normal file
74
src/routes/launcher/passwordResetEmail.js
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
const sql = require('mssql');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { logger, accountLogger } = require('../../utils/logger');
|
||||
const { sendPasswordResetEmail } = require('../../mailer/mailer');
|
||||
const Joi = require('joi');
|
||||
|
||||
// Set up database connection
|
||||
const { connAccount } = require('../../utils/dbConfig');
|
||||
|
||||
// Joi schema for request body validation
|
||||
const schema = Joi.object({
|
||||
email: Joi.string().email().required()
|
||||
});
|
||||
|
||||
// Route for registering an account
|
||||
router.post('/', async (req, res) => {
|
||||
try {
|
||||
// Validate request body
|
||||
const { error, value } = schema.validate(req.body);
|
||||
if (error) {
|
||||
return res.status(400).send(error.details[0].message);
|
||||
}
|
||||
const email = req.body.email;
|
||||
|
||||
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
||||
logger.info('Invalid email format');
|
||||
return res.status(400).send('InvalidEmailFormat');
|
||||
}
|
||||
|
||||
// Use a prepared statement to retrieve the account information
|
||||
const pool = await connAccount;
|
||||
const request = pool.request();
|
||||
request.input('Identifier', sql.VarChar, email);
|
||||
const result = await request.execute('GetAccount');
|
||||
const row = result.recordset[0];
|
||||
|
||||
if (row && row.Result === 'AccountExists') {
|
||||
const emailAdress = row.Email;
|
||||
const windycode = row.WindyCode;
|
||||
const verificationCode = Math.floor(10000 + Math.random() * 90000).toString();
|
||||
const expirationTime = new Date(Date.now() + 600000).toISOString(); // 10 minutes from now
|
||||
|
||||
// Prepare the second statement to insert the verification code information
|
||||
const insertRequest = pool.request();
|
||||
insertRequest.input('Email', sql.VarChar, email);
|
||||
insertRequest.input('VerificationCode', sql.VarChar, verificationCode);
|
||||
insertRequest.input('ExpirationTime', sql.DateTime, expirationTime);
|
||||
const insertResult = await insertRequest.execute('SetPasswordVerificationCode');
|
||||
const insertRow = insertResult.recordset[0];
|
||||
|
||||
if (insertRow && insertRow.Result === 'Success') {
|
||||
|
||||
// Send verification code email
|
||||
sendPasswordResetEmail(email, verificationCode);
|
||||
|
||||
return res.status(200).send('EmailSent');
|
||||
}
|
||||
else {
|
||||
accountLogger.info(`[Account] Failed to insert verification code for email: ${email}`);
|
||||
return res.status(500).send(insertRow.Result);
|
||||
}
|
||||
} else if (row && row.Result === 'AccountNotFound') {
|
||||
return res.status(400).send('AccountNotFound');
|
||||
} else {
|
||||
return res.status(500).send(row.Result);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('[Account] Database query failed: ' + error.message);
|
||||
return res.status(500).send('Database query failed: ' + error.message);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
67
src/routes/launcher/register.js
Normal file
67
src/routes/launcher/register.js
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
const sql = require('mssql');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const bcrypt = require('bcrypt');
|
||||
const crypto = require('crypto');
|
||||
const { logger, accountLogger } = require('../../utils/logger');
|
||||
const { sendConfirmationEmail } = require('../../mailer/mailer');
|
||||
const Joi = require('joi');
|
||||
|
||||
// Set up database connection
|
||||
const { connAccount } = require('../../utils/dbConfig');
|
||||
|
||||
// Joi schema for validating request data
|
||||
const schema = Joi.object({
|
||||
windyCode: Joi.string().alphanum().min(1).max(16).required(),
|
||||
email: Joi.string().email().required(),
|
||||
password: Joi.string().min(6).required(),
|
||||
});
|
||||
|
||||
// Route for registering an account
|
||||
router.post('/', async (req, res) => {
|
||||
try {
|
||||
const { error, value } = schema.validate(req.body);
|
||||
if (error) {
|
||||
return res.status(400).send(error.details[0].message);
|
||||
}
|
||||
|
||||
const windyCode = value.windyCode;
|
||||
const email = value.email;
|
||||
const password = value.password;
|
||||
const userIp = req.ip;
|
||||
|
||||
const md5_password = crypto.createHash('md5').update(windyCode + password).digest('hex'); // Generate MD5 hash
|
||||
|
||||
const passwordHash = await bcrypt.hash(md5_password, 10);
|
||||
|
||||
// Use a prepared statement to create the account
|
||||
const pool = await connAccount;
|
||||
const request = pool.request();
|
||||
request.input('WindyCode', sql.VarChar, windyCode);
|
||||
request.input('AccountPwd', sql.VarChar, passwordHash);
|
||||
request.input('Email', sql.VarChar, email);
|
||||
request.input('RegisterIP', sql.VarChar, userIp);
|
||||
const result = await request.execute('CreateAccount');
|
||||
const row = result.recordset[0];
|
||||
|
||||
if (row && row.Result === 'AccountCreated') {
|
||||
accountLogger.info(`[Account] Account [${windyCode}] created successfully`);
|
||||
sendConfirmationEmail(email, windyCode);
|
||||
|
||||
const clearRequest = pool.request();
|
||||
clearRequest.input('Email', sql.VarChar, email);
|
||||
const clearResult = await clearRequest.execute('ClearVerificationCode');
|
||||
const clearRow = clearResult.recordset[0];
|
||||
|
||||
return res.status(200).send('Success');
|
||||
} else {
|
||||
accountLogger.info(`[Account] Account [${windyCode}] creation failed: ${row.Result}`);
|
||||
return res.status(400).send(row.Result);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('[Account] Database query failed: ' + error.message);
|
||||
return res.status(500).send('Database query failed: ' + error.message);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
68
src/routes/launcher/verificationEmail.js
Normal file
68
src/routes/launcher/verificationEmail.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// Load environment variables
|
||||
const env = require('../../utils/env');
|
||||
|
||||
const sql = require('mssql');
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { logger } = require('../../utils/logger');
|
||||
const { sendVerificationEmail } = require('../../mailer/mailer');
|
||||
const Joi = require('joi');
|
||||
|
||||
// Set up database connection
|
||||
const { connAccount } = require('../../utils/dbConfig');
|
||||
|
||||
// Joi schema for request body validation
|
||||
const schema = Joi.object({
|
||||
email: Joi.string().email().required()
|
||||
});
|
||||
|
||||
// Route for registering an account
|
||||
router.post('/', async (req, res) => {
|
||||
try {
|
||||
// Validate request body
|
||||
const { error, value } = schema.validate(req.body);
|
||||
if (error) {
|
||||
return res.status(400).send(error.details[0].message);
|
||||
}
|
||||
const email = req.body.email;
|
||||
|
||||
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
|
||||
return res.status(400).send('InvalidEmailFormat');
|
||||
}
|
||||
|
||||
// Use a prepared statement to retrieve the account information
|
||||
const pool = await connAccount;
|
||||
const request = pool.request();
|
||||
request.input('Identifier', sql.VarChar, email);
|
||||
const result = await request.execute('GetAccount');
|
||||
const row = result.recordset[0];
|
||||
|
||||
if (row && row.Result === 'AccountNotFound') {
|
||||
const verificationCode = Math.floor(10000 + Math.random() * 90000).toString();
|
||||
const timeZone = process.env.TZ;
|
||||
|
||||
// Set the expiration time 10 minutes from now in the specified timezone
|
||||
const expirationTime = new Date(Date.now() + 600000).toLocaleString('en-US', { timeZone });
|
||||
|
||||
// Prepare the second statement to insert the verification code information
|
||||
const insertRequest = pool.request();
|
||||
insertRequest.input('Email', sql.VarChar, email);
|
||||
insertRequest.input('VerificationCode', sql.VarChar, verificationCode);
|
||||
insertRequest.input('ExpirationTime', sql.DateTime, expirationTime);
|
||||
const insertResult = await insertRequest.execute('SetAccountVerificationCode');
|
||||
const insertRow = insertResult.recordset[0];
|
||||
|
||||
// Send verification code email
|
||||
sendVerificationEmail(email, verificationCode);
|
||||
|
||||
return res.status(200).send('EmailSent');
|
||||
} else {
|
||||
return res.status(400).send(row.Result);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('[Account] Database query failed: ' + error.message);
|
||||
return res.status(500).send('Database query failed: ' + error.message);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
21
src/utils/dbConfig.js
Normal file
21
src/utils/dbConfig.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
const sql = require('mssql');
|
||||
const env = require('./env');
|
||||
const { logger } = require('../utils/logger');
|
||||
|
||||
const dbConfig = {
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
server: process.env.DB_SERVER,
|
||||
database: process.env.DB_DATABASE,
|
||||
options: {
|
||||
encrypt: process.env.DB_ENCRYPT === 'true'
|
||||
}
|
||||
};
|
||||
|
||||
const connAccount = new sql.ConnectionPool(dbConfig);
|
||||
connAccount.connect();
|
||||
logger.info(`Database: Connected.`);
|
||||
|
||||
module.exports = {
|
||||
connAccount
|
||||
};
|
||||
6
src/utils/env.js
Normal file
6
src/utils/env.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
require('dotenv').config();
|
||||
|
||||
// Access environment variables with a function
|
||||
module.exports = {
|
||||
get: (key) => process.env[key],
|
||||
};
|
||||
144
src/utils/logger.js
Normal file
144
src/utils/logger.js
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const util = require("util");
|
||||
const winston = require("winston");
|
||||
|
||||
const logsDirectory = 'logs';
|
||||
|
||||
if (!fs.existsSync(logsDirectory)) {
|
||||
fs.mkdirSync(logsDirectory);
|
||||
}
|
||||
|
||||
const authLogger = winston.createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
||||
winston.format.printf(info => `${info.level}: ${info.message} [${info.timestamp}] `)
|
||||
),
|
||||
transports: [
|
||||
new winston.transports.File({
|
||||
filename: `logs/auth-${new Date().toISOString().slice(0, 10)}.log`,
|
||||
level: 'info',
|
||||
filter: (log) => log.message.includes('[Auth]')
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
if (process.env.LOG_AUTH_CONSOLE === 'true') {
|
||||
authLogger.add(new winston.transports.Console({
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.simple(),
|
||||
winston.format.printf(info => `${info.level}: ${info.message} [${info.timestamp}]`)
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
const billingLogger = winston.createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
||||
winston.format.printf(info => `${info.level}: ${info.message} [${info.timestamp}] `)
|
||||
),
|
||||
transports: [
|
||||
new winston.transports.File({
|
||||
filename: `logs/billing-${new Date().toISOString().slice(0, 10)}.log`,
|
||||
level: 'info',
|
||||
filter: (log) => log.message.includes('[Billing]')
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
if (process.env.LOG_BILLING_CONSOLE === 'true') {
|
||||
billingLogger.add(new winston.transports.Console({
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.simple(),
|
||||
winston.format.printf(info => `${info.level}: ${info.message} [${info.timestamp}]`)
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
const mailerLogger = winston.createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
||||
winston.format.printf(info => `${info.level}: ${info.message} [${info.timestamp}] `)
|
||||
),
|
||||
transports: [
|
||||
new winston.transports.File({
|
||||
filename: `logs/mailer-${new Date().toISOString().slice(0, 10)}.log`,
|
||||
level: 'info',
|
||||
filter: (log) => log.message.includes('[Mailer]')
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
if (process.env.LOG_MAILER_CONSOLE === 'true') {
|
||||
mailerLogger.add(new winston.transports.Console({
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.simple(),
|
||||
winston.format.printf(info => `${info.level}: ${info.message} [${info.timestamp}]`)
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
const accountLogger = winston.createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
||||
winston.format.printf(info => `${info.level}: ${info.message} [${info.timestamp}] `)
|
||||
),
|
||||
transports: [
|
||||
new winston.transports.File({
|
||||
filename: `logs/account-${new Date().toISOString().slice(0, 10)}.log`,
|
||||
level: 'info',
|
||||
filter: (log) => log.message.includes('[Account]')
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
if (process.env.LOG_ACCOUNT_CONSOLE === 'true') {
|
||||
accountLogger.add(new winston.transports.Console({
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.simple(),
|
||||
winston.format.printf(info => `${info.level}: ${info.message} [${info.timestamp}]`)
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
const logger = winston.createLogger({
|
||||
level: 'info',
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
|
||||
winston.format.printf(info => `${info.level}: ${info.message} [${info.timestamp}] `)
|
||||
),
|
||||
transports: [
|
||||
new winston.transports.Console({
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.simple(),
|
||||
winston.format.printf(info => `${info.level}: ${info.message} [${info.timestamp}]`)
|
||||
)
|
||||
}),
|
||||
new winston.transports.File({
|
||||
filename: `logs/api-${new Date().toISOString().slice(0, 10)}.log`,
|
||||
level: 'info'
|
||||
}),
|
||||
new winston.transports.File({
|
||||
filename: `logs/error-${new Date().toISOString().slice(0, 10)}.log`,
|
||||
level: 'error'
|
||||
})
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
module.exports = {
|
||||
authLogger,
|
||||
billingLogger,
|
||||
mailerLogger,
|
||||
accountLogger,
|
||||
logger
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue