Кроссбразуреная, кросплатформенная особенность задания (set) Node.textContent:
Вставит строчку как html код:
Для создания пароля можно использовать любые ASCII символы в диапазоне 32-126. Один из этих символов — знак меньше ("<"). Для удобства генерации пароля создал закладку (bookmark) в бразуре, в которой в url вместо ссылки на страницу используется протокол javascript.
JS генерирует пароль длиной n из набора доступных ASCII символов и вставляет в документ получившуюся строку с помощью document.body.textContent.
После некоторого использования закладки заметил, что иногда пароль отображается не полностью, т.е. первые k символов из всех, заранее заданых n.
После некоторого изучения получил следующий код:
Если его запустить в консоли браузера, или в script теге html, javascript отработает как надо, т.е. вставит строку вместе с символами "<" и ">".
Но если этот же код выполнить в протоколе javascript в документе окажется html элемент:
Причём если сохранить ссылку на переменную:
Текст вставиться как надо:
Не используйте на своих страницах протокол javascript для вставки пользовательского неотформатированного текста через innerText/textContent
Для себя более удобным стало не вставлять текст в DOM а сразу копировать пароль в буффер обмена.
P.S.: Вместо циклов можно использовать Array.map. Кто-то считает, что так элегантнее, кто-то замечает, что это медленнее — это уже дело вкуса.
P.P.S.: Вместо закладки можно использовать extenshion: например, chrome — это также дело вкуса.
Update
Из коментария mayorovp
Происходит данное не из-за работы textContent, а из-за обработки протокола javascript
Браузер выполнив js вставляет в html результат последнего выражение
вернёт строку, которую браузер воспримет как html документ
обойти данную особенность можно вставив в конце скрипта void (0) или любой другое выражение, не возвращающее корректного значения (строки, в некоторых браузерах числа)
<a href="javascript:document.body.textContent = '<div>text</div>';">click</a>
Вставит строчку как html код:
<div>text</div>
Вступление
Для создания пароля можно использовать любые 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.
Изучение
После некоторого изучения получил следующий код:
document.body.textContent = '<div>text</div>';
Если его запустить в консоли браузера, или в script теге html, javascript отработает как надо, т.е. вставит строку вместе с символами "<" и ">".
<div>text</div>
Особенность
Но если этот же код выполнить в протоколе javascript в документе окажется html элемент:
<a href="javascript:document.body.textContent = '<div>text</div>';">click</a>
<div>text</div>
Эфимерность
Причём если сохранить ссылку на переменную:
<a href="javascript:var str='<div>text</div>';document.body.textContent = str;window.test=function(){str}">click</a>
Текст вставиться как надо:
<div>text</div>
Защита
Не используйте на своих страницах протокол javascript для вставки пользовательского неотформатированного текста через innerText/textContent
Решение
Для себя более удобным стало не вставлять текст в 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;
}
P.S.: Вместо циклов можно использовать 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();
P.P.S.: Вместо закладки можно использовать extenshion: например, chrome — это также дело вкуса.
Update
Разоблачение
Из коментария mayorovp
Происходит данное не из-за работы textContent, а из-за обработки протокола javascript
Браузер выполнив js вставляет в html результат последнего выражение
javascript:'<div>text</div>'
вернёт строку, которую браузер воспримет как html документ
обойти данную особенность можно вставив в конце скрипта void (0) или любой другое выражение, не возвращающее корректного значения (строки, в некоторых браузерах числа)
mayorovp
Это связано с тем фактом, что если после схемы
javascript:
указано выражение — его результат будет использован вместо html-кода.К примеру, если написать в адресной строке
javascript:'<div>text</div>'
— результат будет точно таким же. Встречая код видаjavascript:document.body.textContent = '<div>text</div>'
, браузер (Mozilla Firefox — точно, остальные — не знаю) делает две операции:1. Присваивание
document.body.textContent = 'div>text</div>'
2. Замена кода документа на результат вычисленного выражения —
'<div>text</div>'
Кстати, шаг 2 является операцией перехода и отражается в истории (можно вернуться назад) — а первый шаг меняет текущую страницу.
При удаче можно даже увидеть, как одна надпись сменяет другую.
Причем такое «чудо» происходит при любой последовательности операторов, если последний из них является выражением. Чтобы защититься от такой «фичи», можно дописать в конец букмарклета
;void(0)
— в таком случае второго шага не происходит.Nookie-Grey
Да, верно. Ложная тревога. Спасибо за объяснение.
Надо бы статью переписать, а может и удалить, за неимением стержня.
Ну или оставить ради генератора пароля.
Жёлтенько получилось.
Shakirok
Удалять не стоит. Думаю можно просто дополнить статью первым комментарием. Тогда получится довольно познавательно.
denis_g
Не стоит удалять, она в будущем может кому-нибудь очень пригодиться. А первый комментарий действительно стоит добавить в статью.
Nookie-Grey
Добавил. Спасибо хабр-сообществу за столь тёплый приём.
denis_g
А не подскажите, где можно почитать о том, почему происходит шаг 2?
mayorovp
Если бы еще я сам это знал…
Vest
Я тут нагуглил, кажется, некоторое задокументированное поведение. Не судите строго: JavaScript URIs.
eyeless_watcher
Ну это же обычное поведение браузера.
При переходе по ссылке или вбивании чего-нибудь в адресную строку браузер просто берет контент по указанному протоколу (обычно это http(s)://, в данном случае — javascript:) и показывает в окне документа, заменяя его текущее содержимое. Разница лишь в том, как именно получается конечный контент.