hard

Прокачиваем собственный генератор паролей

Тройная защита для вашей семьи!

В прошлый раз мы сделали собственный генератор паролей: в него скармливался адрес любого сайта и он выдавал вариант пароля, который можно использовать на этом сайте. Хитрость в том, что благодаря секретному слову и меняющемся адресам можно было сделать пароль уникальным, и никто бы не смог его подобрать по словарю. 

В основе генератора лежал алгоритм хеширования — когда любую строку можно зашифровать так, чтобы потом невозможно было восстановить исходный текст. Даёшь ему любой текст, а он тебе что-то такое: 88A42764A5ADE6FF2B27D2981A58A24A — вот это и было основой пароля.

У нашего генератора был большой потенциал для роста и доработок. Сегодня мы добавим в генератор новые возможности и повысим безопасность алгоритма. Вот что мы сделаем:

  • добавим опцию использования спецсимволов в паролях (некоторые сайты это требуют);
  • сделаем некоторые буквы большими для большей безопасности;
  • сделаем так, чтобы пароль создавался сам при каждом новом символе в секретном слове;
  • сделаем так, чтобы программа выдавала удобный в использовании пароль (три группы по три символа, между ними — дефисы).


За основу возьмём исходный код из прошлой статьи.

<!DOCTYPE html>
<html>
<!-- служебная часть -->

<head>
  <!-- заголовок страницы -->
  <title>Генератор паролей</title>
  <!-- настраиваем служебную информацию для браузеров -->
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- подключаем функцию, которая хеширует строку -->
  <script src="http://thecode.local/wp-content/uploads/2019/05/js-md5.js"></script>
  <!-- задаём CSS-стили прямо здесь же, чтобы всё было в одном файле -->
  <style type="text/css">
    /*задаём общие параметры для всей страницы: шрифт и отступы*/
    body {
      text-align: center;
      margin: 10;
      font-family: Verdana, Arial, sans-serif;
      font-size: 16px;
    }

    /* настраиваем внешний вид полей ввода*/
    input {
      display: inline-block;
      margin: 20px auto;
      border: 2px solid #eee;
      padding: 10px 20px;
      font-family: Verdana, Arial, sans-serif;
      font-size: 16px;
    }

    /*закончили со стилями*/
  </style>
  <!-- закрываем служебную часть страницы -->
</head>

<body>
  <!-- началась визуальная часть -->
  <!-- ставим всё содержимое в один блок по центру  -->
  <div class="container" margin: auto;">
    <!-- заголовок страницы -->
    <h2 class="todo__caption">Генератор паролей</h2>
    <!--делаем отступ -->
    <br>
    <!-- задаём поле ввода для адреса нужного сайта и настраиваем параметры поля -->
    <input type="text" id="site_url" size="50" placeholder="Вставьте адрес сайта, где вам нужен пароль">
    <!--делаем отступ -->
    <br>
    <!-- задаём поле ввода для кодового слова и настраиваем параметры поля -->
    <input type="text" id="keyword" size="50" placeholder="Напишите кодовое слово, чтобы сделать пароль сильнее">
    <!--делаем двойной отступ -->
    <br>
    <br>
    <!-- вставляем кнопку, которая запускает генератор пароля и настраиваем отступы -->
    <button style="font-size: 100%; padding:5px 10px 10px 10px" onclick="generate()">Создать пароль</button>
    <!--выводим сгенерированный пароль -->
    <p>Ваш пароль:</p>
    <div id="pass_text" style="font-weight: bold"></div>
  </div>
  <!-- закончилась видимая часть -->
  <!-- пишем скрипт, который будет генерировать пароль по нажатию кнопки -->
  <script>
    // задаём переменные, где будем хранить адрес сайта, кодовое слово…
    var site, salt;
    // …исходные текстовые данные для пароля и сам пароль
    var text, password;
    // объявляем функцию, которая создаёт пароль и выводит его на экран
    function generate() {
      // кладём в соответствующие переменные текстовое значение адреса сайта…
      site = document.getElementById('site_url').value;
      // …и кодового слова
      salt = document.getElementById('keyword').value;
      // подготавливаем исходную строку для пароля и добавляем в неё наш секретный ингредиент
      text = site + salt + 'Misha Polyanin molodets';
      // на основе этой строки с помощью функции md5, которую мы подключили в самом начале, создаём пароль
      password = md5(text);
      // выводим его на экран
      document.getElementById('pass_text').innerHTML = password;
    }
  // закончилась скриптовая часть
  </script>
</body>
<!-- конец всей страницы -->

</html>

Прокачиваем внешний вид генератора

Сразу сделаем всё в визуальной части страницы, чтобы потом к ней не возвращаться. 

Нам нужно добавить поле, куда пользователь будет вводить секретное число. Работать оно будет так: берём пароль, разбиваем его на группы по три символа, берём секретное число и, начиная с него, берём три группы символов. Между группами вставляем дефис, чтобы получился пароль вида abc-def-ghj. Его легче запомнить, к тому же он зависит от секретного числа: новое число — новый пароль.

Нужный фрагмент мы вставим после поля ввода кодового слова. Обратите внимание — у нас поменялся тип поля. Раньше был текст, а теперь число — это значит, что туда можно будет ввести только цифры. Это сделано для того, чтобы никто туда случайно не ввёл буквы и программа не сломалась. Можно, конечно, настроить ручную проверку введённых данных, но в нашем случае это уже избыточно. 

Второе добавление — галочка, которая показывает, нужно нам использовать в пароле спецсимволы (%:*#@%&) или нет. Логика простая: галочка стоит — добавляем спецсимволы в пароль.

<!-- задаём числовое поле ввода для секретного числа -->
<input type="number" id="secnumber" size="50" placeholder="Введите число">
<!--делаем отступ -->
<br>
<!-- добавляем чекбокс, который скажет нам, нужны спецсимволы или нет -->
<input type="checkbox" id="sym">Использовать спецсимволы
<!--делаем отступ -->
<br>

Сохраняем изменения и обновляем страницу с генератором:

Готовим скрипт

Мы будем обращаться к элементам по их именам, а значит, нам нужно подключить jQuery:

<!-- подключаем JQuery -->

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js">

</script>

Затем немного изменим наш блок с переменными, добавим, чего не хватает, чтобы этот блок выглядел так:

// задаём переменные, где будем хранить адрес сайта, кодовое слово, секретное число…

var site, salt, secnum;

// …исходные текстовые данные для пароля и сам пароль

var text, password;

// переменная для временного хранения исходного пароля

var sourcepass;

// спецсимволы, которые добавим в пароль, если нужно

var symbols;

symbols = '%:*#@%&';

Сразу выдаём пароль

Мы хотим, чтобы при каждом новом символе в кодовом слове новый пароль создавался на лету. Для этого используем обработчик событий addEventListener:

// отслеживаем каждое нажатие клавиши при вводе секретной фразы и при каждом нажатии генерируем пароль
document.getElementById('keyword').addEventListener('keydown', function (e) {
  generate();
})

А теперь подумайте: как повесить такой же обработчик событий на поле с числом и на поле с галочкой?

Прокачиваем сам генератор

Раз мы вводим секретное число, надо сразу его обработать и запомнить в отдельной переменной. Это число влияет на выбор начальной тройки для пароля и не может быть меньше единицы:

// вводим секретное число

secnum = document.getElementById('secnumber').value;

// нельзя стартовать с нулевой тройки чисел или меньше

if (secnum < 1) {secnum = 1};

Раз мы будем модифицировать пароль, который в самом начале получаем с помощью MD5-функции, то сохраним его в другой переменной. На её основе мы получим нужный нам модифицированный пароль. Заодно очистим переменную с финальным паролем:

// на основе этой строки с помощью функции md5, которую мы подключили в самом начале, создаём пароль

sourcepass = md5(text);

// обнуляем переменную, где будет храниться изменённый пароль

password = '';

Настало время добавить большие буквы и спецсимволы. Чтобы выбрать, какие буквы делать большими, мы возьмём остаток от деления нашего секретного числа на 3 и полученное число примем за шаг. Как только доходим до нового шага — делаем букву большой. Со спецсимволами тоже всё просто: каждый раз проверяем, стоит галочка или нет. Если стоит — добавляем их на каждой третьей итерации цикла. Выбор спецсимвола тоже зависит от секретного числа.

// цикл, который отвечает за большие числа и спецсимволы в пароле, проходит всю длину строки и обрабатывает каждый символ
for (var i = 0; i < sourcepass.length; i++) {
  // секретным числом определяем шаг, с которым будем делать следующую заглавную букву в пароле
  var upperstep = secnum % 3;
  // если шаг сработал — делаем большой символ, иначе оставляем старый
  if (i % upperstep == 0) { password += sourcepass[i].toUpperCase() }
  else { password += sourcepass[i] };
  // если поставлена галочка про спецсимволы…
  if (document.getElementById('sym').checked) {
    // на каждой третьей итерации вставляем спецсимвол на нужное место
    if (i % 3 == 0) { password += symbols[secnum % 6] }
  }
} 

Разбиваем пароль на тройки

Здесь вся сложность в том, чтобы предусмотреть такой вариант: секретное число больше, чем количество троек в пароле. В этом случае мы по кругу проходим все тройки столько раз, сколько нужно пока не закончится секретное число, и начинаем с текущей позиции. Если тройки закончатся в процессе — вернёмся в начало и будем брать их оттуда. Весь код добавляем в ту же функцию generate():

// перед тем как мысленно разбивать пароль на тройки, поместим его в промежуточную переменную
sourcepass = password;
// обнуляем строку — в неё будем заново собирать наш пароль из троек
password = '';
// если наше секретное число больше, чем групп из трёх символов в исходном пароле — прогоняем тройки по кругу, возвращаемся в начало и останавливаемся на нужной позиции
if (Number(secnum) * 3 > sourcepass.length) { secnum = (Number(secnum) * 3) % sourcepass.length } else { secnum = secnum * 3 };
// формируем пароль из групп по три символа с разделителем
for (var i = 1; i < 10; i++) {
  // если после сложения мы превысили длину исходного пароля — возвращаемся в начало, чтобы продолжить на следующем шаге с первого
  if (sourcepass.length == secnum + i) { secnum = -i };
  // добавляем очередной символ в группу из трёх символов
  password += sourcepass[secnum + i];
  // если прошло уже три символа — добавляем разделитель (а после девятого символа — не добавляем)
  if ((i % 3 == 0) && (i % 9 != 0)) { password += '-' };
} 

Собираем весь код вместе и смотрим, что получилось:

Готовый код

<!DOCTYPE html>
<html>
<!-- служебная часть -->

<head>
  <!-- заголовок страницы -->
  <title>Генератор паролей</title>
  <!-- настраиваем служебную информацию для браузеров -->
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <!-- подключаем функцию, которая хеширует строку -->
  <script src="http://thecode.local/wp-content/uploads/2019/05/js-md5.js"></script>
  <!-- задаём CSS-стили прямо здесь же, чтобы всё было в одном файле -->
  <style type="text/css">
    /*задаём общие параметры для всей страницы: шрифт и отступы*/
    body {
      text-align: center;
      margin: 10;
      font-family: Verdana, Arial, sans-serif;
      font-size: 16px;
    }

    /* настраиваем внешний вид полей ввода*/
    input {
      display: inline-block;
      margin: 20px auto;
      border: 2px solid #eee;
      padding: 10px 20px;
      font-family: Verdana, Arial, sans-serif;
      font-size: 16px;
    }

    /*закончили со стилями*/
  </style>
  <!-- закрываем служебную часть страницы -->
</head>

<body>
  <!-- началась визуальная часть -->
  <!-- ставим всё содержимое в один блок по центру  -->
  <div class="container" margin: auto;">
    <!-- заголовок страницы -->
    <h2 class="todo__caption">Генератор паролей</h2>
    <!--делаем отступ -->
    <br>
    <!-- задаём поле ввода для адреса нужного сайта и настраиваем параметры поля -->
    <input type="text" id="site_url" size="50" placeholder="Вставьте адрес сайта, где вам нужен пароль">
    <!--делаем отступ -->
    <br>
    <!-- задаём поле ввода для кодового слова и настраиваем параметры поля -->
    <input type="text" id="keyword" size="50" placeholder="Напишите кодовое слово, чтобы сделать пароль сильнее">
    <!--делаем отступ -->
    <br>
    <!-- задаём числовое поле ввода для секретного числа -->
    <input type="number" id="secnumber" size="50" placeholder="Введите число">
    <!--делаем отступ -->
    <br>
    <!-- добавляем чекбокс, который скажет нам, нужны спецсимволы или нет -->
    <input type="checkbox" id="sym">Использовать спецсимволы
    <!--делаем отступ -->
    <br>
    <!--делаем двойной отступ -->
    <br>
    <br>
    <!-- вставляем кнопку, которая запускает генератор пароля и настраиваем отступы -->
    <button style="font-size: 100%; padding:5px 10px 10px 10px" onclick="generate()">Создать пароль</button>
    <!--выводим сгенерированный пароль -->
    <p>Ваш пароль:</p>
    <div id="pass_text" style="font-weight: bold"></div>
  </div>
  <!-- закончилась видимая часть -->
  <!-- подключаем JQuery -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js">
  </script>
  <!-- пишем скрипт, который будет генерировать пароль по нажатию кнопки -->
  <script>
    // отслеживаем каждое нажатие клавиши при вводе секретной фразы и при каждом нажатии генерируем пароль
    document.getElementById('keyword').addEventListener('keydown', function (e) {
      generate();
    })
    // функция, которая возвращает случайное число в заданном диапазоне
    function randz(min, max) {
      return Math.floor(Math.random() * (max - min + 1)) + min;
    }
    // задаём переменные, где будем хранить адрес сайта, кодовое слово, секретное число…
    var site, salt, secnum;
    // …исходные текстовые данные для пароля и сам пароль
    var text, password;
    // переменная для временного хранения исходного пароля
    var sourcepass;
    // спецсимволы, которые добавим в пароль, если нужно
    var symbols;
    symbols = '%:*#@%&';
    // объявляем функцию, которая создаёт пароль и выводит его на экран
    function generate() {
      // кладём в соответствующие переменные текстовое значение адреса сайта,
      site = document.getElementById('site_url').value;
      // кодового слова…
      salt = document.getElementById('keyword').value;
      // и секретного числа…
      secnum = document.getElementById('secnumber').value;
      // нельзя стартовать с нулевой тройки чисел или меньше
      if (secnum < 1) { secnum = 1 };
      // подготавливаем исходную строку для пароля и добавляем в неё наш секретный ингредиент
      text = site + salt + 'Misha Polyanin molodets';
      // на основе этой строки с помощью функции md5, которую мы подключили в самом начале, создаём пароль
      sourcepass = md5(text);
      // обнуляем переменную, где будет храниться изменённый пароль
      password = '';
      // цикл, который отвечает за большие числа и спецсимволы в пароле, проходит всю длину строки и обрабатывает каждый символ
      for (var i = 0; i < sourcepass.length; i++) {
        // секретным числом определяем шаг, с которым будем делать следующую заглавную букву в пароле
        var upperstep = secnum % 3;
        // если шаг сработал — делаем большой символ, иначе оставляем старый
        if (i % upperstep == 0) { password += sourcepass[i].toUpperCase() }
        else { password += sourcepass[i] };
        // если поставлена галочка про спецсимволы…
        if (document.getElementById('sym').checked) {
          // на каждой третьей итерации вставляем спецсимвол на нужное место
          if (i % 3 == 0) { password += symbols[secnum % 6] }
        }
      }
      // перед тем как мысленно разбивать пароль на тройки, поместим его в промежуточную переменную
      sourcepass = password;
      // обнуляем строку — в неё будем заново собирать наш пароль из троек
      password = '';
      // если наше секретное число больше, чем групп из трёх символов в исходном пароле — прогоняем тройки по кругу, возвращаемся в начало и останавливаемся на нужной позиции
      if (Number(secnum) * 3 > sourcepass.length) { secnum = (Number(secnum) * 3) % sourcepass.length } else { secnum = secnum * 3 };
      // формируем пароль из групп по три символа с разделителем
      for (var i = 1; i < 10; i++) {
        // если после сложения мы превысили длину исходного пароля — возвращаемся в начало, чтобы продолжить на следующем шаге с первого
        if (sourcepass.length == secnum + i) { secnum = -i };
        // добавляем очередной символ в группу из трёх символов
        password += sourcepass[secnum + i];
        // если прошло уже три символа — добавляем разделитель (а после девятого символа — не добавляем)
        if ((i % 3 == 0) && (i % 9 != 0)) { password += '-' };
      }
      // выводим финальный пароль
      document.getElementById('pass_text').innerHTML = password;
    }
  // закончилась скриптовая часть
  </script>
</body>
<!-- конец всей страницы -->

</html>

В финальной статье мы сделаем из этой страницы отдельное приложение, которое можно запустить на компьютере или на телефоне! Подписывайтесь, чтобы не пропустить.

Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Начать карьеру в ИТ
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
Еще по теме
hard