Advertisement
Guest User

Untitled

a guest
May 26th, 2017
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.28 KB | None | 0 0
  1. /**
  2. * Copyright (c) 2010 - 2016 by Eric Van Dewoestine
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. *
  22. * Plugin to pull username/password from pass for logging onto sites.
  23. *
  24. * Usage:
  25. * :pass login
  26. * Attempt to find the username/password fields and populate them.
  27. * :pass username
  28. * Populate the current (or last) focused input with the username.
  29. * :pass password
  30. * Populate the current (or last) focused password input with the password.
  31. * Note: this will only populate the input if it is of type 'password'.
  32. */
  33. function Keyring() {
  34. function console(){
  35. return window.console;
  36. }
  37.  
  38. function paste(arg){
  39. try{
  40. var inputField = window.content.document.lastInputField;
  41. if (!inputField){
  42. return;
  43. }
  44.  
  45. var clip = Components.classes["@mozilla.org/widget/clipboard;1"]
  46. .getService(Components.interfaces.nsIClipboard);
  47. if (!clip){
  48. console().log('Failed to aquire the clipboard.');
  49. return;
  50. }
  51.  
  52. var trans = Components.classes["@mozilla.org/widget/transferable;1"]
  53. .createInstance(Components.interfaces.nsITransferable);
  54. if (!trans){
  55. console().log('Failed to aquire the transferable.');
  56. return;
  57. }
  58. trans.addDataFlavor("text/unicode");
  59. clip.getData(trans, clip.kGlobalClipboard);
  60. var str = new Object();
  61. var strLength = new Object();
  62. trans.getTransferData("text/unicode", str, strLength);
  63.  
  64. if (!str) {
  65. console().log('No content retrieved from the clipboard.');
  66. return;
  67. }
  68.  
  69. str = str.value.QueryInterface(Components.interfaces.nsISupportsString);
  70. var value = str.data.substring(0, strLength.value / 2);
  71. if (arg == 'username'){
  72. var values = value.split("\n");
  73. if (values.length > 1){
  74. // FIXME: prompt user with avaliable options
  75. value = values[0];
  76. }
  77. }
  78. window.content.document.username = value;
  79. inputField.value = value;
  80. }catch(e){
  81. console().error(e);
  82. }
  83. }
  84.  
  85. function KeyringObserver(arg) {
  86. this.register();
  87. this.arg = arg;
  88. }
  89. KeyringObserver.prototype = {
  90. observe: function(subject, topic, data) {
  91. paste(this.arg);
  92. },
  93. register: function() {
  94. var observerService =
  95. Components.classes["@mozilla.org/observer-service;1"]
  96. .getService(Components.interfaces.nsIObserverService);
  97. observerService.addObserver(this, "keyring", false);
  98. }
  99. };
  100. var observers = {
  101. 'username': new KeyringObserver('username'),
  102. 'password': new KeyringObserver('password')
  103. };
  104.  
  105. function execute(args){
  106. try{
  107. var dirService =
  108. Components.classes["@mozilla.org/file/directory_service;1"]
  109. .getService(Components.interfaces.nsIProperties);
  110. var homeDirFile = dirService.get("Home", Components.interfaces.nsIFile);
  111. var homeDir = homeDirFile.path;
  112.  
  113. var file = Components.classes["@mozilla.org/file/local;1"]
  114. .createInstance(Components.interfaces.nsILocalFile);
  115. file.initWithPath(homeDir + '/bin/pass2xclip');
  116. var process = Components.classes["@mozilla.org/process/util;1"]
  117. .createInstance(Components.interfaces.nsIProcess);
  118. var observer = observers[args[0]];
  119. process.init(file);
  120. process.runAsync(args, args.length, observer);
  121. }catch(e){
  122. console().error(e);
  123. }
  124. }
  125.  
  126. function hostname(document, args){
  127. var domain = args && args.length ? args[0] : '';
  128. if (domain){
  129. return domain;
  130. }
  131.  
  132. var host = document.location.hostname;
  133. var remove = /^(www\d*|wwws|us|login|safe|sitekey|secure.*?)\./;
  134. if (remove.test(host)){
  135. host = host.replace(remove, '');
  136. }
  137. return host;
  138. }
  139.  
  140. function findPasswordInput(root){
  141. var passInputs = root.querySelectorAll('input[type=password]');
  142.  
  143. for(var i = 0; i < passInputs.length; i++){
  144. if (isVisible(passInputs[i])){
  145. return passInputs[i];
  146. }
  147. }
  148.  
  149. if (root == window.content.document){
  150. var frames = root.querySelectorAll('iframe');
  151. for (i = 0; i < frames.length; i++){
  152. passInput = findPasswordInput(frames[i].contentWindow.document);
  153. if (passInput){
  154. return passInput;
  155. }
  156. }
  157. }
  158. return null;
  159. }
  160.  
  161. function isVisible(input){
  162. var node = input;
  163. while(node){
  164. if(node.nodeName.toLowerCase() == 'body'){
  165. return true;
  166. }
  167. if(node.style.display == 'none' || node.style.visibility == 'hidden'){
  168. return false;
  169. }
  170. node = node.parentNode;
  171. }
  172. return true;
  173. }
  174.  
  175. return {
  176. login: function(args){
  177. var passInput = findPasswordInput(window.content.document);
  178. if (!passInput){
  179. liberator.echoerr('No password input found.');
  180. return;
  181. }
  182.  
  183. var node = passInput.parentNode;
  184. var userInput = null;
  185. while (node != document){
  186. userInput = node.querySelector('input[type=email], input[type=text]');
  187. if (userInput){
  188. break;
  189. }
  190. node = node.parentNode;
  191. }
  192.  
  193. if (!userInput){
  194. liberator.echoerr('No user input found.');
  195. return;
  196. }
  197. console().log(['username', userInput]);
  198. console().log(['password', passInput]);
  199. keyring['username'](args, userInput);
  200. // hacky... is there a better way to wait for completion of the username
  201. // step?
  202. setTimeout(function(){
  203. if (window.content.document.username){
  204. var host = hostname(userInput.ownerDocument, args);
  205. var username = window.content.document.username;
  206. keyring['password']([username], passInput, host);
  207. }
  208. }, 5000);
  209. },
  210.  
  211. username: function(args, input){
  212. var inputField = input || window.content.document.lastInputField;
  213. if (inputField){
  214. buffer.focusElement(inputField);
  215. window.content.document.lastInputField = inputField;
  216. var host = hostname(inputField.ownerDocument, args);
  217. execute(['username', host]);
  218. }else{
  219. liberator.echoerr('Unable to determine input element.');
  220. }
  221. },
  222.  
  223. password: function(args, input, host){
  224. var inputField = input || window.content.document.lastInputField;
  225. if (!inputField || inputField.nodeName != 'INPUT' || inputField.type != 'password'){
  226. var passInput = findPasswordInput(window.content.document);
  227. if (passInput){
  228. inputField = passInput;
  229. }
  230. }
  231. if (inputField){
  232. if (inputField.nodeName != 'INPUT' || inputField.type != 'password'){
  233. liberator.echoerr('Not a password input field.');
  234. }else{
  235. buffer.focusElement(inputField);
  236. window.content.document.lastInputField = inputField;
  237. var username = args && args.length ? args[0] :
  238. window.content.document.username || '';
  239. console().log(['username', username]);
  240. host = host || hostname(inputField.ownerDocument);
  241.  
  242. // no username, so look it up by the host
  243. if (!username){
  244. execute(['username', host]);
  245. setTimeout(function(){
  246. if (window.content.document.username){
  247. username = window.content.document.username;
  248. execute(['password', host]);
  249. }
  250. }, 500);
  251.  
  252. // contains @, so could just be username (email) or could be
  253. // username@host
  254. }else{
  255. execute(['password', host]);
  256. }
  257. }
  258. }else{
  259. liberator.echoerr('Unable to determine input field.');
  260. }
  261. },
  262.  
  263. _execute: function(args){
  264. var name = args.length ? args.shift() : '';
  265. var cmd = keyring[name];
  266. if (!cmd){
  267. liberator.echoerr('Unsupported keyring command: ' + name);
  268. return false;
  269. }
  270. return cmd(args);
  271. },
  272.  
  273. _completer: function(context){
  274. var commands = [];
  275. for (var name in keyring){
  276. if (name.indexOf('_') !== 0 && keyring.hasOwnProperty(name)){
  277. commands.push(name.replace('_', '-'));
  278. }
  279. }
  280. // FIXME: not providing completions
  281. context.completions = util.map(commands, function(i, command){
  282. return [command, command];
  283. });
  284. }
  285. }
  286. }
  287.  
  288. var keyring = Keyring();
  289.  
  290. commands.addUserCommand(["pass"],
  291. "Insert username or password into a login field.",
  292. function(args) { keyring._execute(args); },
  293. { count: false, argCount: '*', completer: keyring._completer }
  294. );
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement