В прошлый раз мы сделали собственный генератор паролей: в него скармливался адрес любого сайта и он выдавал вариант пароля, который можно использовать на этом сайте. Хитрость в том, что благодаря секретному слову и меняющемся адресам можно было сделать пароль уникальным, и никто бы не смог его подобрать по словарю.
В основе генератора лежал алгоритм хеширования — когда любую строку можно зашифровать так, чтобы потом невозможно было восстановить исходный текст. Даёшь ему любой текст, а он тебе что-то такое: 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>
В финальной статье мы сделаем из этой страницы отдельное приложение, которое можно запустить на компьютере или на телефоне! Подписывайтесь, чтобы не пропустить.