sequelize-game-bank 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +44 -0
  3. package/database/models/Account.js +3 -5
  4. package/database/models/Credit.js +4 -6
  5. package/database/models/Transaction.js +4 -5
  6. package/database/models/User.js +8 -10
  7. package/database/services/account/add-manny.js +4 -7
  8. package/database/services/account/change-pincode.js +3 -7
  9. package/database/services/account/change-status.js +3 -2
  10. package/database/services/account/create-credit.js +50 -100
  11. package/database/services/account/create.js +4 -7
  12. package/database/services/account/delete.js +2 -1
  13. package/database/services/account/find-manny.js +1 -3
  14. package/database/services/account/logs.js +6 -12
  15. package/database/services/account/remove-manny.js +4 -6
  16. package/database/services/account/transfer.js +44 -41
  17. package/database/services/bot/bot.js +5 -20
  18. package/database/services/bot/cron-schedule.js +123 -0
  19. package/database/services/bot/generators/register-bot.html +1 -1
  20. package/database/services/bot/generators/register-bot.txt +2 -2
  21. package/database/services/bot/write.js +3 -12
  22. package/database/services/user/change-avatar.js +1 -5
  23. package/database/services/user/change-gmail.js +1 -3
  24. package/database/services/user/change-password.js +3 -4
  25. package/database/services/user/create.js +3 -10
  26. package/database/services/user/delete.js +3 -4
  27. package/database/services/user/disable-2FA.js +5 -7
  28. package/database/services/user/enable-2FA.js +4 -6
  29. package/database/services/user/login.js +6 -17
  30. package/database/services/user/math-manny.js +3 -3
  31. package/index.js +27 -48
  32. package/package.json +21 -5
  33. package/public/credit.html +26 -0
  34. package/public/js/js.js +160 -26
  35. package/public/transfer.html +41 -39
  36. package/public/uploads/avatars/default.png +0 -0
  37. package/server/middleware/auth.js +1 -6
  38. package/server/server.js +8 -25
  39. package/src/logo/icon.png +0 -0
  40. package/.env +0 -114
  41. package/database/citybank.db +0 -0
  42. package/database/config/init-db.js +0 -33
  43. package/logs/errors.log +0 -14
  44. package/public/uploads/avatars/Pavel_1790269874496.png +0 -0
  45. package/public/uploads/avatars/Pavel_1790275457821.png +0 -0
  46. package/public/uploads/avatars/Pavel_1790867570006.png +0 -0
  47. package/public/uploads/avatars/Romanenko_1790270954677.png +0 -0
  48. package/public/uploads/avatars/root_1790275537324.png +0 -0
  49. package/public/uploads/avatars/root_1790275537381.png +0 -0
  50. package/public/uploads/avatars/root_1790349234549.png +0 -0
  51. package/public/uploads/avatars/root_1790519734671.png +0 -0
  52. package/public/uploads/avatars/root_1790879784620.png +0 -0
  53. package/public/uploads/avatars/root_1790879790948.png +0 -0
  54. package/public/uploads/avatars/root_1790879796755.png +0 -0
  55. package/public/uploads/avatars/root_1790962800544.png +0 -0
  56. package/public/uploads/avatars/root_1791009911239.png +0 -0
  57. package/test.js +0 -20
@@ -1,38 +1,23 @@
1
- // database/services/bot/bot.js
2
1
  const fs = require('fs').promises;
3
2
  const path = require('path');
4
-
5
- /**
6
- * Вспомогательный метод для асинхронного рендеринга и подстановки данных
7
- */
3
+ const logger = require("custom-color-logs").print;
8
4
  async function renderTemplate(templateName, ext, vars) {
9
5
  try {
10
- // 🔑 СТРОГО ВЫЧИСЛЯЕМ АБСОЛЮТНЫЙ ПУТЬ к папке generators
11
6
  const filePath = path.resolve(__dirname, 'generators', `${templateName}.${ext}`);
12
-
13
- // Читаем файл с диска
14
7
  let data = await fs.readFile(filePath, 'utf-8');
15
-
16
- // Подставляем переменные
17
8
  for (const [key, value] of Object.entries(vars)) {
18
9
  data = data.replace(new RegExp(`{${key}}`, 'g'), value);
19
10
  }
20
11
  return data;
21
12
  } catch (err) {
22
- console.error(`[Bot Render Error] Не найден файл ${templateName}.${ext}:`, err.message);
23
- return ""; // Возвращаем пустую строку вместо падения или перехвата статики
13
+ console.log(logger.NodemailerError(`[Bot Render Error] Не найден файл ${templateName}.${ext}:`, err.message))
14
+ return "";
24
15
  }
25
16
  }
26
-
27
- /**
28
- * Главный движок компиляции сообщений бота
29
- */
30
17
  async function sendBotNotification(templateName, variables) {
31
18
  const txtContent = await renderTemplate(templateName, 'txt', variables);
32
19
  const htmlContent = await renderTemplate(templateName, 'html', variables);
33
-
34
- console.log(`\n🤖 [City-Bank Bot Engine]: Сгенерировано событие уведомления [${templateName}]`);
20
+ console.log(logger.NodemailerInfo(`Сгенерировано событие уведомления [${templateName}]`))
35
21
  return { txt: txtContent, html: htmlContent };
36
22
  }
37
-
38
- module.exports = { sendBotNotification };
23
+ module.exports = { sendBotNotification };
@@ -0,0 +1,123 @@
1
+ const cron = require('node-cron');
2
+ const nodemailer = require('nodemailer');
3
+ const { Op } = require('sequelize');
4
+ const path = require("path");
5
+ const Account = require(path.join(__dirname, '..', '..', 'models', 'Account'));
6
+ const Credit = require(path.join(__dirname, '..', '..', 'models', 'Credit'));
7
+ const User = require(path.join(__dirname, '..', '..', 'models', 'User'));
8
+ const sequelize = require(path.join(__dirname, '..', '..', 'config', 'init-db'));
9
+ const logger = require("custom-color-logs").print;
10
+ const transporter = nodemailer.createTransport({
11
+ service: 'gmail',
12
+ auth: {
13
+ user: process.env.GMAIL,
14
+ pass: process.env.GOOGLE_APP_PASSWORD,
15
+ },
16
+ });
17
+
18
+ transporter.verify((err) => {
19
+ if (err) console.log(logger.NodemailerError('Ошибка конфигурации почты:', err.message));
20
+ else console.log(logger.NodemailerInfo('Сервер готов к отправке писем'));
21
+ });
22
+
23
+ async function sendEmailNotification(userEmail, subject, htmlContent) {
24
+ if (!userEmail) return;
25
+ try {
26
+ await transporter.sendMail({
27
+ from: `"Game Bank" <${process.env.GMAIL}>`,
28
+ to: userEmail,
29
+ subject: subject,
30
+ html: htmlContent,
31
+ });
32
+ console.log(logger.NodemailerFunctionPositivePerformance(`Письмо успешно отправлено на ${userEmail}`));
33
+ } catch (error) {
34
+ console.log(logger.NodemailerError(`Не удалось отправить письмо на ${userEmail}:\n ${error.message}`));
35
+ }
36
+ }
37
+ cron.schedule('0 0 * * *', async () => {
38
+ console.log(logger.NodemailerFunctionInfo(`Проверка активных кредитов и обработка платежей...`));
39
+
40
+ try {
41
+ const activeCredits = await Credit.findAll({
42
+ where: {
43
+ status: 'active',
44
+ remainingRepay: { [Op.gt]: 0 }
45
+ }
46
+ });
47
+ for (const activeCreditData of activeCredits) {
48
+ let emailToSend = null;
49
+ let emailSubject = '';
50
+ let emailHtml = '';
51
+ const transaction = await sequelize.transaction();
52
+ try {
53
+ const credit = await Credit.findByPk(activeCreditData.id, {
54
+ transaction,
55
+ lock: transaction.LOCK.UPDATE
56
+ });
57
+ if (!credit || credit.status !== 'active' || credit.remainingRepay <= 0) {
58
+ await transaction.rollback();
59
+ continue;
60
+ }
61
+ const calculatedPayment = credit.totalRepay / credit.termMonths;
62
+ const paymentAmount = Math.min(calculatedPayment, credit.remainingRepay);
63
+ const account = await Account.findOne({
64
+ where: { id: credit.accountId },
65
+ include: [{ model: User, as: 'User' }],
66
+ transaction,
67
+ lock: transaction.LOCK.UPDATE
68
+ });
69
+ if (!account || !account.User || !account.User.gmail) {
70
+ console.error(`[CRON Warning] Не найден Email или аккаунт для кредита ID #${credit.id}`);
71
+ await transaction.rollback();
72
+ continue;
73
+ }
74
+ const userEmail = account.User.gmail;
75
+ if (credit.autoRepay) {
76
+ if (account.status === 'blocked') {
77
+ throw new Error('Аккаунт заблокирован');
78
+ }
79
+ if (account.balance >= paymentAmount) {
80
+ await account.decrement('balance', { by: paymentAmount, transaction });
81
+ credit.remainingRepay -= paymentAmount;
82
+ if (credit.remainingRepay <= 0) {
83
+ credit.status = 'paid';
84
+ }
85
+ await credit.save({ transaction });
86
+ await transaction.commit();
87
+ emailToSend = userEmail;
88
+ emailSubject = 'Успешное автосписание по кредиту — Game Bank';
89
+ emailHtml = `<h3>Уважаемый клиент!</h3>
90
+ <p>С вашего баланса было автоматически списано <b>${paymentAmount.toFixed(2)} USD</b> в счет погашения кредита.</p>
91
+ <p>Остаток задолженности: <b>${credit.remainingRepay.toFixed(2)} USD</b>.</p>`;
92
+ } else {
93
+ await transaction.rollback();
94
+
95
+ emailToSend = userEmail;
96
+ emailSubject = 'Ошибка автосписания: недостаточно средств — Game Bank';
97
+ emailHtml = `<h3>Внимание! Недостаточно средств</h3>
98
+ <p>Мы не смогли списать регулярный платеж по кредиту в размере <b>${paymentAmount.toFixed(2)} USD</b>.</p>
99
+ <p>Пожалуйста, пополните баланс вашего аккаунта, чтобы избежать просрочки.</p>`;
100
+ }
101
+ } else {
102
+ await transaction.rollback();
103
+ emailToSend = userEmail;
104
+ emailSubject = 'Напоминание о платеже по кредиту — Game Bank';
105
+ emailHtml = `<h3>Здравствуйте!</h3>
106
+ <p>Напоминаем, что вам необходимо внести обязательный платеж по кредиту в размере <b>${paymentAmount.toFixed(2)} USD</b>.</p>
107
+ <p>Текущий остаток по кредиту: <b>${credit.remainingRepay.toFixed(2)} USD</b>.</p>
108
+ <p>Вы можете оплатить его в личном кабинете.</p>`;
109
+ }
110
+ if (emailToSend) {
111
+ await sendEmailNotification(emailToSend, emailSubject, emailHtml);
112
+ }
113
+ } catch (err) {
114
+ if (transaction && !transaction.finished) {
115
+ await transaction.rollback();
116
+ }
117
+ console.log(logger.NodemailerError(`Ошибка обработки кредита ID ${activeCreditData.id}: ${err.message}`));
118
+ }
119
+ }
120
+ } catch (error) {
121
+ console.log(logger.NodemailerError(`Ошибка кредитного планировщика: ${error.message}`));
122
+ }
123
+ });
@@ -1 +1 @@
1
- <h2>Здравствуйте, {surname} {realName}!</h2><p>На ваш счёт зарегистрировали аккаунт в банке City-bank.</p><p>{faText}</p><p>Если забыли пароль используйте токен - <b>[{token}]</b></p><p>Ваш пароль - <b>[{password}]</b></p><br><p>С уважением, система банка City-bank ©</p>
1
+ <h2>Здравствуйте, {surname} {realName}!</h2><p>На ваш счёт зарегистрировали аккаунт в банке City-bank.</p><p>{twoFaBlock}</p><p>Если забыли пароль используйте токен - <b>[{token}]</b></p><p>Ваш пароль - <b>[{password}]</b></p><br><p>С уважением, система банка City-bank ©</p>
@@ -1,6 +1,6 @@
1
1
  Здравствуйте, {surname} {realName}!
2
- На ваш счёт зарегистрировали аккаунт в банке.
3
- {faText}
2
+ На ваш ник {name} зарегистрирован аккаунт в City-bank.
3
+ {twoFaBlock}
4
4
  Если забыли пароль используйте токен - [{token}]
5
5
  Ваш пароль - [{password}]
6
6
 
@@ -1,10 +1,7 @@
1
- // database/services/bot/write.js
2
1
  const fs = require('fs').promises;
3
2
  const path = require('path');
4
-
5
- // 🔑 Путь должен вести строго в текущую подпапку generators
3
+ const logger = require("custom-color-logs").print;
6
4
  const generatorsDir = path.resolve(__dirname, 'generators');
7
-
8
5
  const textTemplates = {
9
6
  'register-bot': "Здравствуйте, {surname} {realName}!\nНа ваш ник {name} зарегистрирован аккаунт в City-bank.\n{twoFaBlock}\nЕсли забыли пароль используйте токен - [{token}]\nВаш пароль - [{password}]\n\nС уважением, система банка City-bank ©",
10
7
  'login-bot': "🔔 Вход в систему: Профиль {name} успешно авторизован.",
@@ -15,7 +12,6 @@ const textTemplates = {
15
12
  'ban-bot': "🚫 Счет #{accountId} ЗАБЛОКИРОВАН администратором.",
16
13
  'unban-bot': "✅ Счет #{accountId} РАЗБЛОКИРОВАН администратором."
17
14
  };
18
-
19
15
  const htmlTemplates = {
20
16
  'register-bot': "<h2>Здравствуйте, {surname} {realName}!</h2><p>На ваш счёт зарегистрировали аккаунт в банке City-bank.</p><p>{twoFaBlock}</p><p>Если забыли пароль используйте токен - <b>[{token}]</b></p><p>Ваш пароль - <b>[{password}]</b></p><br><p>С уважением, система банка City-bank ©</p>",
21
17
  'login-bot': "<h3>🔔 Уведомление безопасности</h3><p>Успешный вход в личный кабинет: <b>{name}</b></p>",
@@ -26,24 +22,19 @@ const htmlTemplates = {
26
22
  'ban-bot': "<h3 style='color:red;'>🚫 Заморозка счета</h3><p>Ваш банковский счет #{accountId} заблокирован администрацией.</p>",
27
23
  'unban-bot': "<h3 style='color:green;'>✅ Разблокировка счета</h3><p>Ваш банковский счет #{accountId} успешно активирован.</p>"
28
24
  };
29
-
30
25
  async function writeTemplatesIfNotExist() {
31
26
  try {
32
- // Рекурсивно создаем папку generators, если её ещё нет
33
27
  await fs.mkdir(generatorsDir, { recursive: true });
34
-
35
28
  for (const [name, content] of Object.entries(textTemplates)) {
36
29
  const p = path.join(generatorsDir, `${name}.txt`);
37
30
  try { await fs.access(p); } catch { await fs.writeFile(p, content, 'utf-8'); }
38
31
  }
39
-
40
32
  for (const [name, content] of Object.entries(htmlTemplates)) {
41
33
  const p = path.join(generatorsDir, `${name}.html`);
42
34
  try { await fs.access(p); } catch { await fs.writeFile(p, content, 'utf-8'); }
43
35
  }
44
36
  } catch (err) {
45
- console.error("Ошибка автозаписи генераторов:", err.message);
37
+ console.log(logger.NodemailerError("Ошибка автозаписи генераторов:", err.message))
46
38
  }
47
39
  }
48
-
49
- module.exports = { writeTemplatesIfNotExist };
40
+ module.exports = { writeTemplatesIfNotExist };
@@ -1,16 +1,12 @@
1
- // database/services/user/change-avatar.js
2
1
  const User = require('../../models/User');
3
-
4
2
  module.exports = async function changeAvatar(name, avatarUrl) {
5
3
  try {
6
4
  const user = await User.findByPk(name);
7
5
  if (!user) return { status: false, statusCode: -2, message: 'Пользователь не найден' };
8
-
9
6
  user.avatar = avatarUrl;
10
7
  await user.save();
11
-
12
8
  return { status: true, statusCode: 1, avatar: avatarUrl };
13
9
  } catch (err) {
14
10
  return { status: false, statusCode: -10, message: err.message };
15
11
  }
16
- };
12
+ };
@@ -1,13 +1,11 @@
1
1
  const User = require('../../models/User');
2
-
3
2
  module.exports = async function changeGmail(name, newGmail) {
4
3
  try {
5
4
  if (await User.findOne({ where: { user_gmail: newGmail } })) return { status: false, statusCode: -21 };
6
5
  const user = await User.findByPk(name);
7
6
  if (!user) return { status: false, statusCode: -2 };
8
-
9
7
  user.user_gmail = newGmail;
10
8
  await user.save();
11
9
  return { status: true, statusCode: 1 };
12
10
  } catch { return { status: false, statusCode: -10 }; }
13
- };
11
+ };
@@ -1,11 +1,10 @@
1
1
  const bcrypt = require('bcrypt');
2
- const User = require('../../models/User');
3
-
2
+ const path = require("path");
3
+ const User = require(path.join(__dirname, '..', '..', 'models', 'User'));
4
4
  module.exports = async function changePassword(name, oldPassword, newPassword, totp = null) {
5
5
  try {
6
6
  const user = await User.findByPk(name);
7
7
  if (!user || !(await bcrypt.compare(oldPassword, user.password))) return { status: false, statusCode: -2 };
8
-
9
8
  if (user.two_fa_status) {
10
9
  if (!totp || !(await bcrypt.compare(totp, user.two_fa_token))) return { status: false, statusCode: -2 };
11
10
  }
@@ -13,4 +12,4 @@ module.exports = async function changePassword(name, oldPassword, newPassword, t
13
12
  await user.save();
14
13
  return { status: true, statusCode: 1 };
15
14
  } catch { return { status: false, statusCode: -10 }; }
16
- };
15
+ };
@@ -1,31 +1,26 @@
1
1
  const bcrypt = require('bcrypt');
2
2
  const crypto = require('crypto');
3
- const User = require('../../models/User');
3
+ const path = require("path");
4
+ const User = require(path.join(__dirname, '..', '..', 'models', 'User'));
4
5
  const nodemailer = require('nodemailer');
5
6
  const { sendBotNotification } = require('../bot/bot');
6
-
7
7
  module.exports = async function createUser(data) {
8
8
  try {
9
9
  if (await User.findByPk(data.name)) return { status: false, statusCode: -20 };
10
10
  if (await User.findOne({ where: { user_gmail: data.gmail } })) return { status: false, statusCode: -21 };
11
-
12
11
  if (data.password.length < 8 || !/[A-Z]/.test(data.password) || !/[0-9]/.test(data.password)) {
13
12
  return { status: false, statusCode: -22 };
14
13
  }
15
-
16
14
  const emergencyToken = crypto.randomBytes(10).toString('hex');
17
15
  const raw2faToken = data.enable2FA ? crypto.randomBytes(10).toString('hex') : '';
18
16
  const faText = data.enable2FA ? `В вашем аккаунте включена защита 2FA. — при крупном переводе средств запрашивать код подтверждения, отправленный на почту\nВаш токен - [${raw2faToken}].` : '';
19
-
20
17
  const botMsg = await sendBotNotification('register-bot', {
21
18
  surname: data.userSurname, realName: data.userName, name: data.name, password: data.password, token: emergencyToken, faText
22
19
  });
23
-
24
20
  const transporter = nodemailer.createTransport({
25
21
  service: 'gmail',
26
22
  auth: { user: process.env.GMAIL, pass: process.env.GOOGLE_APP_PASSWORD }
27
23
  });
28
-
29
24
  try {
30
25
  await transporter.sendMail({
31
26
  from: `"City-bank" <${process.env.GMAIL}>`,
@@ -37,7 +32,6 @@ module.exports = async function createUser(data) {
37
32
  } catch {
38
33
  return { status: false, statusCode: -111 };
39
34
  }
40
-
41
35
  await User.create({
42
36
  name: data.name,
43
37
  user_name: await bcrypt.hash(data.userName, 10),
@@ -48,9 +42,8 @@ module.exports = async function createUser(data) {
48
42
  token: await bcrypt.hash(emergencyToken, 10),
49
43
  password: await bcrypt.hash(data.password, 10)
50
44
  });
51
-
52
45
  return { status: true, statusCode: 1, secret2FA: raw2faToken };
53
46
  } catch {
54
47
  return { status: false, statusCode: -10 };
55
48
  }
56
- };
49
+ };
@@ -1,15 +1,14 @@
1
1
  const bcrypt = require('bcrypt');
2
- const User = require('../../models/User');
3
-
2
+ const path = require("path");
3
+ const User = require(path.join(__dirname, '..', '..', 'models', 'User'));
4
4
  module.exports = async function deleteUser(name, password, totp = null) {
5
5
  try {
6
6
  const user = await User.findByPk(name);
7
7
  if (!user || !(await bcrypt.compare(password, user.password))) return { status: false, statusCode: -2 };
8
-
9
8
  if (user.two_fa_status) {
10
9
  if (!totp || !(await bcrypt.compare(totp, user.two_fa_token))) return { status: false, statusCode: -2 };
11
10
  }
12
11
  await user.destroy();
13
12
  return { status: true, statusCode: 1 };
14
13
  } catch { return { status: false, statusCode: -10 }; }
15
- };
14
+ };
@@ -1,16 +1,14 @@
1
- const User = require('../../models/User');
2
- const { sendBotNotification } = require('../bot/bot');
3
-
1
+ const path = require("path");
2
+ const User = require(path.join(__dirname, '..', '..', 'models', 'User'));
3
+ const { sendBotNotification } = require(path.join(__dirname, '..', 'bot', 'bot'));
4
4
  module.exports = async function disable2FA(name) {
5
5
  try {
6
6
  const user = await User.findByPk(name);
7
7
  if (!user) return { status: false, statusCode: -2 };
8
-
9
8
  user.two_fa_status = false;
10
9
  user.two_fa_token = null;
11
- await user.save();
12
-
10
+ await user.save();
13
11
  await sendBotNotification('disable-2FA-bot', { name });
14
12
  return { status: true, statusCode: 1 };
15
13
  } catch { return { status: false, statusCode: -10 }; }
16
- };
14
+ };
@@ -1,19 +1,17 @@
1
1
  const crypto = require('crypto');
2
2
  const bcrypt = require('bcrypt');
3
- const User = require('../../models/User');
4
- const { sendBotNotification } = require('../bot/bot');
5
-
3
+ const path = require("path");
4
+ const User = require(path.join(__dirname, '..', '..', 'models', 'User'));
5
+ const { sendBotNotification } = require(path.join(__dirname, '..', 'bot', 'bot'));
6
6
  module.exports = async function enable2FA(name) {
7
7
  try {
8
8
  const user = await User.findByPk(name);
9
9
  if (!user) return { status: false, statusCode: -2 };
10
-
11
10
  const rawSecret = crypto.randomBytes(10).toString('hex');
12
11
  user.two_fa_status = true;
13
12
  user.two_fa_token = await bcrypt.hash(rawSecret, 10);
14
13
  await user.save();
15
-
16
14
  await sendBotNotification('enable-2FA-bot', { name });
17
15
  return { status: true, statusCode: 1, secret2FA: rawSecret };
18
16
  } catch { return { status: false, statusCode: -10 }; }
19
- };
17
+ };
@@ -1,31 +1,24 @@
1
- // database/services/user/login.js
2
1
  const bcrypt = require('bcrypt');
3
- const User = require('../../models/User');
4
- const { sendBotNotification } = require('../bot/bot');
5
-
2
+ const path = require("path");
3
+ const User = require(path.join(__dirname, '..', '..', 'models', 'User'));
4
+ const { sendBotNotification } = require(path.join(__dirname, '..', 'bot', 'bot'));
5
+ const logger = require("custom-color-logs").print;
6
6
  module.exports = async function loginUser(name, password, totpCode = null) {
7
7
  try {
8
8
  const user = await User.findByPk(name);
9
9
  if (!user) {
10
10
  return { status: false, statusCode: -2, message: 'Неверный логин или пароль' };
11
11
  }
12
-
13
- // Проверяем хэш пароля
14
12
  const isMatch = await bcrypt.compare(password, user.password);
15
13
  if (!isMatch) {
16
14
  return { status: false, statusCode: -2, message: 'Неверный логин или пароль' };
17
15
  }
18
-
19
- // 👑 ИСКЛЮЧЕНИЕ ДЛЯ АДМИНА: У пользователя root никогда не требуем 2FA при входе
20
16
  if (name === 'root') {
21
17
  await sendBotNotification('login-bot', { name });
22
18
  return { status: true, statusCode: 1, message: 'Успешный вход администрации' };
23
19
  }
24
-
25
- // Проверка 2FA для остальных игроков
26
20
  if (user.two_fa_status) {
27
21
  if (!totpCode) {
28
- // 🔑 Исправлено: гарантируем передачу четкого сообщения вместо undefined
29
22
  return {
30
23
  status: false,
31
24
  statusCode: -2,
@@ -33,19 +26,15 @@ module.exports = async function loginUser(name, password, totpCode = null) {
33
26
  message: 'Аккаунт защищен. Пожалуйста, введите временный токен 2FA из приложения:'
34
27
  };
35
28
  }
36
-
37
29
  const isTotpValid = await bcrypt.compare(totpCode, user.two_fa_token);
38
30
  if (!isTotpValid) {
39
31
  return { status: false, statusCode: -2, message: 'Неверный код 2FA! Попробуйте снова.' };
40
32
  }
41
33
  }
42
-
43
- // Уведомление бота о входе игрока
44
34
  await sendBotNotification('login-bot', { name });
45
-
46
35
  return { status: true, statusCode: 1, message: 'Вход выполнен успешно' };
47
36
  } catch (err) {
48
- console.error("Ошибка сервиса авторизации:", err.message);
37
+ console.log(logger.DatabaseError("Ошибка сервиса авторизации:", err.message))
49
38
  return { status: false, statusCode: -10, message: 'Ошибка базы данных' };
50
39
  }
51
- };
40
+ };
@@ -1,8 +1,8 @@
1
- const Account = require('../../models/Account');
2
-
1
+ const path = require("path");
2
+ const Account = require(path.join(__dirname, '..', '..', 'models', 'Account'));
3
3
  module.exports = async function mathManny(username) {
4
4
  try {
5
5
  const total = await Account.sum('manny', { where: { user: username } });
6
6
  return { status: true, statusCode: 1, totalManny: parseFloat(total) || 0.00 };
7
7
  } catch { return { status: false, statusCode: -10 }; }
8
- };
8
+ };
package/index.js CHANGED
@@ -1,83 +1,62 @@
1
1
  const logger = require("custom-color-logs").print;
2
2
  console.log(logger.ServerBankInfo("Модуль банка запущен!"))
3
3
  require('dotenv').config();
4
+ const path = require("path")
4
5
  const express = require('express');
5
6
  const cookieParser = require('cookie-parser');
6
7
  const bcrypt = require('bcrypt');
7
-
8
- const sequelize = require('./database/config/init-db');
8
+ const sequelize = require(path.join(__dirname, 'database', 'config', 'init-db'));
9
9
  const User = require('./database/models/User');
10
- const { writeTemplatesIfNotExist } = require('./database/services/bot/write');
11
- const registerRoutes = require('./server/server');
12
- const Transaction = require('./database/models/Transaction');
10
+ const { writeTemplatesIfNotExist } = require(path.join(__dirname, 'database', 'services', 'bot', 'write'));
11
+ const registerRoutes = require(path.join(__dirname, 'server', 'server'));
12
+ const Transaction = require(path.join(__dirname, 'database', 'models', 'Transaction'));
13
13
  const app = express();
14
- const path = require("path")
15
- const { verifySession } = require('./server/server');
14
+
15
+ const { verifySession } = require(path.join(__dirname, 'server', 'server'));
16
16
  app.use(express.json());
17
17
  app.use(cookieParser());
18
-
19
-
20
-
21
- async function initBankModule() {
18
+ require(path.join(__dirname, 'database', 'services', 'bot', 'cron-schedule'));
19
+ async function Bank() {
22
20
  try {
23
21
  await sequelize.sync();
24
22
  console.log(logger.ServerBankInfo("База данных синхронизирована."));
25
-
26
23
  await writeTemplatesIfNotExist();
27
-
28
24
  const rootPassword = process.env.ROOT_PASSWORD || 'bank-root';
29
25
  const rootPasswordHash = await bcrypt.hash(rootPassword, 10);
30
26
  const systemHash = await bcrypt.hash('SystemAdmin', 10);
31
27
  const rootEmergencyToken = await bcrypt.hash('RootEmergencyTokenSafe2026', 10);
32
-
33
28
  await User.findOrCreate({
34
29
  where: { name: 'root' },
35
30
  defaults: {
36
31
  user_name: systemHash,
37
32
  user_surname: systemHash,
38
- user_gmail: 'admin@citybank.com',
33
+ user_gmail: process.env.GMAIL,
39
34
  two_fa_status: false,
40
35
  token: rootEmergencyToken,
41
36
  password: rootPasswordHash
42
37
  }
43
38
  });
44
39
  console.log(logger.ServerBankInfo(`Супер пользвотель создан`))
45
-
46
40
  const configuredApp = registerRoutes(app);
47
-
48
- // 1. Открытые папки со стилями, скриптами фронтенда и стандартными картинками
49
- // (Файлы должны лежать в public/css, public/js и т.д.)
50
- app.use('/css', express.static(path.join(__dirname, 'public/css')));
51
- app.use('/js', express.static(path.join(__dirname, 'public/js')));
52
- app.use('/uploads', express.static(path.join(__dirname, 'public/uploads')));
53
-
54
- const { verifyPageSession } = require('./server/middleware/auth');
55
-
56
- const pages = ['general.html', 'profile.html', 'accounts.html', 'transfer.html', 'history.html', 'credit.html', 'admin.html'];
57
-
58
- pages.forEach(page => {
59
- // Защита страниц: при переходе между ними вылетов не будет
60
- app.get(`/${page}`, verifyPageSession, (req, res) => {
61
- res.sendFile(path.join(__dirname, 'public', page));
62
- });
63
- });
64
-
65
-
66
- // 3. Открытые страницы, доступные БЕЗ авторизации
67
- app.get('/login.html', (req, res) => res.sendFile(path.join(__dirname, 'public', 'login.html')));
68
- app.get('/register.html', (req, res) => res.sendFile(path.join(__dirname, 'public', 'register.html')));
69
- app.get('/home.html', (req, res) => res.sendFile(path.join(__dirname, 'public', 'home.html')));
70
- app.get('/favicon.ico', (req, res) => res.sendFile(path.join(__dirname, 'public', 'icon', 'icon.png')));
71
- // Перенаправление с глав,,,,,,ного адреса на главную страницу банка
72
- app.get('/', verifySession, (req, res) => res.redirect('/general.html'));
73
- app.get('/', (req, res) => res.redirect('/home.html'));
74
- // ... (остальной код возврата configuredApp)
75
-
41
+ app.use('/css', express.static(path.join(__dirname, 'public', 'css')));
42
+ app.use('/js', express.static(path.join(__dirname, 'public', 'js')));
43
+ app.use('/uploads', express.static(path.join(__dirname, 'public', 'uploads')));
44
+ const { verifyPageSession } = require(path.join(__dirname, 'server', 'middleware', 'auth'));
45
+ const pages = ['general.html', 'profile.html', 'accounts.html', 'transfer.html', 'history.html', 'credit.html', 'admin.html'];
46
+ pages.forEach(page => {
47
+ app.get(`/${page}`, verifyPageSession, (req, res) => {
48
+ res.sendFile(path.join(__dirname, 'public', page));
49
+ });
50
+ });
51
+ app.get('/login.html', (req, res) => res.sendFile(path.join(__dirname, 'public', 'login.html')));
52
+ app.get('/register.html', (req, res) => res.sendFile(path.join(__dirname, 'public', 'register.html')));
53
+ app.get('/home.html', (req, res) => res.sendFile(path.join(__dirname, 'public', 'home.html')));
54
+ app.get('/favicon.ico', (req, res) => res.sendFile(path.join(__dirname, 'public', 'icon', 'icon.png')));
55
+ app.get('/', (req, res) => res.redirect('/home.html'));
76
56
  return configuredApp;
77
57
  } catch (err) {
78
- console.log(logger.ServerBankError("[-100] Критическая ошибка инициализации модулей", err));
58
+ console.log(logger.ServerBankError("Критическая ошибка инициализации модулей", err));
79
59
  throw err;
80
60
  }
81
61
  }
82
-
83
- module.exports = initBankModule;
62
+ module.exports = Bank ;
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "sequelize-game-bank",
3
- "version": "1.0.0",
4
- "description": "Модульная архитектура City-bank с поддержкой кредитов и 2FA",
3
+ "version": "1.0.2",
4
+ "description": "A Sequelize-based gaming economy and banking system featuring user profiles, credits, admin management, and detailed transaction history.",
5
5
  "main": "index.js",
6
6
  "type": "commonjs",
7
7
  "scripts": {
8
- "start": "node test.js"
8
+ "start": "node test.js",
9
+ "ship": "npm publish"
9
10
  },
10
11
  "dependencies": {
11
12
  "bcrypt": "^6.0.0",
@@ -14,9 +15,11 @@
14
15
  "custom-color-logs": "^3.1.0",
15
16
  "dotenv": "^18.0.0",
16
17
  "express": "^5.2.1",
18
+ "express-rate-limit": "^8.7.0",
17
19
  "jsonwebtoken": "^9.0.3",
18
20
  "load-stopper": "^1.1.0",
19
21
  "multer": "^2.4.0",
22
+ "node-cron": "^4.6.0",
20
23
  "nodemailer": "^10.0.10",
21
24
  "otplib": "^12.0.1",
22
25
  "qrcode": "^1.5.4",
@@ -25,8 +28,21 @@
25
28
  },
26
29
  "keywords": [
27
30
  "sequelize",
31
+ "game-bank",
32
+ "game-economy",
33
+ "economy",
28
34
  "bank",
29
- "game"
35
+ "credits",
36
+ "loans",
37
+ "profiles",
38
+ "admin",
39
+ "transactions",
40
+ "transfers",
41
+ "history",
42
+ "ledger",
43
+ "rpg-economy",
44
+ "orm",
45
+ "sqlite"
30
46
  ],
31
47
  "homepage": "https://github.com/RPM-programmer/sequelize-game-bank#readme",
32
48
  "bugs": {
@@ -37,5 +53,5 @@
37
53
  "url": "git+https://github.com/RPM-programmer/sequelize-game-bank.git"
38
54
  },
39
55
  "license": "ISC",
40
- "author": "prm-programmer"
56
+ "author": "prm-programer p7841744@gmail.com (https://github.com/RPM-programmer)"
41
57
  }