BugMeNot Everywhere

Add a list of login accounts from BugMeNot ( bugmenot.com ) on any website when focusing on username input

目前为 2018-08-01 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name BugMeNot Everywhere
  3. // @namespace https://greasyfork.org/users/37096/
  4. // @homepage https://greasyfork.org/scripts/35957/
  5. // @supportURL https://greasyfork.org/scripts/35957/feedback
  6. // @version 1.1.0
  7. // @description Add a list of login accounts from BugMeNot ( bugmenot.com ) on any website when focusing on username input
  8. // @author Hồng Minh Tâm
  9. // @icon http://bugmenot.com/favicon.ico
  10. // @include *
  11. // @grant GM_addStyle
  12. // @grant GM_xmlhttpRequest
  13. // @license GPL-3.0
  14. // ==/UserScript==
  15.  
  16. (function () {
  17. 'use strict';
  18. GM_addStyle([
  19. '.bmn-list { display:none; list-style: none; border: 1px solid #ccc; padding: 0; margin: 0; background-color: #fff; position: fixed; cursor: default; z-index: 9999999999; box-sizing: border-box; overflow: auto; text-align: left; }',
  20. '.bmn-list.show { display:block; }',
  21. '.bmn-list .bmn-row { position: relative; margin: 0 5px 5px 5px; display: -ms-flexbox; display: -webkit-flex; display: flex; }',
  22. '.bmn-list .bmn-row:last-child { margin-bottom: 0; }',
  23. '.bmn-list .bmn-col { position: relative; display: -ms-flexbox; display: -webkit-flex; display: flex; -webkit-flex-direction: column; -ms-flex-direction: column; flex-direction: column; }',
  24. '.bmn-list .bmn-full { -webkit-flex: 1 0 auto; -ms-flex: 1 0 auto; flex: 1 0 auto; }',
  25. '.bmn-list .bmn-align-items-center { -webkit-align-items: center; -ms-flex-align: center; align-items: center; }',
  26. '.bmn-list .bmn-align-self-center { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; }',
  27. '.bmn-list .bmn-justify-content-center { -webkit-justify-content: center; -ms-flex-pack: center; justify-content: center; }',
  28. '.bmn-list .bmn-item { position: relative; padding: 5px 2px 5px 7px; margin: 0; cursor: pointer; border-bottom: 1px solid rgba(0,0,0,.125); color: #495057; }',
  29. '.bmn-list .bmn-item:last-child { border-bottom: 0; }',
  30. '.bmn-list .bmn-item:hover { background-color: #f8f9fa; }',
  31. '.bmn-list .bmn-item:before { position: absolute; content: ""; width: 5px; top: 0; left: 0; bottom: 0; background-color: #f7704f; }',
  32. '.bmn-list .bmn-item .bmn-icon { padding: 5px; background-color: #e9ecef; border: 1px solid #ced4da; }',
  33. '.bmn-list .bmn-item .bmn-username { margin-left: 10px; font-weight: 700; }',
  34. '.bmn-list .bmn-item .bmn-password { margin-left: 10px; color: #666; }',
  35. '.bmn-list .bmn-item .bmn-success { display: inline-block; font-weight: 700; }',
  36. '.bmn-list .bmn-item.bmn-success-100 .bmn-success { color: rgb(0,198,0); }',
  37. '.bmn-list .bmn-item.bmn-success-100:before { background-color: rgb(0,198,0); }',
  38. '.bmn-list .bmn-item.bmn-success-90 .bmn-success { color: rgb(50,180,0); }',
  39. '.bmn-list .bmn-item.bmn-success-90:before { background-color: rgb(50,180,0); }',
  40. '.bmn-list .bmn-item.bmn-success-80 .bmn-success { color: rgb(99,164,0); }',
  41. '.bmn-list .bmn-item.bmn-success-80:before { background-color: rgb(99,164,0); }',
  42. '.bmn-list .bmn-item.bmn-success-70 .bmn-success { color: rgb(149,146,0); }',
  43. '.bmn-list .bmn-item.bmn-success-70:before { background-color: rgb(149,146,0); }',
  44. '.bmn-list .bmn-item.bmn-success-60 .bmn-success { color: rgb(199,129,0); }',
  45. '.bmn-list .bmn-item.bmn-success-60:before { background-color: rgb(199,129,0); }',
  46. '.bmn-list .bmn-item.bmn-success-50 .bmn-success { color: rgb(247,112,0); }',
  47. '.bmn-list .bmn-item.bmn-success-50:before { background-color: rgb(247,112,0); }',
  48. '.bmn-list .bmn-item.bmn-success-40 .bmn-success { color: rgb(247,90,0); }',
  49. '.bmn-list .bmn-item.bmn-success-40:before { background-color: rgb(247,90,0); }',
  50. '.bmn-list .bmn-item.bmn-success-30 .bmn-success { color: rgb(247,67,0); }',
  51. '.bmn-list .bmn-item.bmn-success-30:before { background-color: rgb(247,67,0); }',
  52. '.bmn-list .bmn-item.bmn-success-20 .bmn-success { color: rgb(247,45,0); }',
  53. '.bmn-list .bmn-item.bmn-success-20:before { background-color: rgb(247,45,0); }',
  54. '.bmn-list .bmn-item.bmn-success-10 .bmn-success { color: rgb(247,22,0); }',
  55. '.bmn-list .bmn-item.bmn-success-10:before { background-color: rgb(247,22,0); }',
  56. '.bmn-list .bmn-item .bmn-vote { display: inline-block; margin-left: 16px; float: right; }',
  57. '.bmn-list .bmn-no-logins-found { padding: 5px 10px; margin: 0; cursor: default; text-align: center; background-color: #a90000; color: #fff; }',
  58. ].join(''));
  59.  
  60. Object.defineProperty(String.prototype, 'toDOM', {
  61. value: function (isFull) {
  62. var parser = new DOMParser(),
  63. dom = parser.parseFromString(this, 'text/html');
  64. return isFull ? dom : dom.body.childNodes[0];
  65. },
  66. enumerable: false
  67. });
  68.  
  69. function setValueInput(input, value, isInputSimulate) {
  70. var setValue = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
  71. setValue.call(input, value);
  72. if (isInputSimulate) {
  73. var e = new Event('input', {
  74. bubbles: true
  75. });
  76. input.dispatchEvent(e);
  77. }
  78. }
  79.  
  80. function getOffset(element) {
  81. var elementRect = element.getBoundingClientRect();
  82. return {
  83. left: elementRect.left,
  84. right: elementRect.right,
  85. top: elementRect.top,
  86. bottom: elementRect.bottom,
  87. };
  88. }
  89.  
  90. function handleEvent(func, data) {
  91. return function (event) {
  92. func.bind(this)(event, data);
  93. };
  94. }
  95.  
  96. function getIcons8(style, id, size, color) {
  97. return 'https://png.icons8.com/' + style + '/' + size + '/' + color + '/' + id + '.png';
  98. }
  99.  
  100. var accounts = [];
  101. var inputUsernameCurrentEl, inputPasswordCurrentEl;
  102. var minHeightListBMN = 100;
  103.  
  104. GM_xmlhttpRequest({
  105. method: 'GET',
  106. url: 'http://bugmenot.com/view/' + location.hostname,
  107. headers: {
  108. 'Content-Type': 'application/x-www-form-urlencoded'
  109. },
  110. onload: function (response) {
  111. var bmnEl = response.responseText.toDOM(true);
  112. var accountEls = bmnEl.getElementsByClassName('account');
  113. for (var i = 0; i < accountEls.length; i++) {
  114. var accountEl = accountEls[i];
  115. var infoEl = accountEl.getElementsByTagName('kbd');
  116. var statsEl = accountEl.getElementsByClassName('stats')[1].getElementsByTagName('li');
  117. var account = {
  118. username: infoEl[0].innerHTML || '',
  119. password: infoEl[1].innerHTML || '',
  120. success: parseInt(statsEl[0].innerHTML.match(/\d+(?=%)/)[0]),
  121. vote: parseInt(statsEl[1].innerHTML.match(/\d+(?=\svotes)/)[0]),
  122. time: statsEl[2].innerHTML
  123. };
  124. accounts.push(account);
  125. }
  126. init();
  127. },
  128. onerror: function (response) {}
  129. });
  130.  
  131. function init() {
  132. var listBMNEl = document.createElement('ul');
  133. listBMNEl.classList.add('bmn-list');
  134. document.body.appendChild(listBMNEl);
  135.  
  136. function showListBMNEl() {
  137. listBMNEl.classList.add('show');
  138. }
  139.  
  140. function hideListBMNEl() {
  141. listBMNEl.classList.remove('show');
  142. }
  143.  
  144. if (accounts.length) {
  145. accounts.forEach(function (account, index) {
  146. var itemBMNEl = document.createElement('li');
  147. itemBMNEl.classList.add('bmn-item');
  148. itemBMNEl.classList.add(getClassSuccess(account.success));
  149. var itemBMNElHTML = [
  150. '<div class="bmn-row">',
  151. ' <div class="bmn-col bmn-full">',
  152. ' <div class="bmn-row bmn-align-items-center">',
  153. ' <img class="bmn-icon" src="' + getIcons8('material', 'user', 20, '495057') + '" />',
  154. ' <span class="bmn-username">' + account.username + '</span>',
  155. ' </div>',
  156. ' <div class="bmn-row bmn-align-items-center">',
  157. ' <img class="bmn-icon" src="' + getIcons8('material', 'password1', 20, '495057') + '" />',
  158. ' <span class="bmn-password">' + account.password + '</span>',
  159. ' </div>',
  160. ' </div>',
  161. ' <div class="bmn-col bmn-align-self-center">',
  162. ' <div class="bmn-success">' + account.success + '%</div>',
  163. ' </div>',
  164. '</div>',
  165. '<div class="bmn-row">',
  166. ' <div class="bmn-vote">' + account.vote + ' votes</div>',
  167. '</div>',
  168. // ',<div class="time">' + account.time + '</div>',
  169. ].join('');
  170. itemBMNEl.innerHTML = itemBMNElHTML;
  171. itemBMNEl.title = [
  172. 'Username: ' + account.username,
  173. 'Password: ' + account.password,
  174. '',
  175. account.success + '% success rate',
  176. account.vote + ' votes',
  177. account.time
  178. ].join('\n');
  179. itemBMNEl.onmousedown = handleEvent(onMouseDownItem);
  180. itemBMNEl.onclick = handleEvent(onClickItem, account);
  181. itemBMNEl.onmouseover = handleEvent(onMouseOverItem, account);
  182. itemBMNEl.onmouseout = handleEvent(onMouseOutItem);
  183. listBMNEl.appendChild(itemBMNEl);
  184. });
  185. } else {
  186. var itemBMNNoLoginsFoundEl = document.createElement('li');
  187. itemBMNNoLoginsFoundEl.classList.add('bmn-no-logins-found');
  188. itemBMNNoLoginsFoundEl.innerHTML = 'No logins found';
  189. listBMNEl.appendChild(itemBMNNoLoginsFoundEl);
  190. }
  191.  
  192. window.onscroll = function (event) {
  193. if (inputUsernameCurrentEl) {
  194. addStyleListBMNEl(inputUsernameCurrentEl);
  195. }
  196. };
  197.  
  198. window.onresize = function (event) {
  199. if (inputUsernameCurrentEl) {
  200. addStyleListBMNEl(inputUsernameCurrentEl);
  201. }
  202. };
  203.  
  204. var enableMouseOut = true;
  205.  
  206. function setValueInputItem(inputUsernameEl, inputPasswordEl, username, password, isInputSimulate) {
  207. // inputUsernameEl.value = username;
  208. // inputPasswordEl.value = password;
  209. setValueInput(inputUsernameEl, username, isInputSimulate);
  210. setValueInput(inputPasswordEl, password, isInputSimulate);
  211. }
  212.  
  213. function onMouseDownItem(event) {
  214. event.preventDefault();
  215. }
  216.  
  217. function onClickItem(event, account) {
  218. event.stopPropagation();
  219. enableMouseOut = false;
  220. if (inputUsernameCurrentEl && inputPasswordCurrentEl) {
  221. setValueInputItem(inputUsernameCurrentEl, inputPasswordCurrentEl, account.username, account.password, true);
  222. inputUsernameCurrentEl.setAttribute('value', account.username);
  223. hideListBMNEl();
  224. }
  225. }
  226.  
  227. function onMouseOverItem(event, account) {
  228. if (inputUsernameCurrentEl && inputPasswordCurrentEl) {
  229. setValueInputItem(inputUsernameCurrentEl, inputPasswordCurrentEl, account.username, account.password);
  230. }
  231. }
  232.  
  233. function onMouseOutItem(event) {
  234. if (!enableMouseOut) {
  235. enableMouseOut = true;
  236. return;
  237. }
  238. if (inputUsernameCurrentEl && inputPasswordCurrentEl) {
  239. setValueInputItem(inputUsernameCurrentEl, inputPasswordCurrentEl, '', '');
  240. }
  241. }
  242.  
  243. function getClassSuccess(success) {
  244. if (success > 91) return 'bmn-success-100';
  245. else if (success > 81) return 'bmn-success-90';
  246. else if (success > 71) return 'bmn-success-80';
  247. else if (success > 61) return 'bmn-success-70';
  248. else if (success > 51) return 'bmn-success-60';
  249. else if (success > 31) return 'bmn-success-50';
  250. else if (success > 21) return 'bmn-success-30';
  251. else if (success > 11) return 'bmn-success-20';
  252. else return 'bmn-success-10';
  253. }
  254.  
  255. function addStyleListBMNEl(inputEl) {
  256. listBMNEl.style.width = inputEl.offsetWidth + 'px';
  257. var offsetTarget = getOffset(inputEl);
  258. var windowHeight = document.documentElement.clientHeight;
  259. if (offsetTarget.top >= minHeightListBMN) {
  260. listBMNEl.style.bottom = (windowHeight - offsetTarget.top) + 'px';
  261. listBMNEl.style.top = '';
  262. listBMNEl.style.left = offsetTarget.left + 'px';
  263. listBMNEl.style.maxHeight = offsetTarget.top + 'px';
  264. } else {
  265. listBMNEl.style.top = offsetTarget.bottom + 'px';
  266. listBMNEl.style.bottom = '';
  267. listBMNEl.style.left = offsetTarget.left + 'px';
  268. listBMNEl.style.maxHeight = (windowHeight - offsetTarget.bottom) + 'px';
  269. }
  270. }
  271.  
  272. function onFocusInput(event, data) {
  273. inputUsernameCurrentEl = data.inputUsernameEl;
  274. inputPasswordCurrentEl = data.inputPasswordEl;
  275. addStyleListBMNEl(inputUsernameCurrentEl);
  276. showListBMNEl();
  277. }
  278.  
  279. function onBlurInput(event) {
  280. if (!event.target.isSameNode(document.activeElement)) {
  281. hideListBMNEl();
  282. }
  283. }
  284.  
  285. function onInputInput(event) {
  286. enableMouseOut = false;
  287. hideListBMNEl();
  288. }
  289.  
  290. function checkAndEventToInput() {
  291. var inputEls = document.querySelectorAll('input:not([type]):not([data-bmn-checked="true"]), input[type=text]:not([data-bmn-checked="true"]), input[type=email]:not([data-bmn-checked="true"]), input[type=tel]:not([data-bmn-checked="true"]), input[type=password]:not([data-bmn-checked="true"])');
  292. if (inputEls.length > 1) {
  293. for (var i = 1; i < inputEls.length; i++) {
  294. inputEls[i].dataset.bmnChecked = true;
  295. if (inputEls[i].type === 'password') {
  296. if ((inputEls[i + 1] && inputEls[i + 1].type === 'password')) {
  297. continue;
  298. }
  299.  
  300. if (inputEls[i - 1]) {
  301. if (inputEls[i - 1].type === 'password') {
  302. continue;
  303. } else {
  304. var inputUsernameEl = inputEls[i - 1];
  305. var inputPasswordEl = inputEls[i];
  306. var data = {
  307. inputUsernameEl: inputUsernameEl,
  308. inputPasswordEl: inputPasswordEl
  309. };
  310. inputUsernameEl.onclick = handleEvent(onFocusInput, data);
  311. inputUsernameEl.onfocus = handleEvent(onFocusInput, data);
  312. inputUsernameEl.onblur = handleEvent(onBlurInput);
  313. inputUsernameEl.oninput = handleEvent(onInputInput);
  314. if (inputUsernameEl.isSameNode(document.activeElement)) onFocusInput(undefined, data);
  315. }
  316. }
  317. }
  318. }
  319. }
  320. }
  321.  
  322. var observeDOM = (function () {
  323. var MutationObserver = window.MutationObserver || window.WebKitMutationObserver,
  324. eventListenerSupported = window.addEventListener;
  325.  
  326. return function (obj, callback) {
  327. if (MutationObserver) {
  328. var obs = new MutationObserver(function (mutations, observer) {
  329. if (mutations[0].addedNodes.length || mutations[0].removedNodes.length) {
  330. callback();
  331. }
  332. });
  333. obs.observe(obj, {
  334. childList: true,
  335. subtree: true
  336. });
  337. } else if (eventListenerSupported) {
  338. obj.addEventListener('DOMNodeInserted', callback, false);
  339. obj.addEventListener('DOMNodeRemoved', callback, false);
  340. }
  341. };
  342. })();
  343.  
  344. observeDOM(document, function () {
  345. checkAndEventToInput();
  346. });
  347. }
  348. })();