comparison temp/js_cache/publickey-0e011cb.js @ 0:1e000243b222

vanilla 1.3.3 distro, I hope
author Charlie Root
date Thu, 04 Jan 2018 15:50:29 -0500
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e000243b222
1 "use strict";
2
3 (function(context){
4 /*
5 Default keyservers (HTTPS and CORS enabled)
6 */
7 var DEFAULT_KEYSERVERS = [
8 "https://keys.fedoraproject.org/",
9 "https://keybase.io/",
10 ];
11
12 /*
13 Initialization to create an PublicKey object.
14
15 Arguments:
16
17 * keyservers - Array of keyserver domains, default is:
18 ["https://keys.fedoraproject.org/", "https://keybase.io/"]
19
20 Examples:
21
22 //Initialize with the default keyservers
23 var hkp = new PublicKey();
24
25 //Initialize only with a specific keyserver
26 var hkp = new PublicKey(["https://key.ip6.li/"]);
27 */
28 var PublicKey = function(keyservers){
29 this.keyservers = keyservers || DEFAULT_KEYSERVERS;
30 };
31
32 /*
33 Get a public key from any keyserver based on keyId.
34
35 Arguments:
36
37 * keyId - String key id of the public key (this is usually a fingerprint)
38
39 * callback - Function that is called when finished. Two arguments are
40 passed to the callback: publicKey and errorCode. publicKey is
41 an ASCII armored OpenPGP public key. errorCode is the error code
42 (either HTTP status code or keybase error code) returned by the
43 last keyserver that was tried. If a publicKey was found,
44 errorCode is null. If no publicKey was found, publicKey is null
45 and errorCode is not null.
46
47 Examples:
48
49 //Get a valid public key
50 var hkp = new PublicKey();
51 hkp.get("F75BE4E6EF6E9DD203679E94E7F6FAD172EFEE3D", function(publicKey, errorCode){
52 errorCode !== null ? console.log(errorCode) : console.log(publicKey);
53 });
54
55 //Try to get an invalid public key
56 var hkp = new PublicKey();
57 hkp.get("bogus_id", function(publicKey, errorCode){
58 errorCode !== null ? console.log(errorCode) : console.log(publicKey);
59 });
60 */
61 PublicKey.prototype.get = function(keyId, callback, keyserverIndex, err){
62 //default starting point is at the first keyserver
63 if(keyserverIndex === undefined){
64 keyserverIndex = 0;
65 }
66
67 //no more keyservers to check, so no key found
68 if(keyserverIndex >= this.keyservers.length){
69 return callback(null, err || 404);
70 }
71
72 //set the keyserver to try next
73 var ks = this.keyservers[keyserverIndex];
74 var _this = this;
75
76 //special case for keybase
77 if(ks.indexOf("https://keybase.io/") === 0){
78
79 //don't need 0x prefix for keybase searches
80 if(keyId.indexOf("0x") === 0){
81 keyId = keyId.substr(2);
82 }
83
84 //request the public key from keybase
85 var xhr = new XMLHttpRequest();
86 xhr.open("get", "https://keybase.io/_/api/1.0/user/lookup.json" +
87 "?fields=public_keys&key_fingerprint=" + keyId);
88 xhr.onload = function(){
89 if(xhr.status === 200){
90 var result = JSON.parse(xhr.responseText);
91
92 //keybase error returns HTTP 200 status, which is silly
93 if(result['status']['code'] !== 0){
94 return _this.get(keyId, callback, keyserverIndex + 1, result['status']['code']);
95 }
96
97 //no public key found
98 if(result['them'].length === 0){
99 return _this.get(keyId, callback, keyserverIndex + 1, 404);
100 }
101
102 //found the public key
103 var publicKey = result['them'][0]['public_keys']['primary']['bundle'];
104 return callback(publicKey, null);
105 }
106 else{
107 return _this.get(keyId, callback, keyserverIndex + 1, xhr.status);
108 }
109 };
110 xhr.send();
111 }
112
113 //normal HKP keyserver
114 else{
115 //add the 0x prefix if absent
116 if(keyId.indexOf("0x") !== 0){
117 keyId = "0x" + keyId;
118 }
119
120 //request the public key from the hkp server
121 var xhr = new XMLHttpRequest();
122 xhr.open("get", ks + "pks/lookup?op=get&options=mr&search=" + keyId);
123 xhr.onload = function(){
124 if(xhr.status === 200){
125 return callback(xhr.responseText, null);
126 }
127 else{
128 return _this.get(keyId, callback, keyserverIndex + 1, xhr.status);
129 }
130 };
131 xhr.send();
132 }
133 };
134
135 /*
136 Search for a public key in the keyservers.
137
138 Arguments:
139
140 * query - String to search for (usually an email, name, or username).
141
142 * callback - Function that is called when finished. Two arguments are
143 passed to the callback: results and errorCode. results is an
144 Array of users that were returned by the search. errorCode is
145 the error code (either HTTP status code or keybase error code)
146 returned by the last keyserver that was tried. If any results
147 were found, errorCode is null. If no results are found, results
148 is null and errorCode is not null.
149
150 Examples:
151
152 //Search for diafygi's key id
153 var hkp = new PublicKey();
154 hkp.search("diafygi", function(results, errorCode){
155 errorCode !== null ? console.log(errorCode) : console.log(results);
156 });
157
158 //Search for a nonexistent key id
159 var hkp = new PublicKey();
160 hkp.search("doesntexist123", function(results, errorCode){
161 errorCode !== null ? console.log(errorCode) : console.log(results);
162 });
163 */
164 PublicKey.prototype.search = function(query, callback, keyserverIndex, results, err){
165 //default starting point is at the first keyserver
166 if(keyserverIndex === undefined){
167 keyserverIndex = 0;
168 }
169
170 //initialize the results array
171 if(results === undefined){
172 results = [];
173 }
174
175 //no more keyservers to check
176 if(keyserverIndex >= this.keyservers.length){
177
178 //return error if no results
179 if(results.length === 0){
180 return callback(null, err || 404);
181 }
182
183 //return results
184 else{
185
186 //merge duplicates
187 var merged = {};
188 for(var i = 0; i < results.length; i++){
189 var k = results[i];
190
191 //see if there's duplicate key ids to merge
192 if(merged[k['keyid']] !== undefined){
193
194 for(var u = 0; u < k['uids'].length; u++){
195 var has_this_uid = false;
196
197 for(var m = 0; m < merged[k['keyid']]['uids'].length; m++){
198 if(merged[k['keyid']]['uids'][m]['uid'] === k['uids'][u]){
199 has_this_uid = true;
200 break;
201 }
202 }
203
204 if(!has_this_uid){
205 merged[k['keyid']]['uids'].push(k['uids'][u])
206 }
207 }
208 }
209
210 //no duplicate found, so add it to the dict
211 else{
212 merged[k['keyid']] = k;
213 }
214 }
215
216 //return a list of the merged results in the same order
217 var merged_list = [];
218 for(var i = 0; i < results.length; i++){
219 var k = results[i];
220 if(merged[k['keyid']] !== undefined){
221 merged_list.push(merged[k['keyid']]);
222 delete(merged[k['keyid']]);
223 }
224 }
225 return callback(merged_list, null);
226 }
227 }
228
229 //set the keyserver to try next
230 var ks = this.keyservers[keyserverIndex];
231 var _this = this;
232
233 //special case for keybase
234 if(ks.indexOf("https://keybase.io/") === 0){
235
236 //request a list of users from keybase
237 var xhr = new XMLHttpRequest();
238 xhr.open("get", "https://keybase.io/_/api/1.0/user/autocomplete.json?q=" + encodeURIComponent(query));
239 xhr.onload = function(){
240 if(xhr.status === 200){
241 var kb_json = JSON.parse(xhr.responseText);
242
243 //keybase error returns HTTP 200 status, which is silly
244 if(kb_json['status']['code'] !== 0){
245 return _this.search(query, callback, keyserverIndex + 1, results, kb_json['status']['code']);
246 }
247
248 //no public key found
249 if(kb_json['completions'].length === 0){
250 return _this.search(query, callback, keyserverIndex + 1, results, 404);
251 }
252
253 //compose keybase user results
254 var kb_results = [];
255 for(var i = 0; i < kb_json['completions'].length; i++){
256 var user = kb_json['completions'][i]['components'];
257
258 //skip if no public key fingerprint
259 if(user['key_fingerprint'] === undefined){
260 continue;
261 }
262
263 //build keybase user result
264 var kb_result = {
265 "keyid": user['key_fingerprint']['val'].toUpperCase(),
266 "href": "https://keybase.io/" + user['username']['val'] + "/key.asc",
267 "info": "https://keybase.io/" + user['username']['val'],
268 "algo": user['key_fingerprint']['algo'],
269 "keylen": user['key_fingerprint']['nbits'],
270 "creationdate": null,
271 "expirationdate": null,
272 "revoked": false,
273 "disabled": false,
274 "expired": false,
275 "uids": [{
276 "uid": user['username']['val'] +
277 " on Keybase <https://keybase.io/" +
278 user['username']['val'] + ">",
279 "creationdate": null,
280 "expirationdate": null,
281 "revoked": false,
282 "disabled": false,
283 "expired": false,
284 }]
285 };
286
287 //add full name
288 if(user['full_name'] !== undefined){
289 kb_result['uids'].push({
290 "uid": "Full Name: " + user['full_name']['val'],
291 "creationdate": null,
292 "expirationdate": null,
293 "revoked": false,
294 "disabled": false,
295 "expired": false,
296 });
297 }
298
299 //add twitter
300 if(user['twitter'] !== undefined){
301 kb_result['uids'].push({
302 "uid": user['twitter']['val'] +
303 " on Twitter <https://twitter.com/" +
304 user['twitter']['val'] + ">",
305 "creationdate": null,
306 "expirationdate": null,
307 "revoked": false,
308 "disabled": false,
309 "expired": false,
310 });
311 }
312
313 //add github
314 if(user['github'] !== undefined){
315 kb_result['uids'].push({
316 "uid": user['github']['val'] +
317 " on Github <https://github.com/" +
318 user['github']['val'] + ">",
319 "creationdate": null,
320 "expirationdate": null,
321 "revoked": false,
322 "disabled": false,
323 "expired": false,
324 });
325 }
326
327 //add reddit
328 if(user['reddit'] !== undefined){
329 kb_result['uids'].push({
330 "uid": user['reddit']['val'] +
331 " on Github <https://reddit.com/u/" +
332 user['reddit']['val'] + ">",
333 "creationdate": null,
334 "expirationdate": null,
335 "revoked": false,
336 "disabled": false,
337 "expired": false,
338 });
339 }
340
341 //add hackernews
342 if(user['hackernews'] !== undefined){
343 kb_result['uids'].push({
344 "uid": user['hackernews']['val'] +
345 " on Hacker News <https://news.ycombinator.com/user?id=" +
346 user['hackernews']['val'] + ">",
347 "creationdate": null,
348 "expirationdate": null,
349 "revoked": false,
350 "disabled": false,
351 "expired": false,
352 });
353 }
354
355 //add coinbase
356 if(user['coinbase'] !== undefined){
357 kb_result['uids'].push({
358 "uid": user['coinbase']['val'] +
359 " on Coinbase <https://www.coinbase.com/" +
360 user['coinbase']['val'] + ">",
361 "creationdate": null,
362 "expirationdate": null,
363 "revoked": false,
364 "disabled": false,
365 "expired": false,
366 });
367 }
368
369 //add websites
370 if(user['websites'] !== undefined){
371 for(var w = 0; w < user['websites'].length; w++){
372 kb_result['uids'].push({
373 "uid": "Owns " + user['websites'][w]['val'],
374 "creationdate": null,
375 "expirationdate": null,
376 "revoked": false,
377 "disabled": false,
378 "expired": false,
379 });
380 }
381 }
382
383 kb_results.push(kb_result);
384 }
385
386 results = results.concat(kb_results);
387 return _this.search(query, callback, keyserverIndex + 1, results, null);
388 }
389 else{
390 return _this.search(query, callback, keyserverIndex + 1, results, xhr.status);
391 }
392 };
393 xhr.send();
394 }
395
396 //normal HKP keyserver
397 else{
398 var xhr = new XMLHttpRequest();
399 xhr.open("get", ks + "pks/lookup?op=index&options=mr&fingerprint=on&search=" + encodeURIComponent(query));
400 xhr.onload = function(){
401 if(xhr.status === 200){
402 var ks_results = [];
403 var raw = xhr.responseText.split("\n");
404 var curKey = undefined;
405 for(var i = 0; i < raw.length; i++){
406 var line = raw[i].trim();
407
408 //pub:<keyid>:<algo>:<keylen>:<creationdate>:<expirationdate>:<flags>
409 if(line.indexOf("pub:") == 0){
410 if(curKey !== undefined){
411 ks_results.push(curKey);
412 }
413 var vals = line.split(":");
414 curKey = {
415 "keyid": vals[1],
416 "href": ks + "pks/lookup?op=get&options=mr&search=0x" + vals[1],
417 "info": ks + "pks/lookup?op=vindex&search=0x" + vals[1],
418 "algo": vals[2] === "" ? null : parseInt(vals[2]),
419 "keylen": vals[3] === "" ? null : parseInt(vals[3]),
420 "creationdate": vals[4] === "" ? null : parseInt(vals[4]),
421 "expirationdate": vals[5] === "" ? null : parseInt(vals[5]),
422 "revoked": vals[6].indexOf("r") !== -1,
423 "disabled": vals[6].indexOf("d") !== -1,
424 "expired": vals[6].indexOf("e") !== -1,
425 "uids": [],
426 }
427 }
428
429 //uid:<escaped uid string>:<creationdate>:<expirationdate>:<flags>
430 if(line.indexOf("uid:") == 0){
431 var vals = line.split(":");
432 curKey['uids'].push({
433 "uid": decodeURIComponent(vals[1]),
434 "creationdate": vals[2] === "" ? null : parseInt(vals[2]),
435 "expirationdate": vals[3] === "" ? null : parseInt(vals[3]),
436 "revoked": vals[4].indexOf("r") !== -1,
437 "disabled": vals[4].indexOf("d") !== -1,
438 "expired": vals[4].indexOf("e") !== -1,
439 });
440 }
441 }
442 ks_results.push(curKey);
443
444 results = results.concat(ks_results);
445 return _this.search(query, callback, keyserverIndex + 1, results, null);
446 }
447 else{
448 return _this.search(query, callback, keyserverIndex + 1, results, xhr.status);
449 }
450 };
451 xhr.send();
452 }
453 };
454
455 context.PublicKey = PublicKey;
456 })(typeof exports === "undefined" ? this : exports);