Pull to refresh

Особенность протокол javascript или генерация случайного пароля в закладке браузера

Reading time3 min
Views7.5K
location.href = "javascript:document.body.textContent = '<div>text</div>';"

Вставит строчку как html код:

<div>text</div>

генерация на любом сайте пароля вида:XbD{'|<"]bFyWT49
в буфер обмена в один клик


Вступление


Для создания пароля можно использовать любые ASCII символы в диапазоне 32-126. Включая спецсимволы: "<", ">", "/" и др.
Для удобства генерации пароля создал закладку (bookmark) в бразуре, в которой в url вместо ссылки на страницу использовался протокол javascript.

JS генерирует пароль длиной n из набора доступных ASCII символов и вставляет в документ получившуюся строку с помощью document.body.textContent.

Url закладки
javascript:for(var a=[],i=0;i<95;i++)a.push(String.fromCharCode(32 + i));for(var b="",i=0;i<16;i++)b+=a[Math.floor(Math.random()*95)];document.body.textContent = b;


Более понятный js
document.body.textContent = createPassword();

function createPassword() {
    var PASSWORD_LENGTH = 16;

    var random = Math.random;
    var allowedChars = getAllowedCharsArr();

    for (var password = "", i = 0; i < PASSWORD_LENGTH; i++) {
        var randomIndex = Math.floor(random() * allowedChars.length);
        password += allowedChars[randomIndex]
    }

    return password;
}

function getAllowedCharsArr() {
    var FIRST_ALLOWED_ASCII_CHAR_INDEX = 32;
    var ALLOWED_CHARS_COUNT = 95;

    for (var allowedChars = [], i = 0; i < ALLOWED_CHARS_COUNT; i++) {
        var asciiCode = FIRST_ALLOWED_ASCII_CHAR_INDEX + i;
        var char = String.fromCharCode(asciiCode);
        allowedChars.push(char)
    }

    return allowedChars;
}


Обнаружение ошибки


После некоторого использования закладки заметил, что иногда пароль отображается не полностью, т.е. первые k символов из всех, заранее заданых n. Причем символы не отображаются после "<";

Т.е. если запустить код в консоли браузера, или в script теге html, javascript отработает по спецификации.

document.body.textContent = '<div>text</div>';

вставит строку как plan text:

<div>text</div>


Но если этот же код выполнить в протоколе javascript в документе окажется html элемент (как показано в начале статьи)

Причина


Такое поведение свойственно протоколу javascript и ни как не связно с textContent
Браузер выполнив js вставляет в html результат последнего выражение, т.е.

javascript:document.body.textContent = '<div>text</div>';

вставляет в body plain text,
выражение возвращет строку,
браузер после выполнения протокола получает строку,
которую воспримет как html документ,
и заменяет им текущую страницу с текстом.

обойти данную особенность можно вставив в конце скрипта void (0)
или любое другое выражение, не возвращающее корректного значения (строки, в некоторых браузерах числа)

Заключение


Для себя более удобным стало не вставлять текст в DOM а сразу копировать пароль в буфер обмена.

Закладка
javascript:for(var a=[],i=0;i<95;i++)a.push(String.fromCharCode(32 + i));for(var b="",i=0;i<16;i++)b+=a[Math.floor(Math.random()*95)];var c=document.createElement('input');c.style.opacity=0;document.body.appendChild(c); c.value=b;c.style.position='fixed';c.style.zIndex=1000000;c.focus();c.select(); document.execCommand('Copy');c.remove();


source
copyToClipBoard(createPassword());

function copyToClipBoard(str) {
    var input = document.createElement('textarea');
    document.body.appendChild(input);
    input.value = str;
    input.style.position = 'fixed';
    input.style.zIndex = 1000000;
    input.style.opacity = 0;
    input.focus();
    input.select();
    document.execCommand('Copy');
    input.remove();
}

function createPassword() {
    var PASSWORD_LENGTH = 16;

    var random = Math.random;
    var allowedChars = getAllowedCharsArr();

    for (var password = "", i = 0; i < PASSWORD_LENGTH; i++) {
        var randomIndex = Math.floor(random() * allowedChars.length);
        password += allowedChars[randomIndex]
    }

    return password;
}

function getAllowedCharsArr() {
    var FIRST_ALLOWED_ASCII_CHAR_INDEX = 32;
    var ALLOWED_CHARS_COUNT = 95;

    for (var allowedChars = [], i = 0; i < ALLOWED_CHARS_COUNT; i++) {
        var asciiCode = FIRST_ALLOWED_ASCII_CHAR_INDEX + i;
        var char = String.fromCharCode(asciiCode);
        allowedChars.push(char)
    }

    return allowedChars;
}


Вместо циклов можно использовать Array.map. Кто-то считает, что так элегантнее, кто-то замечает, что это медленнее — это уже дело вкуса.

Альтернатива
javascript:var a = Array.apply(null, Array(127)).map(String.fromCharCode, String).slice(32);var b = Array.apply(null, Array(16)).map(() => a[Math.floor(Math.random() * 95)]).join("");var c = document.createElement('input');document.body.appendChild(c);c.value = b;c.style.position = 'fixed';c.style.zIndex = 1000000;c.style.opacity = 0;c.focus();c.select();document.execCommand('Copy');c.remove();


Вместо закладки можно использовать extenshion: например, chrome — это также дело вкуса.

P.S.: Update после комментария mayorovp, за что ему отдельное спасибо, статья подверглась полному редактированию, но суть и основной материал остался тем же.
Tags:
Hubs:
Total votes 22: ↑15 and ↓7+8
Comments10

Articles