R.I.P me........

This commit is contained in:
2026-05-06 21:15:12 +03:00
parent a406af54bd
commit 0e6103f138
8 changed files with 1193 additions and 33 deletions

View File

@@ -31,7 +31,7 @@ public class IikoHandler {
log.error("Failed to initialize database", err);
});
router.route("/api/reports/olap/*").handler(authHandler::requireAuth);
// router.route("/api/reports/olap/*").handler(authHandler::requireAuth);
router.get("/api/reports/olap/columns").handler(this::getColumns);
router.delete("/api/reports/olap/columns/:fieldKey").handler(AdminHandler::requireAdmin).handler(this::deleteColumn);
router.post("/api/reports/olap/initialize").handler(AdminHandler::requireAdmin).handler(this::postInitialize);

View File

@@ -0,0 +1,24 @@
package su.xserver.iikocon.test;
import java.security.SecureRandom;
public class CodeGenerator {
// SecureRandom — это криптостойкий генератор случайных чисел.
// Он обеспечивает непредсказуемость, что критично для безопасности.
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
/**
* Генерирует шестизначный код подтверждения, соответствующий корпоративным стандартам.
*
* @return Строка, содержащая ровно 6 цифр. Первая цифра никогда не будет '0'.
*/
public static String generateCorporateCode() {
// Генерируем число в диапазоне от 100 000 до 999 999.
// Это гарантирует, что наш код всегда будет шестизначным.
int code = SECURE_RANDOM.nextInt(900_000) + 100_000;
return String.valueOf(code);
}
}

View File

@@ -17,5 +17,14 @@ public class DateRangeSetup {
System.out.println("dateFrom=" + formattedDateFrom);
System.out.println("dateTo=" + formattedDateTo);
System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode());
System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode());
System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode());
System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode());
System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode());
System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode());
System.out.println("CodeGenerator=" + CodeGenerator.generateCorporateCode());
}
}

View File

@@ -0,0 +1,198 @@
package su.xserver.iikocon.test;
import io.vertx.core.Vertx;
import io.vertx.ext.mail.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestMail {
private static final Logger log = LoggerFactory.getLogger(TestMail.class);
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
MailConfig config = new MailConfig()
.setHostname("mail.xserver.su")
.setPort(465)
.setSsl(true)
.setStarttls(StartTLSOptions.REQUIRED)
.setUsername("admin.app@xserver.su")
.setPassword("SOLTiLS64TiL");
MailClient mailClient = MailClient.create(vertx, config);
// MailMessage message = new MailMessage()
// .setFrom("bodrycraft@yandex.ru")
// .setTo("danil.bodry@vk.com")
// .setSubject("Hello from Vert.x")
// .setText("This is a test email sent using Vert.x Mail Client!");
// String htmlBody = """
// <html>
// <body>
// <h1>Заголовок письма</h1>
// <p>Это основная часть письма с форматированием.</p>
// <p>Вы можете использовать <strong>жирный</strong> текст,
// <a href="https://example.com">ссылки</a> и другие элементы.</p>
// <img src="cid:bannerImage" alt="Баннер"><br>
// <p>С уважением,<br>Ваша команда</p>
// </body>
// </html>
// """;
// MailAttachment regularAttachment = MailAttachment.create()
// .setData(Buffer.buffer("Это содержимое текстового файла."))
// .setName("информация.txt")
// .setContentType("text/plain");
// MailAttachment inlineImage = MailAttachment.create()
// .setData(Buffer.buffer()) // Здесь должны быть данные вашего изображения
// .setContentType("image/png")
// .setContentId("bannerImage"); // Этот ID и используется в теге <img src="cid:bannerImage">
// MailMessage message = new MailMessage()
// .setFrom("bodrycraft@yandex.ru")
// .setTo("danil.bodry@vk.com")
// .setSubject("Красивое письмо от Vert.x")
// .setText("Это обычная текстовая версия письма.")
// .setHtml(htmlBody)
// .setAttachment(regularAttachment)
// .setInlineAttachment(inlineImage);
// 2. Генерируем 6-значный код
String verificationCode = CodeGenerator.generateCorporateCode();
String recipientEmail = "danil.bodry@xserver.su";
String userName = "Дорогой пользователь"; // можно подставить имя
// 3. HTML-шаблон письма
String htmlBody = buildHtmlEmail(verificationCode, userName);
// 4. Текстовая версия (plain text)
String textBody = String.format("""
%s,
Ваш код подтверждения: %s
Для завершения входа введите этот код на странице авторизации.
Код действителен в течение 10 минут.
Если вы не запрашивали вход, просто проигнорируйте это письмо.
С уважением,
Команда поддержки
""", userName, verificationCode);
// 5. Формируем письмо
MailMessage message = new MailMessage()
.setFrom("gallery@xserver.su")
.setTo(recipientEmail)
.setSubject("Ваш код для входа")
// .setText(textBody)
.setHtml(htmlBody);
mailClient.sendMail(message)
.onSuccess(res -> log.info("Success!"))
.onFailure(err -> log.error("Error: {}", err.getMessage()));
}
private static String buildHtmlEmail(String code, String userName) {
return "<!DOCTYPE html>\n" +
"<html>\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
" <title>Код подтверждения</title>\n" +
" <style>\n" +
" * { margin: 0; padding: 0; box-sizing: border-box; }\n" +
" body {\n" +
" font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;\n" +
" background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n" +
" margin: 0;\n" +
" padding: 20px;\n" +
" }\n" +
" .container {\n" +
" max-width: 520px;\n" +
" margin: 0 auto;\n" +
" background: #ffffff;\n" +
" border-radius: 32px;\n" +
" box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n" +
" overflow: hidden;\n" +
" }\n" +
" .header {\n" +
" background: linear-gradient(120deg, #4f46e5, #7c3aed);\n" +
" padding: 32px 20px;\n" +
" text-align: center;\n" +
" }\n" +
" .header h1 { color: white; font-size: 28px; font-weight: 700; letter-spacing: -0.5px; margin: 0; }\n" +
" .content { padding: 40px 32px; }\n" +
" .greeting { font-size: 20px; font-weight: 600; color: #1e293b; margin-bottom: 16px; }\n" +
" .message { color: #334155; font-size: 16px; line-height: 1.5; margin-bottom: 28px; }\n" +
" .code-box {\n" +
" background: #f8fafc;\n" +
" border-radius: 20px;\n" +
" padding: 24px;\n" +
" text-align: center;\n" +
" margin: 24px 0;\n" +
" border: 1px solid #e2e8f0;\n" +
" box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);\n" +
" }\n" +
" .code-label { font-size: 13px; text-transform: uppercase; letter-spacing: 1px; font-weight: 600; color: #64748b; margin-bottom: 12px; }\n" +
" .code {\n" +
" font-family: 'SF Mono', 'Menlo', 'Monaco', 'Cascadia Code', monospace;\n" +
" font-size: 48px;\n" +
" font-weight: 800;\n" +
" letter-spacing: 8px;\n" +
" color: #1e293b;\n" +
" background: white;\n" +
" display: inline-block;\n" +
" padding: 12px 24px;\n" +
" border-radius: 16px;\n" +
" box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n" +
" margin: 8px 0;\n" +
" }\n" +
" .expiry { font-size: 14px; color: #475569; background: #f1f5f9; display: inline-block; padding: 6px 14px; border-radius: 40px; margin-top: 12px; }\n" +
" .button {\n" +
" display: inline-block;\n" +
" background: linear-gradient(90deg, #4f46e5, #7c3aed);\n" +
" color: white;\n" +
" text-decoration: none;\n" +
" padding: 12px 28px;\n" +
" border-radius: 40px;\n" +
" font-weight: 600;\n" +
" margin: 16px 0 8px;\n" +
" box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n" +
" }\n" +
" .footer { text-align: center; padding: 24px 32px; background: #f8fafc; font-size: 12px; color: #64748b; border-top: 1px solid #e2e8f0; }\n" +
" .footer a { color: #4f46e5; text-decoration: none; }\n" +
" @media (max-width: 560px) { .content { padding: 28px 20px; } .code { font-size: 36px; letter-spacing: 4px; padding: 8px 16px; } .header h1 { font-size: 24px; } }\n" +
" </style>\n" +
"</head>\n" +
"<body>\n" +
" <div class=\"container\">\n" +
" <div class=\"header\">\n" +
" <h1>Вход в аккаунт</h1>\n" +
" </div>\n" +
" <div class=\"content\">\n" +
" <div class=\"greeting\">Здравствуйте, " + userName + "!</div>\n" +
" <div class=\"message\">\n" +
" Мы получили запрос на вход в ваш аккаунт. Используйте код подтверждения ниже, чтобы завершить вход.\n" +
" </div>\n" +
" <div class=\"code-box\">\n" +
" <div class=\"code-label\">Ваш одноразовый код</div>\n" +
" <div class=\"code\">" + code + "</div>\n" +
" <div class=\"expiry\">Действителен 10 минут</div>\n" +
" </div>\n" +
" <div style=\"text-align: center; margin-top: 8px;\">\n" +
" <a href=\"#\" class=\"button\">Перейти на страницу входа</a>\n" +
" </div>\n" +
" <div class=\"message\" style=\"font-size: 14px; margin-top: 24px; color: #64748b;\">\n" +
" Если вы не запрашивали вход, просто проигнорируйте это письмо. Никому не сообщайте код.\n" +
" </div>\n" +
" </div>\n" +
" <div class=\"footer\">\n" +
" (c) 2025 Ваша компания | <a href=\"#\">Помощь</a> | <a href=\"#\">Безопасность</a>\n" +
" </div>\n" +
" </div>\n" +
"</body>\n" +
"</html>";
}
}