vshih (owner)

Revisions

gist: 102363 Download_button fork
public
Description:
Ubiquity bugmenot.com - Queries bugmenot.com and posts login information for the current page.
Public Clone URL: git://gist.github.com/102363.git
bugmenot.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/*
bugmenot.js
 
Queries bugmenot.com for the current page, populates login information and submits.
Written by Victor Shih (vshih at yahoo.com, http://blog.vicshih.com/2009/04/bugmenot-command-for-ubiquity.html)
 
Initial idea and some code from Onur Yalazı (onur@yalazi.org, http://www.yalazi.org/ubiquity) and Brandon Goldsworthy.
*/
const MIN_RATE_PERCENT = 50; // only show entries that rate 50% or more
 
CmdUtils.CreateCommand({
  names: ['bugmenot'],
  icon: 'http://www.bugmenot.com/favicon.gif',
  homepage: 'http://blog.vicshih.com/2009/04/bugmenot-command-for-ubiquity.html',
  author: {name: 'Victor Shih', email: 'vshih at yahoo.com'},
  license: 'MPL',
  description: 'Queries bugmenot.com for the current page, populates login information and submits.',
  help: 'Enter the desired index of the bugmenot.com entry; defaults to top entry.',
 
  arguments: [ {role: 'object', nountype: /\d*/, label: 'entry number'} ],
 
  preview: function(pblock, args) {
    var url = this._getUrl();
 
    pblock.innerHTML = 'Passwords for ' + url + ':<br />';
 
    this._showEntries(pblock, url, args.object.text);
  },
 
  execute: function(args) {
    var url = this._getUrl();
 
    var entryID = parseInt(args.object.text) - 1;
    if (isNaN(entryID)) entryID = 0;
 
    var proxy = this;
 
    this._getEntries(url, function(entries) {
      if (entries.length == 0) {
        displayMessage(_('Bugmenot.com - no entries found.'));
        return;
      }
 
      if (entryID >= entries.length) entryID = entries.length - 1;
 
      proxy._submit(entries[entryID]);
    });
  },
 
  // Private members
  _entries: {},
 
  _decode: function(data, key) {
    var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
    var o11 = '', o21 = '', o31 = '';
    var h11 = '', h21 = '', h31 = '', h41 = '';
    var bits1 = '', i1 = 0, enc1 = '';
 
    do {
      h11 = b64.indexOf(data.charAt(i1++));
      h21 = b64.indexOf(data.charAt(i1++));
      h31 = b64.indexOf(data.charAt(i1++));
      h41 = b64.indexOf(data.charAt(i1++));
      bits1 = h11 << 18 | h21 << 12 | h31 << 6 | h41;
      o11 = bits1 >> 16 & 255;
      o21 = bits1 >> 8 & 255;
      o31 = bits1 & 255;
      if (h31 == 64) {
        enc1 += String.fromCharCode(o11);
      }
      else if (h41 == 64) {
        enc1 += String.fromCharCode(o11, o21);
      }
      else {
        enc1 += String.fromCharCode(o11, o21, o31);
      }
    }
    while (i1 < data.length);
 
    var strInput = enc1;
    var strOutput = '';
    var intOffset = (key + 112) / 12;
 
    for (i1 = 4; i1 < strInput.length; ++i1) {
      var thisLetter = strInput.charAt(i1);
      var thisCharCode = strInput.charCodeAt(i1);
      var newCharCode = thisCharCode - intOffset;
      strOutput += String.fromCharCode(newCharCode);
    }
 
    return strOutput;
  },
 
  _getUrl: function() {
    var url = Application.activeWindow.activeTab.document.location.toString();
    var i = url.indexOf('://');
    if (i != -1) url = url.substr(i + 3);
    var i = url.indexOf('/');
    if (i != -1) url = url.substr(0, i);
    return url;
  },
 
  _getEntries: function(url, callback) {
    if (this._entries[url]) {
      callback.call(this, this._entries[url]);
    }
    else {
      var proxy = this;
 
      jQuery.ajax({
          url: 'http://www.bugmenot.com/view/' + url,
          success: function(html) {
            var key = parseInt(html.match(/key.=.(-?[0-9]*)/)[1]);
            var ps = html.split('<div class="account"');
 
            var result = [];
 
            for (var i = 0; i < ps.length; ++i) {
              var pair = ps[i].match(/d\('(.*)'\)/g);
 
              if (!pair) continue;
 
              var rate = parseInt(ps[i].match(/[0-9]{1,3}%/));
 
              if (rate < MIN_RATE_PERCENT) continue;
 
              var username = proxy._decode(pair[0].match(/'(.*)'/)[1], key);
              var password = proxy._decode(pair[1].match(/'(.*)'/)[1], key);
 
              result.push({username: username, password: password, rate: rate});
            }
 
            proxy._entries[url] = result;
 
            callback.call(proxy, result);
          },
        error: function() {
          // The ajax call seems to fail when there are no bugmenot entries found.
          // In this case, none of the parameters are informative, so just callback with no entries
          callback.call(proxy, []);
        }
      });
    }
  },
 
  _showEntries: function(pblock, url, entryID) {
    var proxy = this;
 
    this._getEntries(url, function(entries) {
      if (entries.length == 0) {
        pblock.innerHTML += 'No entries found.';
        return;
      }
 
      for (var i = 0; i < entries.length; ++i) {
        proxy._showEntry(pblock, i, entries[i], entryID);
      }
    });
  },
 
  _showEntry: function(pblock, i, entry, entryID) {
    var index = (i + 1).toString();
    var style = (entryID == index) ? 'style="background-color: green"' : '';
    pblock.innerHTML += '<div ' + style + '>' + index + (index.length == 1 ? '&nbsp;' : '') + ' ' + entry.username +
      ' <span style="color: gray">' + entry.password + '</span> ' + entry.rate + '%</div>';
  },
 
  _submit: function(entry) {
    var ins = jQuery(CmdUtils.getDocument()).find(':text,:password');
 
    var pass = ins.filter(':password:eq(0)');
    ins.slice(0, ins.index(pass)).filter(':text:last').val(entry.username);
    pass.val(entry.password)[0].form.submit();
  }
});