cms.login.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. <?php
  2. // Appliquer les headers de sécurité pour la page de login
  3. securityHeaders::applyForLogin();
  4. ?>
  5. <!DOCTYPE html>
  6. <html lang="fr">
  7. <head>
  8. <meta charset="UTF-8">
  9. <title>CSE Invent : Identification</title>
  10. <?php pwa::printManifeste(); ?>
  11. <meta name="mobile-web-app-capable" content="yes">
  12. <meta name="apple-mobile-web-app-capable" content="yes">
  13. <meta name="application-name" content="CSE Invent : CMS">
  14. <meta name="apple-mobile-web-app-title" content="CSE Invent : CMS">
  15. <meta name="msapplication-starturl" content="/">
  16. <meta name="msapplication-TileColor" content="#da532c">
  17. <meta name="theme-color" content="#ffffff">
  18. <link rel="icon" type="image/x-icon" href="<?php cache::printFileWithTime("favicon.ico") ?>">
  19. <!-- Token CSRF pour les requêtes AJAX -->
  20. <?php echo csrf::metaTag('login-ajax'); ?>
  21. <script src="<?php cache::printFileWithTime("libs/js/jquery.min.js") ?>"></script>
  22. <script src="<?php cache::printFileWithTime("libs/bootstrap/js/bootstrap.min.js") ?>"></script>
  23. <link rel="stylesheet" href="<?php cache::printFileWithTime("libs/bootstrap/assets/dist/css/bootstrap.min.css") ?>">
  24. <link rel="stylesheet" href="<?php cache::printFileWithTime("css/login.css") ?>">
  25. </head>
  26. <body>
  27. <div class="wrapper fadeInDown">
  28. <div id="formContent">
  29. <div class="fadeIn first">
  30. <img src="img/logo.png" id="icon" alt="CSE Invent" />
  31. </div>
  32. <form method="post" action="/submit.php" id="form-authent">
  33. <?php echo csrf::inputField('login-form'); ?>
  34. <input type="hidden" name="from" value="login">
  35. <!-- Honeypot anti-bot (champ invisible) -->
  36. <div style="position:absolute;left:-9999px;" aria-hidden="true">
  37. <input type="text" name="website" tabindex="-1" autocomplete="off">
  38. </div>
  39. <input type="text" class="fadeIn second" name="email" id="email" placeholder="email" required autocomplete="username">
  40. <input type="password" class="fadeIn third" name="password" placeholder="mot de passe" required autocomplete="current-password">
  41. <input type="text" class="third" style="display:none;" name="authenticator" id="authenticator" maxlength="6" placeholder="Code Google Authenticator">
  42. <input type="button" class="fadeIn fourth" id="submit-authent" value="Se connecter">
  43. <!-- Message de rate limiting -->
  44. <div id="rate-limit-warning" class="alert alert-warning" style="display:none;margin:10px;"></div>
  45. </form>
  46. <div id="formFooter" <?php if (!alert::ifError()) {
  47. echo ' style="display:none"';
  48. } ?>>
  49. <div class="alert alert-danger" role="alert"><?php if (alert::ifError()) {
  50. echo alert::printAlert(alert::getError());
  51. } ?></div>
  52. </div>
  53. <script nonce="<?php echo securityHeaders::getNonce(); ?>">
  54. $(document).ready(function() {
  55. // Configuration CSRF pour les requêtes AJAX
  56. $(document).ajaxSend(function(event, jqxhr, settings) {
  57. if (settings.type === 'POST') {
  58. const csrfToken = $('meta[name="csrf-token"]').attr('content');
  59. if (csrfToken) {
  60. jqxhr.setRequestHeader('X-CSRF-Token', csrfToken);
  61. }
  62. }
  63. });
  64. $("#submit-authent").on("click", function() {
  65. var $btn = $(this);
  66. var $warning = $("#rate-limit-warning");
  67. // Désactiver le bouton pendant la requête
  68. $btn.prop('disabled', true).val('Vérification...');
  69. $warning.hide();
  70. var formData = {
  71. email: $("#email").val(),
  72. from: "authenticator",
  73. csrf_token: $("input[name='csrf_token']").val() // Inclure le token CSRF du formulaire
  74. };
  75. $.ajax({
  76. type: "POST",
  77. url: "submit.php",
  78. data: formData,
  79. dataType: "json",
  80. encode: true,
  81. }).done(function(data) {
  82. if (data && data.blocked) {
  83. // Compte bloqué - afficher le message
  84. $warning.html('<strong>⚠️ ' + data.message + '</strong>').show();
  85. $btn.prop('disabled', true).val('Bloqué');
  86. // Réactiver après le délai
  87. if (data.remaining_time) {
  88. setTimeout(function() {
  89. $btn.prop('disabled', false).val('Se connecter');
  90. $warning.hide();
  91. }, data.remaining_time * 1000);
  92. }
  93. } else if (data == 1 || data.authenticator == 1) {
  94. $("#authenticator").show();
  95. $("#authenticator").prop("required", true);
  96. $('#submit-authent').attr('type', 'submit').val('Se connecter');
  97. $btn.prop('disabled', false);
  98. } else {
  99. $("#form-authent").submit();
  100. }
  101. }).fail(function(jqXHR, textStatus, errorThrown) {
  102. console.error("Erreur AJAX:", textStatus, errorThrown);
  103. $btn.prop('disabled', false).val('Se connecter');
  104. // Gérer les erreurs spécifiques
  105. if (jqXHR.status === 429) {
  106. var response = jqXHR.responseJSON || {};
  107. $warning.html('<strong>⚠️ ' + (response.message || 'Trop de tentatives. Veuillez patienter.') + '</strong>').show();
  108. } else if (jqXHR.status === 403) {
  109. $warning.html('<strong>⚠️ Session expirée. Rechargez la page.</strong>').show();
  110. }
  111. });
  112. });
  113. });
  114. </script>
  115. </div>
  116. </div>
  117. <?php pwa::printServiceWorker(); ?>
  118. </body>
  119. </html>
  120. <?php
  121. alert::destroyAlert();
  122. ?>