PageRenderTime 55ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/authentication_clients/chromeipass.ext/chromeipass.js

https://github.com/eghm/mooltipass
JavaScript | 1839 lines | 1751 code | 74 blank | 14 comment | 114 complexity | c483abd848af92e7bf3073b1a0b25215 MD5 | raw file
  1. // contains already called method names
  2. var _called = {};
  3. chrome.extension.onMessage.addListener(function(req, sender, callback) {
  4. if ('action' in req) {
  5. if(req.action == "fill_user_pass_with_specific_login") {
  6. if(cip.credentials[req.id]) {
  7. var combination = null;
  8. if (cip.u) {
  9. cip.u.val(cip.credentials[req.id].Login);
  10. combination = cipFields.getCombination("username", cip.u);
  11. cip.u.focus();
  12. }
  13. if (cip.p) {
  14. cip.p.val(cip.credentials[req.id].Password);
  15. combination = cipFields.getCombination("password", cip.p);
  16. }
  17. var list = {};
  18. if(cip.fillInStringFields(combination.fields, cip.credentials[req.id].StringFields, list)) {
  19. cipForm.destroy(false, {"password": list.list[0], "username": list.list[1]});
  20. }
  21. }
  22. // wish I could clear out _logins and _u, but a subsequent
  23. // selection may be requested.
  24. }
  25. else if (req.action == "fill_user_pass") {
  26. cip.fillInFromActiveElement(false);
  27. }
  28. else if (req.action == "fill_pass_only") {
  29. cip.fillInFromActiveElementPassOnly(false);
  30. }
  31. else if (req.action == "activate_password_generator") {
  32. cip.initPasswordGenerator(cipFields.getAllFields());
  33. }
  34. else if(req.action == "remember_credentials") {
  35. cip.contextMenuRememberCredentials();
  36. }
  37. else if (req.action == "choose_credential_fields") {
  38. cipDefine.init();
  39. }
  40. else if (req.action == "clear_credentials") {
  41. cipEvents.clearCredentials();
  42. }
  43. else if (req.action == "activated_tab") {
  44. cipEvents.triggerActivatedTab();
  45. }
  46. else if (req.action == "redetect_fields") {
  47. chrome.extension.sendMessage({
  48. "action": "get_settings",
  49. }, function(response) {
  50. cip.settings = response.data;
  51. cip.initCredentialFields(true);
  52. });
  53. }
  54. }
  55. });
  56. // Hotkeys for every page
  57. // ctrl + shift + p = fill only password
  58. // ctrl + shift + u = fill username + password
  59. window.addEventListener("keydown", function(e) {
  60. if (e.ctrlKey && e.shiftKey) {
  61. if (e.keyCode == 80) { // P
  62. e.preventDefault();
  63. cip.fillInFromActiveElementPassOnly(false);
  64. } else if (e.keyCode == 85) { // U
  65. e.preventDefault();
  66. cip.fillInFromActiveElement(false);
  67. }
  68. }
  69. }, false);
  70. function _f(fieldId) {
  71. var field = (fieldId) ? cIPJQ("input[data-cip-id='"+fieldId+"']:first") : [];
  72. return (field.length > 0) ? field : null;
  73. }
  74. function _fs(fieldId) {
  75. var field = (fieldId) ? cIPJQ("input[data-cip-id='"+fieldId+"']:first,select[data-cip-id='"+fieldId+"']:first").first() : [];
  76. return (field.length > 0) ? field : null;
  77. }
  78. var cipAutocomplete = {};
  79. // objects of username + description for autocomplete
  80. cipAutocomplete.elements = [];
  81. cipAutocomplete.init = function(field) {
  82. if(field.hasClass("cip-ui-autocomplete-input")) {
  83. //_f(credentialInputs[i].username).autocomplete("source", autocompleteSource);
  84. field.autocomplete("destroy");
  85. }
  86. field
  87. .autocomplete({
  88. minLength: 0,
  89. source: cipAutocomplete.onSource,
  90. select: cipAutocomplete.onSelect,
  91. open: cipAutocomplete.onOpen
  92. });
  93. field
  94. .click(cipAutocomplete.onClick)
  95. .blur(cipAutocomplete.onBlur)
  96. .focus(cipAutocomplete.onFocus);
  97. }
  98. cipAutocomplete.onClick = function() {
  99. cIPJQ(this).autocomplete("search", cIPJQ(this).val());
  100. }
  101. cipAutocomplete.onOpen = function(event, ui) {
  102. // NOT BEAUTIFUL!
  103. // modifies ALL ui-autocomplete menus of class .cip-ui-menu
  104. cIPJQ("ul.cip-ui-autocomplete.cip-ui-menu").css("z-index", 2147483636);
  105. }
  106. cipAutocomplete.onSource = function (request, callback) {
  107. var matches = cIPJQ.map( cipAutocomplete.elements, function(tag) {
  108. if ( tag.label.toUpperCase().indexOf(request.term.toUpperCase()) === 0 ) {
  109. return tag;
  110. }
  111. });
  112. callback(matches);
  113. }
  114. cipAutocomplete.onSelect = function (e, ui) {
  115. e.preventDefault();
  116. cIPJQ(this).val(ui.item.value);
  117. var fieldId = cipFields.prepareId(cIPJQ(this).attr("data-cip-id"));
  118. var combination = cipFields.getCombination("username", fieldId);
  119. combination.loginId = ui.item.loginId;
  120. cip.fillInCredentials(combination, true, false);
  121. cIPJQ(this).data("fetched", true);
  122. }
  123. cipAutocomplete.onBlur = function() {
  124. if(cIPJQ(this).data("fetched") == true) {
  125. cIPJQ(this).data("fetched", false);
  126. }
  127. else {
  128. var fieldId = cipFields.prepareId(cIPJQ(this).attr("data-cip-id"));
  129. var fields = cipFields.getCombination("username", fieldId);
  130. if(_f(fields.password) && _f(fields.password).data("unchanged") != true && cIPJQ(this).val() != "") {
  131. cip.fillInCredentials(fields, true, true);
  132. }
  133. }
  134. }
  135. cipAutocomplete.onFocus = function() {
  136. cip.u = cIPJQ(this);
  137. if(cIPJQ(this).val() == "") {
  138. cIPJQ(this).autocomplete("search", "");
  139. }
  140. }
  141. var cipPassword = {};
  142. cipPassword.observedIcons = [];
  143. cipPassword.observingLock = false;
  144. cipPassword.init = function() {
  145. if("initPasswordGenerator" in _called) {
  146. return;
  147. }
  148. _called.initPasswordGenerator = true;
  149. window.setInterval(function() {
  150. cipPassword.checkObservedElements();
  151. }, 400);
  152. }
  153. cipPassword.initField = function(field, inputs, pos) {
  154. if(!field || field.length != 1) {
  155. return;
  156. }
  157. if(field.data("cip-password-generator")) {
  158. return;
  159. }
  160. field.data("cip-password-generator", true);
  161. cipPassword.createIcon(field);
  162. cipPassword.createDialog();
  163. var $found = false;
  164. if(inputs) {
  165. for(var i = pos + 1; i < inputs.length; i++) {
  166. if(inputs[i] && inputs[i].attr("type") && inputs[i].attr("type").toLowerCase() == "password") {
  167. field.data("cip-genpw-next-field-id", inputs[i].data("cip-id"));
  168. field.data("cip-genpw-next-is-password-field", (i == 0));
  169. $found = true;
  170. break;
  171. }
  172. }
  173. }
  174. field.data("cip-genpw-next-field-exists", $found);
  175. }
  176. cipPassword.createDialog = function() {
  177. if("passwordCreateDialog" in _called) {
  178. return;
  179. }
  180. _called.passwordCreateDialog = true;
  181. var $dialog = cIPJQ("<div>")
  182. .attr("id", "cip-genpw-dialog");
  183. var $divFloat = cIPJQ("<div>").addClass("cip-genpw-clearfix");
  184. var $btnGenerate = cIPJQ("<button>")
  185. .text("Generate")
  186. .attr("id", "cip-genpw-btn-generate")
  187. .addClass("b2c-btn")
  188. .addClass("b2c-btn-primary")
  189. .addClass("b2c-btn-small")
  190. .css("float", "left")
  191. .click(function(e) {
  192. e.preventDefault();
  193. chrome.extension.sendMessage({
  194. action: "generate_password"
  195. }, cipPassword.callbackGeneratedPassword);
  196. });
  197. $divFloat.append($btnGenerate);
  198. var $btnClipboard = cIPJQ("<button>")
  199. .text("Copy to clipboard")
  200. .attr("id", "cip-genpw-btn-clipboard")
  201. .addClass("b2c-btn")
  202. .addClass("b2c-btn-small")
  203. .css("float", "right")
  204. .click(function(e) {
  205. e.preventDefault();
  206. chrome.extension.sendMessage({
  207. action: "copy_password",
  208. args: [cIPJQ("input#cip-genpw-textfield-password").val()]
  209. }, cipPassword.callbackPasswordCopied);
  210. });
  211. $divFloat.append($btnClipboard);
  212. $dialog.append($divFloat);
  213. var $textfieldPassword = cIPJQ("<input>")
  214. .attr("id", "cip-genpw-textfield-password")
  215. .attr("type", "text")
  216. .addClass("cip-genpw-textfield")
  217. .on('change keypress paste textInput input', function() {
  218. cIPJQ("#cip-genpw-btn-clipboard:first").removeClass("b2c-btn-success");
  219. });
  220. var $quality = cIPJQ("<span>")
  221. .addClass("b2c-add-on")
  222. .attr("id", "cip-genpw-quality")
  223. .text("123 Bits");
  224. var $frameInputAppend = cIPJQ("<div>")
  225. .addClass("b2c-input-append")
  226. .addClass("cip-genpw-password-frame");
  227. $frameInputAppend.append($textfieldPassword).append($quality);
  228. $dialog.append($frameInputAppend);
  229. var $checkboxNextField = cIPJQ("<input>")
  230. .attr("id", "cip-genpw-checkbox-next-field")
  231. .attr("type", "checkbox")
  232. .addClass("cip-genpw-checkbox");
  233. var $labelNextField = cIPJQ("<label>")
  234. .append($checkboxNextField)
  235. .addClass("cip-genpw-label")
  236. .append(" also fill in the next password-field");
  237. $dialog.append($labelNextField);
  238. var $btnFillIn = cIPJQ("<button>")
  239. .text("Fill in & copy to clipboard")
  240. .attr("id", "cip-genpw-btn-fillin")
  241. .addClass("b2c-btn")
  242. .addClass("b2c-btn-small")
  243. .click(function(e) {
  244. e.preventDefault();
  245. var fieldId = cIPJQ("#cip-genpw-dialog:first").data("cip-genpw-field-id");
  246. var field = cIPJQ("input[data-cip-id='"+fieldId+"']:first");
  247. if(field.length == 1) {
  248. var $password = cIPJQ("input#cip-genpw-textfield-password:first").val();
  249. if(field.attr("maxlength")) {
  250. if($password.length > field.attr("maxlength")) {
  251. $password = $password.substring(0, field.attr("maxlength"));
  252. cIPJQ("input#cip-genpw-textfield-password:first").val($password);
  253. cIPJQ("#cip-genpw-btn-clipboard:first").removeClass("b2c-btn-success");
  254. alert("The generated password is longer than the allowed length!\nIt has been cut to fit the length.\n\nPlease remember the new password!");
  255. }
  256. }
  257. field.val($password);
  258. if(cIPJQ("input#cip-genpw-checkbox-next-field:checked").length == 1) {
  259. if(field.data("cip-genpw-next-field-exists")) {
  260. var nextFieldId = field.data("cip-genpw-next-field-id");
  261. var nextField = cIPJQ("input[data-cip-id='"+nextFieldId+"']:first");
  262. if(nextField.length == 1) {
  263. nextField.val($password);
  264. }
  265. }
  266. }
  267. // copy password to clipboard
  268. chrome.extension.sendMessage({
  269. action: "copy_password",
  270. args: [$password]
  271. }, cipPassword.callbackPasswordCopied);
  272. }
  273. });
  274. $dialog.append($btnFillIn);
  275. $dialog.hide();
  276. cIPJQ("body").append($dialog);
  277. $dialog.dialog({
  278. closeText: "×",
  279. autoOpen: false,
  280. modal: true,
  281. resizable: false,
  282. minWidth: 340,
  283. title: "Password Generator",
  284. open: function(event, ui) {
  285. cIPJQ(".cip-ui-widget-overlay").click(function() {
  286. cIPJQ("#cip-genpw-dialog:first").dialog("close");
  287. });
  288. if(cIPJQ("input#cip-genpw-textfield-password:first").val() == "") {
  289. cIPJQ("button#cip-genpw-btn-generate:first").click();
  290. }
  291. }
  292. });
  293. }
  294. cipPassword.createIcon = function(field) {
  295. var $className = (field.outerHeight() > 28) ? "cip-icon-key-big" : "cip-icon-key-small";
  296. var $size = (field.outerHeight() > 28) ? 24 : 16;
  297. var $offset = Math.floor((field.outerHeight() - $size) / 3);
  298. $offset = ($offset < 0) ? 0 : $offset;
  299. var $zIndex = 0;
  300. var $zIndexField = field;
  301. var z;
  302. var c = 0;
  303. while($zIndexField.length > 0) {
  304. z = $zIndexField.css("z-index");
  305. if(!isNaN(z) && parseInt(z) > $zIndex) {
  306. $zIndex = parseInt(z);
  307. }
  308. $zIndexField = $zIndexField.parent();
  309. if(c > 100) {
  310. break;
  311. }
  312. c++;
  313. }
  314. if(isNaN($zIndex) || $zIndex < 1) {
  315. $zIndex = 1;
  316. }
  317. $zIndex += 1;
  318. var $icon = cIPJQ("<div>").addClass("cip-genpw-icon")
  319. .addClass($className)
  320. .css("z-index", $zIndex)
  321. .data("size", $size)
  322. .data("offset", $offset)
  323. .data("cip-genpw-field-id", field.data("cip-id"));
  324. cipPassword.setIconPosition($icon, field);
  325. $icon.click(function(e) {
  326. e.preventDefault();
  327. if(!field.is(":visible")) {
  328. $icon.remove();
  329. field.removeData("cip-password-generator");
  330. return;
  331. }
  332. var $dialog = cIPJQ("#cip-genpw-dialog");
  333. if($dialog.dialog("isOpen")) {
  334. $dialog.dialog("close");
  335. }
  336. $dialog.dialog("option", "position", { my: "left-10px top", at: "center bottom", of: cIPJQ(this) });
  337. $dialog.data("cip-genpw-field-id", field.data("cip-id"));
  338. $dialog.data("cip-genpw-next-field-id", field.data("cip-genpw-next-field-id"));
  339. $dialog.data("cip-genpw-next-is-password-field", field.data("cip-genpw-next-is-password-field"));
  340. var $bool = Boolean(field.data("cip-genpw-next-field-exists"));
  341. cIPJQ("input#cip-genpw-checkbox-next-field:first")
  342. .attr("checked", $bool)
  343. .attr("disabled", !$bool);
  344. $dialog.dialog("open");
  345. });
  346. cipPassword.observedIcons.push($icon);
  347. cIPJQ("body").append($icon);
  348. }
  349. cipPassword.setIconPosition = function($icon, $field) {
  350. $icon.css("top", $field.offset().top + $icon.data("offset") + 1)
  351. .css("left", $field.offset().left + $field.outerWidth() - $icon.data("size") - $icon.data("offset"))
  352. }
  353. cipPassword.callbackPasswordCopied = function(bool) {
  354. if(bool) {
  355. cIPJQ("#cip-genpw-btn-clipboard").addClass("b2c-btn-success");
  356. }
  357. }
  358. cipPassword.callbackGeneratedPassword = function(entries) {
  359. if(entries && entries.length >= 1) {
  360. console.log(entries[0]);
  361. cIPJQ("#cip-genpw-btn-clipboard:first").removeClass("b2c-btn-success");
  362. cIPJQ("input#cip-genpw-textfield-password:first").val(entries[0].Password);
  363. if(isNaN(entries[0].Login)) {
  364. cIPJQ("#cip-genpw-quality:first").text("??? Bits");
  365. }
  366. else {
  367. cIPJQ("#cip-genpw-quality:first").text(entries[0].Login + " Bits");
  368. }
  369. }
  370. else {
  371. if(cIPJQ("div#cip-genpw-error:first").length == 0) {
  372. cIPJQ("button#cip-genpw-btn-generate:first").after("<div style='block' id='cip-genpw-error'>Cannot receive generated password.<br />Is your version of KeePassHttp up-to-date?<br /><br /><a href='https://github.com/pfn/keepasshttp/'>Please visit the KeePassHttp homepage</a></div>");
  373. cIPJQ("input#cip-genpw-textfield-password:first").parent().hide();
  374. cIPJQ("input#cip-genpw-checkbox-next-field:first").parent("label").hide();
  375. cIPJQ("button#cip-genpw-btn-generate").hide();
  376. cIPJQ("button#cip-genpw-btn-clipboard").hide();
  377. cIPJQ("button#cip-genpw-btn-fillin").hide();
  378. }
  379. }
  380. }
  381. cipPassword.onRequestPassword = function() {
  382. chrome.extension.sendMessage({
  383. 'action': 'generate_password'
  384. }, cipPassword.callbackGeneratedPassword);
  385. }
  386. cipPassword.checkObservedElements = function() {
  387. if(cipPassword.observingLock) {
  388. return;
  389. }
  390. cipPassword.observingLock = true;
  391. cIPJQ.each(cipPassword.observedIcons, function(index, iconField) {
  392. if(iconField && iconField.length == 1) {
  393. var fieldId = iconField.data("cip-genpw-field-id");
  394. var field = cIPJQ("input[data-cip-id='"+fieldId+"']:first");
  395. if(!field || field.length != 1) {
  396. iconField.remove();
  397. cipPassword.observedIcons.splice(index, 1);
  398. }
  399. else if(!field.is(":visible")) {
  400. iconField.hide();
  401. //field.removeData("cip-password-generator");
  402. }
  403. else if(field.is(":visible")) {
  404. iconField.show();
  405. cipPassword.setIconPosition(iconField, field);
  406. field.data("cip-password-generator", true);
  407. }
  408. }
  409. else {
  410. cipPassword.observedIcons.splice(index, 1);
  411. }
  412. });
  413. cipPassword.observingLock = false;
  414. }
  415. var cipForm = {};
  416. cipForm.init = function(form, credentialFields) {
  417. // TODO: could be called multiple times --> update credentialFields
  418. // not already initialized && password-field is not null
  419. if(!form.data("cipForm-initialized") && credentialFields.password) {
  420. form.data("cipForm-initialized", true);
  421. cipForm.setInputFields(form, credentialFields);
  422. form.submit(cipForm.onSubmit);
  423. }
  424. }
  425. cipForm.destroy = function(form, credentialFields) {
  426. if(form === false && credentialFields) {
  427. var field = _f(credentialFields.password) || _f(credentialFields.username);
  428. if(field) {
  429. form = field.closest("form");
  430. }
  431. }
  432. if(form && cIPJQ(form).length > 0) {
  433. cIPJQ(form).unbind('submit', cipForm.onSubmit);
  434. }
  435. }
  436. cipForm.setInputFields = function(form, credentialFields) {
  437. form.data("cipUsername", credentialFields.username);
  438. form.data("cipPassword", credentialFields.password);
  439. }
  440. cipForm.onSubmit = function(event) {
  441. var usernameId = cIPJQ(this).data("cipUsername");
  442. var passwordId = cIPJQ(this).data("cipPassword");
  443. var usernameValue = "";
  444. var passwordValue = "";
  445. var usernameField = _f(usernameId);
  446. var passwordField = _f(passwordId);
  447. if(usernameField) {
  448. usernameValue = usernameField.val();
  449. console.log('submit: username "'+usernameValue);
  450. }
  451. if(passwordField) {
  452. passwordValue = passwordField.val();
  453. console.log('submit: password');
  454. }
  455. cip.rememberCredentials(event, usernameField, usernameValue, passwordField, passwordValue);
  456. };
  457. var cipDefine = {};
  458. cipDefine.selection = {
  459. "username": null,
  460. "password": null,
  461. "fields": {}
  462. };
  463. cipDefine.eventFieldClick = null;
  464. cipDefine.init = function () {
  465. var $backdrop = cIPJQ("<div>").attr("id", "b2c-backdrop").addClass("b2c-modal-backdrop");
  466. cIPJQ("body").append($backdrop);
  467. var $chooser = cIPJQ("<div>").attr("id", "b2c-cipDefine-fields");
  468. cIPJQ("body").append($chooser);
  469. var $description = cIPJQ("<div>").attr("id", "b2c-cipDefine-description");
  470. $backdrop.append($description);
  471. cipFields.getAllFields();
  472. cipFields.prepareVisibleFieldsWithID("select");
  473. cipDefine.initDescription();
  474. cipDefine.resetSelection();
  475. cipDefine.prepareStep1();
  476. cipDefine.markAllUsernameFields($chooser);
  477. }
  478. cipDefine.initDescription = function() {
  479. var $description = cIPJQ("div#b2c-cipDefine-description");
  480. var $h1 = cIPJQ("<div>").addClass("b2c-chooser-headline");
  481. $description.append($h1);
  482. var $help = cIPJQ("<div>").addClass("b2c-chooser-help").attr("id", "b2c-help");
  483. $description.append($help);
  484. var $btnDismiss = cIPJQ("<button>").text("Dismiss").attr("id", "b2c-btn-dismiss")
  485. .addClass("b2c-btn").addClass("b2c-btn-danger")
  486. .click(function(e) {
  487. cIPJQ("div#b2c-backdrop").remove();
  488. cIPJQ("div#b2c-cipDefine-fields").remove();
  489. });
  490. var $btnSkip = cIPJQ("<button>").text("Skip").attr("id", "b2c-btn-skip")
  491. .addClass("b2c-btn").addClass("b2c-btn-info")
  492. .css("margin-right", "5px")
  493. .click(function() {
  494. if(cIPJQ(this).data("step") == 1) {
  495. cipDefine.selection.username = null;
  496. cipDefine.prepareStep2();
  497. cipDefine.markAllPasswordFields(cIPJQ("#b2c-cipDefine-fields"));
  498. }
  499. else if(cIPJQ(this).data("step") == 2) {
  500. cipDefine.selection.password = null;
  501. cipDefine.prepareStep3();
  502. cipDefine.markAllStringFields(cIPJQ("#b2c-cipDefine-fields"));
  503. }
  504. });
  505. var $btnAgain = cIPJQ("<button>").text("Again").attr("id", "b2c-btn-again")
  506. .addClass("b2c-btn").addClass("b2c-btn-warning")
  507. .css("margin-right", "5px")
  508. .click(function(e) {
  509. cipDefine.resetSelection();
  510. cipDefine.prepareStep1();
  511. cipDefine.markAllUsernameFields(cIPJQ("#b2c-cipDefine-fields"));
  512. })
  513. .hide();
  514. var $btnConfirm = cIPJQ("<button>").text("Confirm").attr("id", "b2c-btn-confirm")
  515. .addClass("b2c-btn").addClass("b2c-btn-primary")
  516. .css("margin-right", "15px")
  517. .click(function(e) {
  518. if(!cip.settings["defined-credential-fields"]) {
  519. cip.settings["defined-credential-fields"] = {};
  520. }
  521. if(cipDefine.selection.username) {
  522. cipDefine.selection.username = cipFields.prepareId(cipDefine.selection.username);
  523. }
  524. var passwordId = cIPJQ("div#b2c-cipDefine-fields").data("password");
  525. if(cipDefine.selection.password) {
  526. cipDefine.selection.password = cipFields.prepareId(cipDefine.selection.password);
  527. }
  528. var fieldIds = [];
  529. var fieldKeys = Object.keys(cipDefine.selection.fields);
  530. for(var i = 0; i < fieldKeys.length; i++) {
  531. fieldIds.push(cipFields.prepareId(fieldKeys[i]));
  532. }
  533. cip.settings["defined-credential-fields"][document.location.origin] = {
  534. "username": cipDefine.selection.username,
  535. "password": cipDefine.selection.password,
  536. "fields": fieldIds
  537. };
  538. chrome.extension.sendMessage({
  539. action: 'save_settings',
  540. args: [cip.settings]
  541. });
  542. cIPJQ("button#b2c-btn-dismiss").click();
  543. })
  544. .hide();
  545. $description.append($btnConfirm);
  546. $description.append($btnSkip);
  547. $description.append($btnAgain);
  548. $description.append($btnDismiss);
  549. if(cip.settings["defined-credential-fields"] && cip.settings["defined-credential-fields"][document.location.origin]) {
  550. var $p = cIPJQ("<p>").html("For this page credential fields are already selected and will be overwritten.<br />");
  551. var $btnDiscard = cIPJQ("<button>")
  552. .attr("id", "b2c-btn-discard")
  553. .text("Discard selection")
  554. .css("margin-top", "5px")
  555. .addClass("b2c-btn")
  556. .addClass("b2c-btn-small")
  557. .addClass("b2c-btn-danger")
  558. .click(function(e) {
  559. delete cip.settings["defined-credential-fields"][document.location.origin];
  560. chrome.extension.sendMessage({
  561. action: 'save_settings',
  562. args: [cip.settings]
  563. });
  564. chrome.extension.sendMessage({
  565. action: 'load_settings'
  566. });
  567. cIPJQ(this).parent("p").remove();
  568. });
  569. $p.append($btnDiscard);
  570. $description.append($p);
  571. }
  572. cIPJQ("div#b2c-cipDefine-description").draggable();
  573. }
  574. cipDefine.resetSelection = function() {
  575. cipDefine.selection = {
  576. username: null,
  577. password: null,
  578. fields: {}
  579. };
  580. }
  581. cipDefine.isFieldSelected = function($cipId) {
  582. return (
  583. $cipId == cipDefine.selection.username ||
  584. $cipId == cipDefine.selection.password ||
  585. $cipId in cipDefine.selection.fields
  586. );
  587. }
  588. cipDefine.markAllUsernameFields = function($chooser) {
  589. cipDefine.eventFieldClick = function(e) {
  590. cipDefine.selection.username = cIPJQ(this).data("cip-id");
  591. cIPJQ(this).addClass("b2c-fixed-username-field").text("Username").unbind("click");
  592. cipDefine.prepareStep2();
  593. cipDefine.markAllPasswordFields(cIPJQ("#b2c-cipDefine-fields"));
  594. };
  595. cipDefine.markFields($chooser, cipFields.inputQueryPattern);
  596. }
  597. cipDefine.markAllPasswordFields = function($chooser) {
  598. cipDefine.eventFieldClick = function(e) {
  599. cipDefine.selection.password = cIPJQ(this).data("cip-id");
  600. cIPJQ(this).addClass("b2c-fixed-password-field").text("Password").unbind("click");
  601. cipDefine.prepareStep3();
  602. cipDefine.markAllStringFields(cIPJQ("#b2c-cipDefine-fields"));
  603. };
  604. cipDefine.markFields($chooser, "input[type='password']");
  605. }
  606. cipDefine.markAllStringFields = function($chooser) {
  607. cipDefine.eventFieldClick = function(e) {
  608. cipDefine.selection.fields[cIPJQ(this).data("cip-id")] = true;
  609. var count = Object.keys(cipDefine.selection.fields).length;
  610. cIPJQ(this).addClass("b2c-fixed-string-field").text("String field #"+count.toString()).unbind("click");
  611. cIPJQ("button#b2c-btn-confirm:first").addClass("b2c-btn-primary").attr("disabled", false);
  612. };
  613. cipDefine.markFields($chooser, cipFields.inputQueryPattern + ", select");
  614. }
  615. cipDefine.markFields = function ($chooser, $pattern) {
  616. //var $found = false;
  617. cIPJQ($pattern).each(function() {
  618. if(cipDefine.isFieldSelected(cIPJQ(this).data("cip-id"))) {
  619. //continue
  620. return true;
  621. }
  622. if(cIPJQ(this).is(":visible") && cIPJQ(this).css("visibility") != "hidden" && cIPJQ(this).css("visibility") != "collapsed") {
  623. var $field = cIPJQ("<div>").addClass("b2c-fixed-field")
  624. .css("top", cIPJQ(this).offset().top)
  625. .css("left", cIPJQ(this).offset().left)
  626. .css("width", cIPJQ(this).outerWidth())
  627. .css("height", cIPJQ(this).outerHeight())
  628. .attr("data-cip-id", cIPJQ(this).attr("data-cip-id"))
  629. .click(cipDefine.eventFieldClick)
  630. .hover(function() {cIPJQ(this).addClass("b2c-fixed-hover-field");}, function() {cIPJQ(this).removeClass("b2c-fixed-hover-field");});
  631. $chooser.append($field);
  632. //$found = true;
  633. }
  634. });
  635. /* skip step if no entry was found
  636. if(!$found) {
  637. alert("No username field found.\nContinue with choosing a password field.");
  638. cIPJQ("button#b2c-btn-skip").click();
  639. }
  640. */
  641. }
  642. cipDefine.prepareStep1 = function() {
  643. cIPJQ("div#b2c-help").text("").css("margin-bottom", 0);
  644. cIPJQ("div#b2c-cipDefine-fields").removeData("username");
  645. cIPJQ("div#b2c-cipDefine-fields").removeData("password");
  646. cIPJQ("div.b2c-fixed-field", cIPJQ("div#b2c-cipDefine-fields")).remove();
  647. cIPJQ("div:first", cIPJQ("div#b2c-cipDefine-description")).text("1. Choose a username field");
  648. cIPJQ("button#b2c-btn-skip:first").data("step", "1").show();
  649. cIPJQ("button#b2c-btn-confirm:first").hide();
  650. cIPJQ("button#b2c-btn-again:first").hide();
  651. }
  652. cipDefine.prepareStep2 = function() {
  653. cIPJQ("div#b2c-help").text("").css("margin-bottom", 0);
  654. cIPJQ("div.b2c-fixed-field:not(.b2c-fixed-username-field)", cIPJQ("div#b2c-cipDefine-fields")).remove();
  655. cIPJQ("div:first", cIPJQ("div#b2c-cipDefine-description")).text("2. Now choose a password field");
  656. cIPJQ("button#b2c-btn-skip:first").data("step", "2");
  657. cIPJQ("button#b2c-btn-again:first").show();
  658. }
  659. cipDefine.prepareStep3 = function() {
  660. /* skip step if no entry was found
  661. if(!cIPJQ("div#b2c-cipDefine-fields").data("username") && !cIPJQ("div#b2c-cipDefine-fields").data("password")) {
  662. alert("Neither an username field nor a password field were selected.\nNothing will be changed and chooser will be closed now.");
  663. cIPJQ("button#b2c-btn-dismiss").click();
  664. return;
  665. }
  666. */
  667. if(!cipDefine.selection.username && !cipDefine.selection.password) {
  668. cIPJQ("button#b2c-btn-confirm:first").removeClass("b2c-btn-primary").attr("disabled", true);
  669. }
  670. cIPJQ("div#b2c-help").html("Please confirm your selection or choose more fields as <em>String fields</em>.").css("margin-bottom", "5px");
  671. cIPJQ("div.b2c-fixed-field:not(.b2c-fixed-password-field,.b2c-fixed-username-field)", cIPJQ("div#b2c-cipDefine-fields")).remove();
  672. cIPJQ("button#b2c-btn-confirm:first").show();
  673. cIPJQ("button#b2c-btn-skip:first").data("step", "3").hide();
  674. cIPJQ("div:first", cIPJQ("div#b2c-cipDefine-description")).text("3. Confirm selection");
  675. }
  676. cipFields = {}
  677. cipFields.inputQueryPattern = "input[type='text'], input[type='email'], input[type='password'], input:not([type])";
  678. // unique number as new IDs for input fields
  679. cipFields.uniqueNumber = 342845638;
  680. // objects with combination of username + password fields
  681. cipFields.combinations = [];
  682. cipFields.setUniqueId = function(field) {
  683. if(field && !field.attr("data-cip-id")) {
  684. // use ID of field if it is unique
  685. // yes, it should be, but there are many bad developers outside...
  686. var fieldId = field.attr("id");
  687. if(fieldId) {
  688. var foundIds = cIPJQ("input#" + cipFields.prepareId(fieldId));
  689. if(foundIds.length == 1) {
  690. field.attr("data-cip-id", fieldId);
  691. return;
  692. }
  693. }
  694. // create own ID if no ID is set for this field
  695. cipFields.uniqueNumber += 1;
  696. field.attr("data-cip-id", "cIPJQ"+String(cipFields.uniqueNumber));
  697. }
  698. }
  699. cipFields.prepareId = function(id) {
  700. id = id.replace(":", "\\:")
  701. .replace("#", "\\#")
  702. .replace(".", "\\.")
  703. .replace(",", "\\,")
  704. .replace("[", "\\[")
  705. .replace("]", "\\]")
  706. .replace("(", "\\(")
  707. .replace(")", "\\)")
  708. .replace("'", "\\'")
  709. .replace(" ", "\\ ")
  710. .replace("\"", "\\\"");
  711. return id;
  712. }
  713. cipFields.getAllFields = function() {
  714. var fields = [];
  715. // get all input fields which are text, email or password and visible
  716. cIPJQ(cipFields.inputQueryPattern).each(function() {
  717. if(cIPJQ(this).is(":visible") && cIPJQ(this).css("visibility") != "hidden" && cIPJQ(this).css("visibility") != "collapsed") {
  718. cipFields.setUniqueId(cIPJQ(this));
  719. fields.push(cIPJQ(this));
  720. }
  721. });
  722. return fields;
  723. }
  724. cipFields.prepareVisibleFieldsWithID = function($pattern) {
  725. cIPJQ($pattern).each(function() {
  726. if(cIPJQ(this).is(":visible") && cIPJQ(this).css("visibility") != "hidden" && cIPJQ(this).css("visibility") != "collapsed") {
  727. cipFields.setUniqueId(cIPJQ(this));
  728. }
  729. });
  730. }
  731. cipFields.getAllCombinations = function(inputs) {
  732. var fields = [];
  733. var uField = null;
  734. for(var i = 0; i < inputs.length; i++) {
  735. if(!inputs[i] || inputs[i].length < 1) {
  736. continue;
  737. }
  738. if(inputs[i].attr("type") && inputs[i].attr("type").toLowerCase() == "password") {
  739. var uId = (!uField || uField.length < 1) ? null : cipFields.prepareId(uField.attr("data-cip-id"));
  740. var combination = {
  741. "username": uId,
  742. "password": cipFields.prepareId(inputs[i].attr("data-cip-id"))
  743. };
  744. fields.push(combination);
  745. // reset selected username field
  746. uField = null;
  747. }
  748. else {
  749. // username field
  750. uField = inputs[i];
  751. }
  752. }
  753. return fields;
  754. }
  755. cipFields.getCombination = function(givenType, fieldId) {
  756. if(cipFields.combinations.length == 0) {
  757. if(cipFields.useDefinedCredentialFields()) {
  758. return cipFields.combinations[0];
  759. }
  760. }
  761. // use defined credential fields (already loaded into combinations)
  762. if(cip.settings["defined-credential-fields"] && cip.settings["defined-credential-fields"][document.location.origin]) {
  763. return cipFields.combinations[0];
  764. }
  765. for(var i = 0; i < cipFields.combinations.length; i++) {
  766. if(cipFields.combinations[i][givenType] == fieldId) {
  767. return cipFields.combinations[i];
  768. }
  769. }
  770. // find new combination
  771. var combination = {
  772. "username": null,
  773. "password": null
  774. };
  775. var newCombi = false;
  776. if(givenType == "username") {
  777. var passwordField = cipFields.getPasswordField(fieldId, true);
  778. var passwordId = null;
  779. if(passwordField && passwordField.length > 0) {
  780. passwordId = cipFields.prepareId(passwordField.attr("data-cip-id"));
  781. }
  782. combination = {
  783. "username": fieldId,
  784. "password": passwordId
  785. };
  786. newCombi = true;
  787. }
  788. else if(givenType == "password") {
  789. var usernameField = cipFields.getUsernameField(fieldId, true);
  790. var usernameId = null;
  791. if(usernameField && usernameField.length > 0) {
  792. usernameId = cipFields.prepareId(usernameField.attr("data-cip-id"));
  793. }
  794. combination = {
  795. "username": usernameId,
  796. "password": fieldId
  797. };
  798. newCombi = true;
  799. }
  800. if(combination.username || combination.password) {
  801. cipFields.combinations.push(combination);
  802. }
  803. if(combination.username) {
  804. if(cip.credentials.length > 1) {
  805. cip.preparePageForMultipleCredentials(cip.credentials);
  806. }
  807. }
  808. if(newCombi) {
  809. combination.isNew = true;
  810. }
  811. return combination;
  812. }
  813. /**
  814. * return the username field or null if it not exists
  815. */
  816. cipFields.getUsernameField = function(passwordId, checkDisabled) {
  817. var passwordField = _f(passwordId);
  818. if(!passwordField) {
  819. return null;
  820. }
  821. var form = passwordField.closest("form")[0];
  822. var usernameField = null;
  823. // search all inputs on this one form
  824. if(form) {
  825. cIPJQ(cipFields.inputQueryPattern, form).each(function() {
  826. cipFields.setUniqueId(cIPJQ(this));
  827. if(cIPJQ(this).attr("data-cip-id") == passwordId) {
  828. // break
  829. return false;
  830. }
  831. if(cIPJQ(this).attr("type") && cIPJQ(this).attr("type").toLowerCase() == "password") {
  832. // continue
  833. return true;
  834. }
  835. usernameField = cIPJQ(this);
  836. });
  837. }
  838. // search all inputs on page
  839. else {
  840. var inputs = cipFields.getAllFields();
  841. cip.initPasswordGenerator(inputs);
  842. for(var i = 0; i < inputs.length; i++) {
  843. if(inputs[i].attr("data-cip-id") == passwordId) {
  844. break;
  845. }
  846. if(inputs[i].attr("type") && inputs[i].attr("type").toLowerCase() == "password") {
  847. continue;
  848. }
  849. usernameField = inputs[i];
  850. }
  851. }
  852. if(usernameField && !checkDisabled) {
  853. var usernameId = usernameField.attr("data-cip-id");
  854. // check if usernameField is already used by another combination
  855. for(var i = 0; i < cipFields.combinations.length; i++) {
  856. if(cipFields.combinations[i].username == usernameId) {
  857. usernameField = null;
  858. break;
  859. }
  860. }
  861. }
  862. cipFields.setUniqueId(usernameField);
  863. return usernameField;
  864. }
  865. /**
  866. * return the password field or null if it not exists
  867. */
  868. cipFields.getPasswordField = function(usernameId, checkDisabled) {
  869. var usernameField = _f(usernameId);
  870. if(!usernameField) {
  871. return null;
  872. }
  873. var form = usernameField.closest("form")[0];
  874. var passwordField = null;
  875. // search all inputs on this one form
  876. if(form) {
  877. passwordField = cIPJQ("input[type='password']:first", form);
  878. if(passwordField.length < 1) {
  879. passwordField = null;
  880. }
  881. if(cip.settings.usePasswordGenerator) {
  882. cipPassword.init();
  883. cipPassword.initField(passwordField);
  884. }
  885. }
  886. // search all inputs on page
  887. else {
  888. var inputs = cipFields.getAllFields();
  889. cip.initPasswordGenerator(inputs);
  890. var active = false;
  891. for(var i = 0; i < inputs.length; i++) {
  892. if(inputs[i].attr("data-cip-id") == usernameId) {
  893. active = true;
  894. }
  895. if(active && cIPJQ(inputs[i]).attr("type") && cIPJQ(inputs[i]).attr("type").toLowerCase() == "password") {
  896. passwordField = inputs[i];
  897. break;
  898. }
  899. }
  900. }
  901. if(passwordField && !checkDisabled) {
  902. var passwordId = passwordField.attr("data-cip-id");
  903. // check if passwordField is already used by another combination
  904. for(var i = 0; i < cipFields.combinations.length; i++) {
  905. if(cipFields.combinations[i].password == passwordId) {
  906. passwordField = null;
  907. break;
  908. }
  909. }
  910. }
  911. cipFields.setUniqueId(passwordField);
  912. return passwordField;
  913. }
  914. cipFields.prepareCombinations = function(combinations) {
  915. for(var i = 0; i < combinations.length; i++) {
  916. // disable autocomplete for username field
  917. if(_f(combinations[i].username)) {
  918. _f(combinations[i].username).attr("autocomplete", "off");
  919. }
  920. var pwField = _f(combinations[i].password);
  921. // needed for auto-complete: don't overwrite manually filled-in password field
  922. if(pwField && !pwField.data("cipFields-onChange")) {
  923. pwField.data("cipFields-onChange", true);
  924. pwField.change(function() {
  925. cIPJQ(this).data("unchanged", false);
  926. });
  927. }
  928. // initialize form-submit for remembering credentials
  929. var fieldId = combinations[i].password || combinations[i].username;
  930. var field = _f(fieldId);
  931. if(field) {
  932. var form = field.closest("form");
  933. if(form && form.length > 0) {
  934. cipForm.init(form, combinations[i]);
  935. }
  936. }
  937. }
  938. }
  939. cipFields.useDefinedCredentialFields = function() {
  940. if(cip.settings["defined-credential-fields"] && cip.settings["defined-credential-fields"][document.location.origin]) {
  941. var creds = cip.settings["defined-credential-fields"][document.location.origin];
  942. var $found = _f(creds.username) || _f(creds.password);
  943. for(var i = 0; i < creds.fields.length; i++) {
  944. if(_fs(creds.fields[i])) {
  945. $found = true;
  946. break;
  947. }
  948. }
  949. if($found) {
  950. var fields = {
  951. "username": creds.username,
  952. "password": creds.password,
  953. "fields": creds.fields
  954. };
  955. cipFields.combinations = [];
  956. cipFields.combinations.push(fields);
  957. return true;
  958. }
  959. }
  960. return false;
  961. }
  962. var cip = {};
  963. // settings of chromeIPass
  964. cip.settings = {};
  965. // username field which will be set on focus
  966. cip.u = null;
  967. // password field which will be set on focus
  968. cip.p = null;
  969. // document.location
  970. cip.url = null;
  971. // request-url of the form in which the field is located
  972. cip.submitUrl = null;
  973. // received credentials from KeePassHTTP
  974. cip.credentials = [];
  975. cip.trapSubmit = true;
  976. cIPJQ(function() {
  977. cip.init();
  978. });
  979. cip.init = function() {
  980. chrome.extension.sendMessage({
  981. "action": "get_settings",
  982. }, function(response) {
  983. cip.settings = response.data;
  984. cip.initCredentialFields();
  985. });
  986. }
  987. cip.initCredentialFields = function(forceCall) {
  988. if(_called.initCredentialFields && !forceCall) {
  989. return;
  990. }
  991. _called.initCredentialFields = true;
  992. var inputs = cipFields.getAllFields();
  993. cipFields.prepareVisibleFieldsWithID("select");
  994. cip.initPasswordGenerator(inputs);
  995. if(!cipFields.useDefinedCredentialFields()) {
  996. // get all combinations of username + password fields
  997. cipFields.combinations = cipFields.getAllCombinations(inputs);
  998. }
  999. cipFields.prepareCombinations(cipFields.combinations);
  1000. if(cipFields.combinations.length == 0) {
  1001. chrome.extension.sendMessage({
  1002. 'action': 'show_default_browseraction'
  1003. });
  1004. return;
  1005. }
  1006. cip.url = document.location.origin;
  1007. cip.submitUrl = cip.getFormActionUrl(cipFields.combinations[0]);
  1008. chrome.extension.sendMessage({
  1009. 'action': 'retrieve_credentials',
  1010. 'args': [ cip.url, cip.submitUrl ]
  1011. }, cip.retrieveCredentialsCallback);
  1012. } // end function init
  1013. cip.initPasswordGenerator = function(inputs) {
  1014. if(cip.settings.usePasswordGenerator) {
  1015. cipPassword.init();
  1016. for(var i = 0; i < inputs.length; i++) {
  1017. if(inputs[i] && inputs[i].attr("type") && inputs[i].attr("type").toLowerCase() == "password") {
  1018. cipPassword.initField(inputs[i], inputs, i);
  1019. }
  1020. }
  1021. }
  1022. }
  1023. /**
  1024. * Submit the credentials to the server
  1025. */
  1026. cip.doSubmit = function doSubmit(pass)
  1027. {
  1028. cip.trapSubmit = false; // don't trap this submit, let it through
  1029. console.log('doSubmit: pass field',pass);
  1030. // locate best submit option
  1031. var forms = $(pass).closest('form');
  1032. if (forms.length > 0) {
  1033. var submits = forms.find(':submit');
  1034. if (submits.length > 0) {
  1035. console.log('submitting form '+forms[0].id+' via ',submits[0]);
  1036. $(submits[0]).click();
  1037. } else {
  1038. console.log('submitting form '+forms[0].id);
  1039. $(forms[0]).submit();
  1040. }
  1041. } else {
  1042. console.log('submitting default form '+$('form').id);
  1043. $('form').submit();
  1044. }
  1045. }
  1046. cip.retrieveCredentialsCallback = function (credentials, dontAutoFillIn) {
  1047. if (cipFields.combinations.length > 0) {
  1048. cip.u = _f(cipFields.combinations[0].username);
  1049. cip.p = _f(cipFields.combinations[0].password);
  1050. }
  1051. if (credentials.length > 0) {
  1052. cip.credentials = credentials;
  1053. cip.prepareFieldsForCredentials(!Boolean(dontAutoFillIn));
  1054. if (cip.p) {
  1055. cip.doSubmit(cip.p);
  1056. }
  1057. }
  1058. }
  1059. cip.prepareFieldsForCredentials = function(autoFillInForSingle) {
  1060. // only one login returned by mooltipass
  1061. var combination = null;
  1062. if(!cip.p && !cip.u && cipFields.combinations.length > 0) {
  1063. cip.u = _f(cipFields.combinations[0].username);
  1064. cip.p = _f(cipFields.combinations[0].password);
  1065. combination = cipFields.combinations[0];
  1066. }
  1067. if (cip.u) {
  1068. cip.u.val(cip.credentials[0].Login);
  1069. combination = cipFields.getCombination("username", cip.u);
  1070. }
  1071. if (cip.p) {
  1072. cip.p.val(cip.credentials[0].Password);
  1073. combination = cipFields.getCombination("password", cip.p);
  1074. }
  1075. if(combination) {
  1076. var list = {};
  1077. if(cip.fillInStringFields(combination.fields, cip.credentials[0].StringFields, list)) {
  1078. cipForm.destroy(false, {"password": list.list[0], "username": list.list[1]});
  1079. }
  1080. }
  1081. }
  1082. cip.preparePageForMultipleCredentials = function(credentials) {
  1083. // add usernames + descriptions to autocomplete-list and popup-list
  1084. var usernames = [];
  1085. cipAutocomplete.elements = [];
  1086. var visibleLogin;
  1087. for(var i = 0; i < credentials.length; i++) {
  1088. visibleLogin = (credentials[i].Login.length > 0) ? credentials[i].Login : "- no username -";
  1089. usernames.push(visibleLogin + " (" + credentials[i].Name + ")");
  1090. var item = {
  1091. "label": visibleLogin + " (" + credentials[i].Name + ")",
  1092. "value": credentials[i].Login,
  1093. "loginId": i
  1094. };
  1095. cipAutocomplete.elements.push(item);
  1096. }
  1097. // generate popup-list of usernames + descriptions
  1098. chrome.extension.sendMessage({
  1099. 'action': 'popup_login',
  1100. 'args': [usernames]
  1101. });
  1102. // initialize autocomplete for username fields
  1103. if(cip.settings.autoCompleteUsernames) {
  1104. for(var i = 0; i < cipFields.combinations.length; i++) {
  1105. if(_f(cipFields.combinations[i].username)) {
  1106. cipAutocomplete.init(_f(cipFields.combinations[i].username));
  1107. }
  1108. }
  1109. }
  1110. }
  1111. cip.getFormActionUrl = function(combination) {
  1112. var field = _f(combination.password) || _f(combination.username);
  1113. if(field == null) {
  1114. return null;
  1115. }
  1116. var form = field.closest("form");
  1117. var action = null;
  1118. if(form && form.length > 0) {
  1119. action = form[0].action;
  1120. }
  1121. if(typeof(action) != "string" || action == "") {
  1122. action = document.location.origin + document.location.pathname;
  1123. }
  1124. return action;
  1125. }
  1126. cip.fillInCredentials = function(combination, onlyPassword, suppressWarnings) {
  1127. var action = cip.getFormActionUrl(combination);
  1128. var u = _f(combination.username);
  1129. var p = _f(combination.password);
  1130. if(combination.isNew) {
  1131. // initialize form-submit for remembering credentials
  1132. var fieldId = combination.password || combination.username;
  1133. var field = _f(fieldId);
  1134. if(field) {
  1135. var form2 = field.closest("form");
  1136. if(form2 && form2.length > 0) {
  1137. cipForm.init(form2, combination);
  1138. }
  1139. }
  1140. }
  1141. if(u) {
  1142. cip.u = u;
  1143. }
  1144. if(p) {
  1145. cip.p = p;
  1146. }
  1147. if(cip.url == document.location.origin && cip.submitUrl == action && cip.credentials.length > 0) {
  1148. cip.fillIn(combination, onlyPassword, suppressWarnings);
  1149. }
  1150. else {
  1151. cip.url = document.location.origin;
  1152. cip.submitUrl = action;
  1153. chrome.extension.sendMessage({
  1154. 'action': 'retrieve_credentials',
  1155. 'args': [ cip.url, cip.submitUrl, false, true ]
  1156. }, function(credentials) {
  1157. cip.retrieveCredentialsCallback(credentials, true);
  1158. cip.fillIn(combination, onlyPassword, suppressWarnings);
  1159. });
  1160. }
  1161. }
  1162. cip.fillInFromActiveElement = function(suppressWarnings) {
  1163. var el = document.activeElement;
  1164. if (el.tagName.toLowerCase() != "input") {
  1165. if(cipFields.combinations.length > 0) {
  1166. cip.fillInCredentials(cipFields.combinations[0], false, suppressWarnings);
  1167. }
  1168. return;
  1169. }
  1170. cipFields.setUniqueId(cIPJQ(el));
  1171. var fieldId = cipFields.prepareId(cIPJQ(el).attr("data-cip-id"));
  1172. var combination = null;
  1173. if(el.type && el.type.toLowerCase() == "password") {
  1174. combination = cipFields.getCombination("password", fieldId);
  1175. }
  1176. else {
  1177. combination = cipFields.getCombination("username", fieldId);
  1178. }
  1179. delete combination.loginId;
  1180. cip.fillInCredentials(combination, false, suppressWarnings);
  1181. }
  1182. cip.fillInFromActiveElementPassOnly = function(suppressWarnings) {
  1183. var el = document.activeElement;
  1184. if (el.tagName.toLowerCase() != "input") {
  1185. if(cipFields.combinations.length > 0) {
  1186. cip.fillInCredentials(cipFields.combinations[0], false, suppressWarnings);
  1187. }
  1188. return;
  1189. }
  1190. cipFields.setUniqueId(cIPJQ(el));
  1191. var fieldId = cipFields.prepareId(cIPJQ(el).attr("data-cip-id"));
  1192. var combination = null;
  1193. if(el.type && el.type.toLowerCase() == "password") {
  1194. combination = cipFields.getCombination("password", fieldId);
  1195. }
  1196. else {
  1197. combination = cipFields.getCombination("username", fieldId);
  1198. }
  1199. if(!_f(combination.password)) {
  1200. var message = "Unable to find a password field";
  1201. chrome.extension.sendMessage({
  1202. action: 'alert',
  1203. args: [message]
  1204. });
  1205. return;
  1206. }
  1207. delete combination.loginId;
  1208. cip.fillInCredentials(combination, true, suppressWarnings);
  1209. }
  1210. cip.setValue = function(field, value) {
  1211. if(field.is("select")) {
  1212. value = value.toLowerCase().trim();
  1213. cIPJQ("option", field).each(function() {
  1214. if(cIPJQ(this).text().toLowerCase().trim() == value) {
  1215. field.val(cIPJQ(this).val());
  1216. return false;
  1217. }
  1218. });
  1219. }
  1220. else {
  1221. field.val(value);
  1222. field.trigger('input');
  1223. }
  1224. }
  1225. cip.fillInStringFields = function(fields, StringFields, filledInFields) {
  1226. var $filledIn = false;
  1227. filledInFields.list = [];
  1228. if(fields && StringFields && fields.length > 0 && StringFields.length > 0) {
  1229. for(var i = 0; i < fields.length; i++) {
  1230. var $sf = _fs(fields[i]);
  1231. if($sf && StringFields[i]) {
  1232. //$sf.val(StringFields[i].Value);
  1233. cip.setValue($sf, StringFields[i].Value);
  1234. filledInFields.list.push(fields[i]);
  1235. $filledIn = true;
  1236. }
  1237. }
  1238. }
  1239. return $filledIn;
  1240. }
  1241. cip.fillIn = function(combination, onlyPassword, suppressWarnings) {
  1242. // no credentials available
  1243. if (cip.credentials.length == 0 && !suppressWarnings) {
  1244. var message = "No logins found.";
  1245. chrome.extension.sendMessage({
  1246. action: 'alert',
  1247. args: [message]
  1248. });
  1249. return;
  1250. }
  1251. var uField = _f(combination.username);
  1252. var pField = _f(combination.password);
  1253. // exactly one pair of credentials available
  1254. if (cip.credentials.length == 1) {
  1255. var filledIn = false;
  1256. if(uField && !onlyPassword) {
  1257. uField.val(cip.credentials[0].Login);
  1258. filledIn = true;
  1259. }
  1260. if(pField) {
  1261. pField.attr("type", "password");
  1262. pField.val(cip.credentials[0].Password);
  1263. pField.data("unchanged", true);
  1264. filledIn = true;
  1265. }
  1266. var list = {};
  1267. if(cip.fillInStringFields(combination.fields, cip.credentials[0].StringFields, list)) {
  1268. cipForm.destroy(false, {"password": list.list[0], "username": list.list[1]});
  1269. filledIn = true;
  1270. }
  1271. if(!filledIn) {
  1272. if(!suppressWarnings) {
  1273. var message = "Error #101\nCannot find fields to fill in.";
  1274. chrome.extension.sendMessage({
  1275. action: 'alert',
  1276. args: [message]
  1277. });
  1278. }
  1279. }
  1280. }
  1281. // specific login id given
  1282. else if(combination.loginId != undefined && cip.credentials[combination.loginId]) {
  1283. var filledIn = false;
  1284. if(uField) {
  1285. uField.val(cip.credentials[combination.loginId].Login);
  1286. filledIn = true;
  1287. }
  1288. if(pField) {
  1289. pField.val(cip.credentials[combination.loginId].Password);
  1290. pField.data("unchanged", true);
  1291. filledIn = true;
  1292. }
  1293. var list = {};
  1294. if(cip.fillInStringFields(combination.fields, cip.credentials[combination.loginId].StringFields, list)) {
  1295. cipForm.destroy(false, {"password": list.list[0], "username": list.list[1]});
  1296. filledIn = true;
  1297. }
  1298. if(!filledIn) {
  1299. if(!suppressWarnings) {
  1300. var message = "Error #102\nCannot find fields to fill in.";
  1301. chrome.extension.sendMessage({
  1302. action: 'alert',
  1303. args: [message]
  1304. });
  1305. }
  1306. }
  1307. }
  1308. // multiple credentials available
  1309. else {
  1310. // check if only one password for given username exists
  1311. var countPasswords = 0;
  1312. if(uField) {
  1313. var valPassword = "";
  1314. var valUsername = "";
  1315. var valStringFields = [];
  1316. var valQueryUsername = uField.val().toLowerCase();
  1317. // find passwords to given username (even those with empty username)
  1318. for (var i = 0; i < cip.credentials.length; i++) {
  1319. if(cip.credentials[i].Login.toLowerCase() == valQueryUsername) {
  1320. countPasswords += 1;
  1321. valPassword = cip.credentials[i].Password;
  1322. valUsername = cip.credentials[i].Login;
  1323. valStringFields = cip.credentials[i].StringFields;
  1324. }
  1325. }
  1326. // for the correct alert message: 0 = no logins, X > 1 = too many logins
  1327. if(countPasswords == 0) {
  1328. countPasswords = cip.credentials.length;
  1329. }
  1330. // only one mapping username found
  1331. if(countPasswords == 1) {
  1332. if(!onlyPassword) {
  1333. uField.val(valUsername);
  1334. }
  1335. if(pField) {
  1336. pField.val(valPassword);
  1337. pField.data("unchanged", true);
  1338. }
  1339. var list = {};
  1340. if(cip.fillInStringFields(combination.fields, valStringFields, list)) {
  1341. cipForm.destroy(false, {"password": list.list[0], "username": list.list[1]});
  1342. }
  1343. }
  1344. // user has to select correct credentials by himself
  1345. if(countPasswords > 1) {
  1346. if(!suppressWarnings) {
  1347. var message = "Error #105\nMore than one login was found in KeePass!\n" +
  1348. "Press the chromeIPass icon for more options.";
  1349. chrome.extension.sendMessage({
  1350. action: 'alert',
  1351. args: [message]
  1352. });
  1353. }
  1354. }
  1355. else if(countPasswords < 1) {
  1356. if(!suppressWarnings) {
  1357. var message = "Error #103\nNo credentials for given username found.";
  1358. chrome.extension.sendMessage({
  1359. action: 'alert',
  1360. args: [message]
  1361. });
  1362. }
  1363. }
  1364. }
  1365. else {
  1366. if(!suppressWarnings) {
  1367. var message = "Error #104\nMore than one login was found in KeePass!\n" +
  1368. "Press the chromeIPass icon for more options.";
  1369. chrome.extension.sendMessage({
  1370. action: 'alert',
  1371. args: [message]
  1372. });
  1373. }
  1374. }
  1375. }
  1376. }
  1377. cip.contextMenuRememberCredentials = function() {
  1378. var el = document.activeElement;
  1379. if (el.tagName.toLowerCase() != "input") {
  1380. return;
  1381. }
  1382. cipFields.setUniqueId(cIPJQ(el));
  1383. var fieldId = cipFields.prepareId(cIPJQ(el).attr("data-cip-id"));
  1384. var combination = null;
  1385. if(el.type && el.type.toLowerCase() == "password") {
  1386. combination = cipFields.getCombination("password", fieldId);
  1387. }
  1388. else {
  1389. combination = cipFields.getCombination("username", fieldId);
  1390. }
  1391. var usernameValue = "";
  1392. var passwordValue = "";
  1393. var usernameField = _f(combination.username);
  1394. var passwordField = _f(combination.password);
  1395. if(usernameField) {
  1396. usernameValue = usernameField.val();
  1397. }
  1398. if(passwordField) {
  1399. passwordValue = passwordField.val();
  1400. }
  1401. if(!cip.rememberCredentials(null, usernameField, usernameValue, passwordField, passwordValue)) {
  1402. alert("Could not detect changed credentials.");
  1403. }
  1404. };
  1405. cip.updateCredentials = function(event, usernameField, username, passwordField, password, url, usernameExists, credentialsList)
  1406. {
  1407. //if (siteBlacklisted) return;
  1408. var pNode = null;
  1409. var updateString = usernameExists ? 'Update credentials for ' : 'Add credentials for ';
  1410. // Offer to update the mooltpass with the new value(s)
  1411. if (!document.getElementById('mpDialog')) {
  1412. console.log('content: creating dialog div');
  1413. var layerNode= document.createElement('div');
  1414. layerNode.setAttribute('id', 'mpDialog');
  1415. layerNode.setAttribute('title','Mooltipass');
  1416. pNode= document.createElement('moolti');
  1417. pNode.innerHTML = '';
  1418. layerNode.appendChild(pNode);
  1419. document.body.appendChild(layerNode);
  1420. } else {
  1421. pNode = $('#moolti');
  1422. }
  1423. if (event) {
  1424. // prevent submit until the credentials have been handled
  1425. event.preventDefault();
  1426. }
  1427. $( "#mpDialog" ).dialog({
  1428. autoOpen: true,
  1429. show: { effect: 'drop', direction: 'up', duration: 500 },
  1430. buttons: [{
  1431. text: updateString,
  1432. click: function()
  1433. {
  1434. chrome.runtime.sendMessage({action: 'update', 'args': [username, password, url, usernameExists, credentialsList]});
  1435. pNode.innerHTML = 'Please confirm on Mooltipass!';
  1436. $(this).dialog('close');
  1437. $( "#mpDialog" ).dialog({
  1438. autoOpen: true,
  1439. hide: { effect: 'puff', duration: 500 },
  1440. open: function (event, ui) {
  1441. setTimeout(function() {
  1442. if (passwordField) {
  1443. console.log('timeout: submitting');
  1444. cip.doSubmit(passwordField);
  1445. } else {
  1446. console.log('timeout: no passwordField, not submitting');
  1447. }
  1448. $('#mpDialog').dialog('close')
  1449. pNode.innerHTML='';} , 3000);
  1450. },
  1451. buttons: {
  1452. OK: function() {
  1453. if (passwordField) {
  1454. cip.doSubmit(passwordField);
  1455. }
  1456. $(this).dialog('close');
  1457. pNode.innerHTML = '';
  1458. }
  1459. }
  1460. });
  1461. }
  1462. },
  1463. { text: 'Skip',
  1464. click: function() {
  1465. if (passwordField) {
  1466. console.log('skip: submitting');
  1467. cip.doSubmit(passwordField);
  1468. } else {
  1469. console.log('skip: no passwordField, not submitting');
  1470. }
  1471. $(this).dialog('close');
  1472. }
  1473. },
  1474. { text: "Never for this site",
  1475. click: function() {
  1476. console.log('sending blacklist req for '+window.location.href);
  1477. chrome.runtime.sendMessage({action: 'addBlacklist', 'args': [url]});
  1478. console.log('blacklist done....');
  1479. doSubmit(activeCredentials);
  1480. $(this).dialog('close');
  1481. }
  1482. }
  1483. ]
  1484. });
  1485. }
  1486. cip.rememberCredentials = function(event, usernameField, usernameValue, passwordField, passwordValue) {
  1487. // no password given or field cleaned by a site-running script
  1488. // --> no password to save
  1489. if(passwordValue == "") {
  1490. return false;
  1491. }
  1492. if (!cip.trapSubmit) {
  1493. cip.trapSubmit = true;
  1494. return false;
  1495. }
  1496. console.log('rememberCredentials()');
  1497. var usernameExists = false;
  1498. var nothingChanged = false;
  1499. for(var i = 0; i < cip.credentials.length; i++) {
  1500. if(cip.credentials[i].Login == usernameValue && cip.credentials[i].Password == passwordValue) {
  1501. nothingChanged = true;
  1502. break;
  1503. }
  1504. if(cip.credentials[i].Login == usernameValue) {
  1505. usernameExists = true;
  1506. }
  1507. }
  1508. if(!nothingChanged) {
  1509. if(!usernameExists) {
  1510. for(var i = 0; i < cip.credentials.length; i++) {
  1511. if(cip.credentials[i].Login == usernameValue) {
  1512. usernameExists = true;
  1513. break;
  1514. }
  1515. }
  1516. }
  1517. var credentialsList = [];
  1518. for(var i = 0; i < cip.credentials.length; i++) {
  1519. credentialsList.push({
  1520. "Login": cip.credentials[i].Login,
  1521. "Name": cip.credentials[i].Name,
  1522. "Uuid": cip.credentials[i].Uuid
  1523. });
  1524. }
  1525. var url = cIPJQ(this)[0].action;
  1526. if(!url) {
  1527. url = document.location.href;
  1528. if(url.indexOf("?") > 0) {
  1529. url = url.substring(0, url.indexOf("?"));
  1530. if(url.length < document.location.origin.length) {
  1531. url = document.location.origin;
  1532. }
  1533. }
  1534. }
  1535. switch (cip.settings.updateMethod) {
  1536. case 'chromeipass':
  1537. console.log('rememberCredentials - sending set_remember_credentials');
  1538. chrome.extension.sendMessage({
  1539. 'action': 'set_remember_credentials',
  1540. 'args': [usernameValue, passwordValue, url, usernameExists, credentialsList]
  1541. });
  1542. break;
  1543. case 'popup':
  1544. cip.updateCredentials(event, usernameField, usernameValue, passwordField, passwordValue, url, usernameExists, credentialsList);
  1545. break;
  1546. case 'notification':
  1547. console.log('rememberCredentials - sending update_notify');
  1548. chrome.extension.sendMessage({
  1549. 'action': 'update_notify',
  1550. 'args': [usernameValue, passwordValue, url, usernameExists, credentialsList]
  1551. });
  1552. break;
  1553. }
  1554. return true;
  1555. } else {
  1556. console.log('rememberCredentials - nothing changed');
  1557. }
  1558. return false;
  1559. };
  1560. cipEvents = {};
  1561. cipEvents.clearCredentials = function() {
  1562. cip.credentials = [];
  1563. cipAutocomplete.elements = [];
  1564. if(cip.settings.autoCompleteUsernames) {
  1565. for(var i = 0; i < cipFields.combinations.length; i++) {
  1566. var uField = _f(cipFields.combinations[i].username);
  1567. if(uField) {
  1568. if(uField.hasClass("cip-ui-autocomplete-input")) {
  1569. uField.autocomplete("destroy");
  1570. }
  1571. }
  1572. }
  1573. }
  1574. }
  1575. cipEvents.triggerActivatedTab = function() {
  1576. // doesn't run a second time because of _called.initCredentialFields set to true
  1577. cip.init();
  1578. // initCredentialFields calls also "retrieve_credentials", to prevent it
  1579. // check of init() was already called
  1580. if(_called.initCredentialFields && (cip.url || cip.submitUrl)) {
  1581. chrome.extension.sendMessage({
  1582. 'action': 'retrieve_credentials',
  1583. 'args': [ cip.url, cip.submitUrl ]
  1584. }, cip.retrieveCredentialsCallback);
  1585. }
  1586. }