Greasy Fork is available in English.

BugMeNot Everywhere

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

  1. // ==UserScript==
  2. // @name BugMeNot Everywhere
  3. // @namespace StephenP
  4. // @homepage https://greatest.deepsurf.us/scripts/35957/
  5. // @supportURL https://greatest.deepsurf.us/scripts/35957/feedback
  6. // @version 1.2.0
  7. // @description Add a list of login accounts from BugMeNot ( bugmenot.com ) on any website when clicking on password input
  8. // @author StephenP
  9. // @icon http://bugmenot.com/favicon.ico
  10. // @match *://*/*
  11. // @connect bugmenot.com
  12. // @grant GM_addStyle
  13. // @grant GM_xmlhttpRequest
  14. // @grant GM_getValue
  15. // @grant GM_setValue
  16. // @grant GM_registerMenuCommand
  17. // @license GNU GPLv3
  18. // ==/UserScript==
  19.  
  20. /*
  21. Original script by Hồng Minh Tâm (https://greatest.deepsurf.us/users/37096/)
  22. Original script page: https://greatest.deepsurf.us/scripts/35957/
  23. */
  24.  
  25. const inputElsQuery='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"])'
  26. function getLogins() {
  27. 'use strict';
  28.  
  29. const icons = {
  30. username: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 172 172"><path fill="currentColor" d="M114.66667,50.16667c0,15.83216 -12.8345,28.66667 -28.66667,28.66667c-15.83216,0 -28.66667,-12.8345 -28.66667,-28.66667c0,-15.83216 12.8345,-28.66667 28.66667,-28.66667c15.83216,0 28.66667,12.8345 28.66667,28.66667zM86,114.66667c9.374,0 17.62608,-4.56102 22.85775,-11.51986c20.1885,4.472 41.64225,14.27902 41.64225,29.43652v17.91667h-129v-17.91667c0,-15.1575 21.45375,-24.96452 41.64225,-29.43652c5.23167,6.95883 13.48375,11.51986 22.85775,11.51986z"></path></svg>',
  31. password: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 172 172"><path fill="currentColor" d="M50.16667,35.83333c-27.70633,0 -50.16667,22.46033 -50.16667,50.16667c0,27.70633 22.46033,50.16667 50.16667,50.16667c22.72313,0 41.89756,-15.11458 48.06706,-35.83333h30.76628v21.5h28.66667v-21.5h14.33333v-28.66667h-73.76628c-6.1695,-20.71875 -25.34393,-35.83333 -48.06706,-35.83333zM50.16667,64.5c11.87517,0 21.5,9.62483 21.5,21.5c0,11.87517 -9.62483,21.5 -21.5,21.5c-11.87517,0 -21.5,-9.62483 -21.5,-21.5c0,-11.87517 9.62483,-21.5 21.5,-21.5z"></path></svg>',
  32. }
  33.  
  34. GM_addStyle([
  35. '.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; }',
  36. '.bmn-list.show { display:block; }',
  37. '.bmn-list .bmn-row { position: relative; margin: 0 5px 5px 5px; display: -ms-flexbox; display: -webkit-flex; display: flex; }',
  38. '.bmn-list .bmn-row:last-child { margin-bottom: 0; }',
  39. '.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; }',
  40. '.bmn-list .bmn-full { -webkit-flex: 1 0 auto; -ms-flex: 1 0 auto; flex: 1 0 auto; }',
  41. '.bmn-list .bmn-align-items-center { -webkit-align-items: center; -ms-flex-align: center; align-items: center; }',
  42. '.bmn-list .bmn-align-self-center { -webkit-align-self: center; -ms-flex-item-align: center; align-self: center; }',
  43. '.bmn-list .bmn-justify-content-center { -webkit-justify-content: center; -ms-flex-pack: center; justify-content: center; }',
  44. '.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; }',
  45. '.bmn-list .bmn-item:last-child { border-bottom: 0; }',
  46. '.bmn-list .bmn-item:hover { background-color: #f8f9fa; }',
  47. '.bmn-list .bmn-item:before { position: absolute; content: ""; width: 5px; top: 0; left: 0; bottom: 0; background-color: #f7704f; }',
  48. '.bmn-list .bmn-item .bmn-icon { width: 32px; height: 32px; padding: 5px; background-color: #e9ecef; border: 1px solid #ced4da; }',
  49. '.bmn-list .bmn-item .bmn-username { margin-left: 10px; font-weight: 700; }',
  50. '.bmn-list .bmn-item .bmn-password { margin-left: 10px; color: #666; }',
  51. '.bmn-list .bmn-item .bmn-success { display: inline-block; font-weight: 700; }',
  52. '.bmn-list .bmn-item.bmn-success-100 .bmn-success { color: rgb(0,198,0); }',
  53. '.bmn-list .bmn-item.bmn-success-100:before { background-color: rgb(0,198,0); }',
  54. '.bmn-list .bmn-item.bmn-success-90 .bmn-success { color: rgb(50,180,0); }',
  55. '.bmn-list .bmn-item.bmn-success-90:before { background-color: rgb(50,180,0); }',
  56. '.bmn-list .bmn-item.bmn-success-80 .bmn-success { color: rgb(99,164,0); }',
  57. '.bmn-list .bmn-item.bmn-success-80:before { background-color: rgb(99,164,0); }',
  58. '.bmn-list .bmn-item.bmn-success-70 .bmn-success { color: rgb(149,146,0); }',
  59. '.bmn-list .bmn-item.bmn-success-70:before { background-color: rgb(149,146,0); }',
  60. '.bmn-list .bmn-item.bmn-success-60 .bmn-success { color: rgb(199,129,0); }',
  61. '.bmn-list .bmn-item.bmn-success-60:before { background-color: rgb(199,129,0); }',
  62. '.bmn-list .bmn-item.bmn-success-50 .bmn-success { color: rgb(247,112,0); }',
  63. '.bmn-list .bmn-item.bmn-success-50:before { background-color: rgb(247,112,0); }',
  64. '.bmn-list .bmn-item.bmn-success-40 .bmn-success { color: rgb(247,90,0); }',
  65. '.bmn-list .bmn-item.bmn-success-40:before { background-color: rgb(247,90,0); }',
  66. '.bmn-list .bmn-item.bmn-success-30 .bmn-success { color: rgb(247,67,0); }',
  67. '.bmn-list .bmn-item.bmn-success-30:before { background-color: rgb(247,67,0); }',
  68. '.bmn-list .bmn-item.bmn-success-20 .bmn-success { color: rgb(247,45,0); }',
  69. '.bmn-list .bmn-item.bmn-success-20:before { background-color: rgb(247,45,0); }',
  70. '.bmn-list .bmn-item.bmn-success-10 .bmn-success { color: rgb(247,22,0); }',
  71. '.bmn-list .bmn-item.bmn-success-10:before { background-color: rgb(247,22,0); }',
  72. '.bmn-list .bmn-item .bmn-vote { display: inline-block; margin-left: 16px; float: right; }',
  73. '.bmn-list .bmn-no-logins-found { padding: 5px 10px; margin: 0; cursor: default; text-align: center; background-color: #a90000; color: #fff; }',
  74. ].join(''));
  75.  
  76. Object.defineProperty(String.prototype, 'toDOM', {
  77. value: function (isFull) {
  78. var parser = new DOMParser(),
  79. dom = parser.parseFromString(this, 'text/html');
  80. return isFull ? dom : dom.body.childNodes[0];
  81. },
  82. enumerable: false
  83. });
  84.  
  85. function setValueInput(input, value, isInputSimulate) {
  86. var setValue = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
  87. setValue.call(input, value);
  88. if (isInputSimulate) {
  89. var e = new Event('input', {
  90. bubbles: true
  91. });
  92. input.dispatchEvent(e);
  93. }
  94. }
  95.  
  96. function getOffset(element) {
  97. var elementRect = element.getBoundingClientRect();
  98. return {
  99. left: elementRect.left,
  100. right: elementRect.right,
  101. top: elementRect.top,
  102. bottom: elementRect.bottom,
  103. };
  104. }
  105.  
  106. function handleEvent(func, data) {
  107. return function (event) {
  108. func.bind(this)(event, data);
  109. };
  110. }
  111.  
  112. var accounts = [];
  113. var inputUsernameCurrentEl, inputPasswordCurrentEl;
  114. var minHeightListBMN = 100;
  115. GM_xmlhttpRequest({
  116. method: 'GET',
  117. url: 'http://bugmenot.com/view/' + location.hostname,
  118. headers: {
  119. 'Content-Type': 'application/x-www-form-urlencoded'
  120. },
  121. onload: function (response) {
  122. var bmnEl = response.responseText.toDOM(true);
  123. var accountEls = bmnEl.getElementsByClassName('account');
  124. if(accountEls.length>0){
  125. for (var i = 0; i < accountEls.length; i++) {
  126. var accountEl = accountEls[i];
  127. var infoEl = accountEl.getElementsByTagName('kbd');
  128. var statsEl = accountEl.getElementsByClassName('stats')[1].getElementsByTagName('li');
  129. var account = {
  130. username: infoEl[0].innerHTML || '',
  131. password: infoEl[1].innerHTML || '',
  132. success: parseInt(statsEl[0].innerHTML.match(/\d+(?=%)/)[0]),
  133. vote: parseInt(statsEl[1].innerHTML.match(/\d+(?=\svotes)/)[0]),
  134. time: statsEl[2].innerHTML
  135. };
  136. accounts.push(account);
  137. }
  138. console.log(accounts)
  139. init();
  140. }
  141. else{
  142. if(response.responseText.includes("This site has been barred from the bugmenot system.")){
  143. alert("This site has been barred from the bugmenot system.");
  144. changeForThisSite();
  145. }
  146. else{
  147. alert("No accounts available at the moment.");
  148. }
  149. }
  150. },
  151. onerror: function (response) { }
  152. });
  153.  
  154. function init() {
  155. checkAndEventToInput();
  156. var listBMNEl = document.createElement('ul');
  157. listBMNEl.classList.add('bmn-list');
  158. document.body.appendChild(listBMNEl);
  159.  
  160. function showListBMNEl() {
  161. listBMNEl.classList.add('show');
  162. }
  163.  
  164. function hideListBMNEl() {
  165. listBMNEl.classList.remove('show');
  166. }
  167.  
  168. if (accounts.length) {
  169. accounts.forEach(function (account, index) {
  170. var itemBMNEl = document.createElement('li');
  171. itemBMNEl.classList.add('bmn-item');
  172. itemBMNEl.classList.add(getClassSuccess(account.success));
  173. var itemBMNElHTML = [
  174. '<div class="bmn-row">',
  175. ' <div class="bmn-col bmn-full">',
  176. ' <div class="bmn-row bmn-align-items-center">',
  177. ' <div class="bmn-icon">' + icons.username + '</div>',
  178. ' <span class="bmn-username">' + account.username + '</span>',
  179. ' </div>',
  180. ' <div class="bmn-row bmn-align-items-center">',
  181. ' <div class="bmn-icon">' + icons.password + '</div>',
  182. ' <span class="bmn-password">' + account.password + '</span>',
  183. ' </div>',
  184. ' </div>',
  185. ' <div class="bmn-col bmn-align-self-center">',
  186. ' <div class="bmn-success">' + account.success + '%</div>',
  187. ' </div>',
  188. '</div>',
  189. '<div class="bmn-row">',
  190. ' <div class="bmn-vote">' + account.vote + ' votes</div>',
  191. '</div>',
  192. // ',<div class="time">' + account.time + '</div>',
  193. ].join('');
  194. itemBMNEl.innerHTML = itemBMNElHTML;
  195. itemBMNEl.title = [
  196. 'Username: ' + account.username,
  197. 'Password: ' + account.password,
  198. '',
  199. account.success + '% success rate',
  200. account.vote + ' votes',
  201. account.time
  202. ].join('\n');
  203. itemBMNEl.onmousedown = handleEvent(onMouseDownItem);
  204. itemBMNEl.onclick = handleEvent(onClickItem, account);
  205. itemBMNEl.onmouseover = handleEvent(onMouseOverItem, account);
  206. itemBMNEl.onmouseout = handleEvent(onMouseOutItem);
  207. listBMNEl.appendChild(itemBMNEl);
  208. });
  209. } else {
  210. var itemBMNNoLoginsFoundEl = document.createElement('li');
  211. itemBMNNoLoginsFoundEl.classList.add('bmn-no-logins-found');
  212. itemBMNNoLoginsFoundEl.innerHTML = 'No logins found';
  213. listBMNEl.appendChild(itemBMNNoLoginsFoundEl);
  214. }
  215.  
  216. window.onscroll = function (event) {
  217. if (inputUsernameCurrentEl) {
  218. addStyleListBMNEl(inputUsernameCurrentEl);
  219. }
  220. };
  221.  
  222. window.onresize = function (event) {
  223. if (inputUsernameCurrentEl) {
  224. addStyleListBMNEl(inputUsernameCurrentEl);
  225. }
  226. };
  227.  
  228. var enableMouseOut = true;
  229.  
  230. function setValueInputItem(inputUsernameEl, inputPasswordEl, username, password, isInputSimulate) {
  231. // inputUsernameEl.value = username;
  232. // inputPasswordEl.value = password;
  233. setValueInput(inputUsernameEl, username, isInputSimulate);
  234. setValueInput(inputPasswordEl, password, isInputSimulate);
  235. }
  236.  
  237. function onMouseDownItem(event) {
  238. event.preventDefault();
  239. }
  240.  
  241. function onClickItem(event, account) {
  242. event.stopPropagation();
  243. enableMouseOut = false;
  244. if (inputUsernameCurrentEl && inputPasswordCurrentEl) {
  245. setValueInputItem(inputUsernameCurrentEl, inputPasswordCurrentEl, account.username, account.password, true);
  246. inputUsernameCurrentEl.setAttribute('value', account.username);
  247. hideListBMNEl();
  248. }
  249. }
  250.  
  251. function onMouseOverItem(event, account) {
  252. if (inputUsernameCurrentEl && inputPasswordCurrentEl) {
  253. setValueInputItem(inputUsernameCurrentEl, inputPasswordCurrentEl, account.username, account.password);
  254. }
  255. }
  256.  
  257. function onMouseOutItem(event) {
  258. if (!enableMouseOut) {
  259. enableMouseOut = true;
  260. return;
  261. }
  262. if (inputUsernameCurrentEl && inputPasswordCurrentEl) {
  263. setValueInputItem(inputUsernameCurrentEl, inputPasswordCurrentEl, '', '');
  264. }
  265. }
  266.  
  267. function getClassSuccess(success) {
  268. if (success > 91) return 'bmn-success-100';
  269. else if (success > 81) return 'bmn-success-90';
  270. else if (success > 71) return 'bmn-success-80';
  271. else if (success > 61) return 'bmn-success-70';
  272. else if (success > 51) return 'bmn-success-60';
  273. else if (success > 31) return 'bmn-success-50';
  274. else if (success > 21) return 'bmn-success-30';
  275. else if (success > 11) return 'bmn-success-20';
  276. else return 'bmn-success-10';
  277. }
  278.  
  279. function addStyleListBMNEl(inputEl) {
  280. listBMNEl.style.width = inputEl.offsetWidth + 'px';
  281. var offsetTarget = getOffset(inputEl);
  282. var windowHeight = document.documentElement.clientHeight;
  283. if (offsetTarget.top >= minHeightListBMN) {
  284. listBMNEl.style.bottom = (windowHeight - offsetTarget.top) + 'px';
  285. listBMNEl.style.top = '';
  286. listBMNEl.style.left = offsetTarget.left + 'px';
  287. listBMNEl.style.maxHeight = offsetTarget.top + 'px';
  288. } else {
  289. listBMNEl.style.top = offsetTarget.bottom + 'px';
  290. listBMNEl.style.bottom = '';
  291. listBMNEl.style.left = offsetTarget.left + 'px';
  292. listBMNEl.style.maxHeight = (windowHeight - offsetTarget.bottom) + 'px';
  293. }
  294. }
  295.  
  296. function onFocusInput(event, data) {
  297. inputUsernameCurrentEl = data.inputUsernameEl;
  298. inputPasswordCurrentEl = data.inputPasswordEl;
  299. addStyleListBMNEl(inputUsernameCurrentEl);
  300. showListBMNEl();
  301. }
  302.  
  303. function onBlurInput(event) {
  304. if (!event.target.isSameNode(document.activeElement)) {
  305. hideListBMNEl();
  306. }
  307. }
  308.  
  309. function onInputInput(event) {
  310. enableMouseOut = false;
  311. hideListBMNEl();
  312. }
  313.  
  314. function checkAndEventToInput() {
  315. var inputEls = document.querySelectorAll(inputElsQuery);
  316. if (inputEls.length > 1) {
  317. for (var i = 1; i < inputEls.length; i++) {
  318. inputEls[i].dataset.bmnChecked = true;
  319. if (inputEls[i].type === 'password') {
  320. if ((inputEls[i + 1] && inputEls[i + 1].type === 'password')) {
  321. continue;
  322. }
  323.  
  324. if (inputEls[i - 1]) {
  325. if (inputEls[i - 1].type === 'password') {
  326. continue;
  327. } else {
  328. var inputUsernameEl = inputEls[i - 1];
  329. var inputPasswordEl = inputEls[i];
  330. var data = {
  331. inputUsernameEl: inputUsernameEl,
  332. inputPasswordEl: inputPasswordEl
  333. };
  334. inputUsernameEl.onclick = handleEvent(onFocusInput, data);
  335. inputUsernameEl.onfocus = handleEvent(onFocusInput, data);
  336. inputUsernameEl.onblur = handleEvent(onBlurInput);
  337. inputUsernameEl.oninput = handleEvent(onInputInput);
  338. if (inputUsernameEl.isSameNode(document.activeElement)) onFocusInput(undefined, data);
  339. }
  340. }
  341. }
  342. }
  343. }
  344. }
  345.  
  346. var observeDOM = (function () {
  347. var MutationObserver = window.MutationObserver || window.WebKitMutationObserver,
  348. eventListenerSupported = window.addEventListener;
  349.  
  350. return function (obj, callback) {
  351. if (MutationObserver) {
  352. var obs = new MutationObserver(function (mutations, observer) {
  353. if (mutations[0].addedNodes.length || mutations[0].removedNodes.length) {
  354. callback();
  355. }
  356. });
  357. obs.observe(obj, {
  358. childList: true,
  359. subtree: true
  360. });
  361. } else if (eventListenerSupported) {
  362. obj.addEventListener('DOMNodeInserted', callback, false);
  363. obj.addEventListener('DOMNodeRemoved', callback, false);
  364. }
  365. };
  366. })();
  367.  
  368. observeDOM(document, function () {
  369. checkAndEventToInput();
  370. });
  371. }
  372. }
  373. var alreadyRun=false;
  374. var url;
  375. //list of disabled sites (synced with the "disabledSites" list saved with GM_setValue())
  376. var disabledSites=[];
  377. var l;
  378. //localizations in JSON format
  379. const jsonLocalization=JSON.parse(`
  380. {
  381. "en": {
  382. "disableFor": "Disable for ",
  383. "enableFor": "Enable again for ",
  384. "disabledSites": "Disabled sites: ",
  385. "isDisabled": " is currently disabled.",
  386. "isNotDisabled": " isn't currently disabled."
  387. },
  388. "it": {
  389. "disableFor": "Disabilita per ",
  390. "enableFor": "Abilita nuovamente per ",
  391. "disabledSites": "Siti disabilitati: ",
  392. "isDisabled": " è attualmente disabilitato.",
  393. "isNotDisabled": " non è attualmente disabilitato."
  394. }
  395. }
  396. `);
  397.  
  398. //Program start: checks and sets the language, looks for which sites the execution has been disabled and launches the function to add the specific css and js for each site.
  399. (async function(){
  400. let lang=getLang();
  401. if(lang.startsWith("it")){
  402. l=jsonLocalization.it;
  403. }
  404. else{
  405. l=jsonLocalization.en;
  406. }
  407. disabledSites=await getDisabledSites();
  408. if(!disabledSites.includes(document.location.hostname)){
  409. GM_registerMenuCommand(l.disableFor+document.location.hostname, changeForThisSite, "D");
  410. start();
  411. }
  412. else{
  413. GM_registerMenuCommand(l.enableFor+document.location.hostname, changeForThisSite, "E");
  414. }
  415. })();
  416.  
  417.  
  418.  
  419. function start(){
  420. var inputFields=document.querySelectorAll("input[type=password]:not([data-bmn-checked='true']");
  421. for(let iF of inputFields){
  422. iF.addEventListener("click",chooseLogin);
  423. }
  424. }
  425.  
  426. function chooseLogin(){
  427. if(!alreadyRun){
  428. if (confirm("Do you want to use BugMeNot to log in?") == true) {
  429. getLogins();
  430. } else {
  431. if(confirm("Remember this choice for "+window.location.hostname+"?")==true){
  432. changeForThisSite();
  433. }
  434. }
  435. alreadyRun=true;
  436. }
  437. }
  438.  
  439.  
  440.  
  441.  
  442.  
  443.  
  444. function getLang() {
  445. try{
  446. if (navigator.languages != undefined)
  447. return navigator.languages[0];
  448. return navigator.language;
  449. }
  450. catch(e){
  451. return "en"
  452. }
  453. }
  454. async function getDisabledSites(){
  455. var dS=await GM_getValue("disabledSites");
  456. console.log(l.disabledSites+dS);
  457. if(dS){
  458. return dS.split(',');
  459. }
  460. else{
  461. return [];
  462. }
  463. }
  464. //this function switches the setting of a site from enabled to disabled and viceversa
  465. function changeForThisSite(){
  466. let tS=document.location.hostname;
  467. if(disabledSites.includes(tS)){
  468. console.log(tS+l.isDisabled);
  469. var filtered = disabledSites.filter(function(value){
  470. return value !== document.location.hostname;
  471. });
  472. console.log(filtered);
  473. disabledSites=filtered;
  474. GM_setValue("disabledSites",filtered.join(","));
  475. document.location.reload();
  476. }
  477. else if(!disabledSites.includes(tS)){
  478. console.log(tS+l.isNotDisabled);
  479. disabledSites.push(tS);
  480. GM_setValue("disabledSites",disabledSites.join(","));
  481. document.location.reload();
  482. }
  483. }