keybase-proofs 2.3.23 → 2.3.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/lib/constants.js +1 -1
- package/lib/schema3.js +9 -0
- package/lib/scrapers/base.js +46 -21
- package/lib/scrapers/generic_social.js +2 -2
- package/lib/scrapers/twitter.js +83 -44
- package/package.json +2 -2
- package/src/schema3.iced +9 -1
- package/src/scrapers/base.iced +7 -2
- package/src/scrapers/generic_social.iced +1 -1
- package/src/scrapers/twitter.iced +68 -26
package/CHANGELOG.md
CHANGED
package/lib/constants.js
CHANGED
package/lib/schema3.js
CHANGED
|
@@ -103,6 +103,7 @@
|
|
|
103
103
|
var keys;
|
|
104
104
|
keys = _arg.keys;
|
|
105
105
|
this._keys = keys;
|
|
106
|
+
this._allow_extra_keys = false;
|
|
106
107
|
Dict.__super__.constructor.apply(this, arguments);
|
|
107
108
|
}
|
|
108
109
|
|
|
@@ -116,6 +117,9 @@
|
|
|
116
117
|
v = obj[k];
|
|
117
118
|
new_path = path.extend(k);
|
|
118
119
|
if ((checker = this._keys[k]) == null) {
|
|
120
|
+
if (this._allow_extra_keys) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
119
123
|
return mkerr(new_path, "key is not supported");
|
|
120
124
|
}
|
|
121
125
|
if ((err = this._check_value({
|
|
@@ -154,6 +158,11 @@
|
|
|
154
158
|
return this._keys[k] = v;
|
|
155
159
|
};
|
|
156
160
|
|
|
161
|
+
Dict.prototype.allow_extra_keys = function() {
|
|
162
|
+
this._allow_extra_keys = true;
|
|
163
|
+
return this;
|
|
164
|
+
};
|
|
165
|
+
|
|
157
166
|
return Dict;
|
|
158
167
|
|
|
159
168
|
})(Node);
|
package/lib/scrapers/base.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// Generated by IcedCoffeeScript 108.0.
|
|
1
|
+
// Generated by IcedCoffeeScript 108.0.12
|
|
2
2
|
(function() {
|
|
3
|
-
var BaseScraper, b64find, constants, decode_sig, iced, parse_int_or_undefined, pkg, sncmp, space_normalize, urlmod, user_agent, v_codes, __iced_k, __iced_k_noop;
|
|
3
|
+
var BaseScraper, b64find, callbackify, constants, decode_sig, iced, parse_int_or_undefined, pkg, sncmp, space_normalize, urlmod, user_agent, v_codes, __iced_k, __iced_k_noop;
|
|
4
4
|
|
|
5
5
|
iced = require('iced-runtime');
|
|
6
6
|
__iced_k = __iced_k_noop = function() {};
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
|
|
20
20
|
urlmod = require('url');
|
|
21
21
|
|
|
22
|
+
callbackify = require('util').callbackify;
|
|
23
|
+
|
|
22
24
|
exports.user_agent = user_agent = constants.user_agent + pkg.version;
|
|
23
25
|
|
|
24
26
|
BaseScraper = (function() {
|
|
@@ -92,7 +94,7 @@
|
|
|
92
94
|
(function(__iced_k) {
|
|
93
95
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
94
96
|
parent: ___iced_passed_deferral,
|
|
95
|
-
filename: "/
|
|
97
|
+
filename: "/home/zapu/Projects/KB/proofs/src/scrapers/base.iced",
|
|
96
98
|
funcname: "BaseScraper.validate"
|
|
97
99
|
});
|
|
98
100
|
_this.check_status(args, __iced_deferrals.defer({
|
|
@@ -102,7 +104,7 @@
|
|
|
102
104
|
return rc = arguments[1];
|
|
103
105
|
};
|
|
104
106
|
})(),
|
|
105
|
-
lineno:
|
|
107
|
+
lineno: 53
|
|
106
108
|
}));
|
|
107
109
|
__iced_deferrals._fulfill();
|
|
108
110
|
})(__iced_k);
|
|
@@ -140,7 +142,7 @@
|
|
|
140
142
|
};
|
|
141
143
|
|
|
142
144
|
BaseScraper.prototype._get_url_body = function(opts, cb) {
|
|
143
|
-
var err, rc, response, rl_limit, rl_remaining, rl_reset, ___iced_passed_deferral, __iced_deferrals, __iced_k, _base;
|
|
145
|
+
var body, err, f, rc, response, rl_limit, rl_remaining, rl_reset, ___iced_passed_deferral, __iced_deferrals, __iced_k, _base;
|
|
144
146
|
__iced_k = __iced_k_noop;
|
|
145
147
|
___iced_passed_deferral = iced.findDeferral(arguments);
|
|
146
148
|
|
|
@@ -158,7 +160,7 @@
|
|
|
158
160
|
return (function(__iced_k) {
|
|
159
161
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
160
162
|
parent: ___iced_passed_deferral,
|
|
161
|
-
filename: "/
|
|
163
|
+
filename: "/home/zapu/Projects/KB/proofs/src/scrapers/base.iced",
|
|
162
164
|
funcname: "BaseScraper._get_url_body"
|
|
163
165
|
});
|
|
164
166
|
_this.libs.fetch(opts.url, opts, __iced_deferrals.defer({
|
|
@@ -168,7 +170,7 @@
|
|
|
168
170
|
return response = arguments[1];
|
|
169
171
|
};
|
|
170
172
|
})(),
|
|
171
|
-
lineno:
|
|
173
|
+
lineno: 87
|
|
172
174
|
}));
|
|
173
175
|
__iced_deferrals._fulfill();
|
|
174
176
|
});
|
|
@@ -192,22 +194,45 @@
|
|
|
192
194
|
}
|
|
193
195
|
rc = typeof err !== "undefined" && err !== null ? err.message.includes('network timeout') ? v_codes.TIMEOUT : v_codes.HOST_UNREACHABLE : ((_ref = response.status) === 401 || _ref === 403) ? v_codes.PERMISSION_DENIED : response.status === 200 ? v_codes.OK : response.status >= 500 ? v_codes.HTTP_500 : response.status >= 400 ? v_codes.HTTP_400 : response.status >= 300 ? v_codes.HTTP_300 : v_codes.HTTP_OTHER;
|
|
194
196
|
if (rc === v_codes.OK) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
197
|
+
(function(__iced_k) {
|
|
198
|
+
try {
|
|
199
|
+
if (opts.json) {
|
|
200
|
+
f = callbackify(response.json);
|
|
201
|
+
(function(__iced_k) {
|
|
202
|
+
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
203
|
+
parent: ___iced_passed_deferral,
|
|
204
|
+
filename: "/home/zapu/Projects/KB/proofs/src/scrapers/base.iced",
|
|
205
|
+
funcname: "BaseScraper._get_url_body"
|
|
206
|
+
});
|
|
207
|
+
f.call(response, __iced_deferrals.defer({
|
|
208
|
+
assign_fn: (function() {
|
|
209
|
+
return function() {
|
|
210
|
+
err = arguments[0];
|
|
211
|
+
return body = arguments[1];
|
|
212
|
+
};
|
|
213
|
+
})(),
|
|
214
|
+
lineno: 109
|
|
215
|
+
}));
|
|
216
|
+
__iced_deferrals._fulfill();
|
|
217
|
+
})(function() {
|
|
218
|
+
if (err) {
|
|
219
|
+
_this.log("| _get_url_body response.json() failed with: " + (err.toString()));
|
|
220
|
+
rc = v_codes.CONTENT_FAILURE;
|
|
221
|
+
}
|
|
222
|
+
return __iced_k(cb(err, rc, body));
|
|
223
|
+
});
|
|
224
|
+
} else {
|
|
225
|
+
return __iced_k(response.text().then(function(body) {
|
|
226
|
+
return cb(err, rc, body);
|
|
227
|
+
}));
|
|
228
|
+
}
|
|
229
|
+
} catch (_error) {
|
|
230
|
+
err = _error;
|
|
231
|
+
return cb(err, rc, null);
|
|
204
232
|
}
|
|
205
|
-
}
|
|
206
|
-
err = _error;
|
|
207
|
-
return cb(err, rc, null);
|
|
208
|
-
}
|
|
233
|
+
})(__iced_k);
|
|
209
234
|
} else {
|
|
210
|
-
return cb(err, rc, null);
|
|
235
|
+
return __iced_k(cb(err, rc, null));
|
|
211
236
|
}
|
|
212
237
|
};
|
|
213
238
|
})(this));
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
return [err, rc];
|
|
75
75
|
}
|
|
76
76
|
found = obj.find(function(x) {
|
|
77
|
-
return sncmp(x.kb_username, kb_username) && sncmp(x.sig_hash, sig_id);
|
|
77
|
+
return x && sncmp(x.kb_username, kb_username) && sncmp(x.sig_hash, sig_id);
|
|
78
78
|
});
|
|
79
79
|
if (found != null) {
|
|
80
80
|
rc = v_codes.OK;
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
return (function(__iced_k) {
|
|
101
101
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
102
102
|
parent: ___iced_passed_deferral,
|
|
103
|
-
filename: "/
|
|
103
|
+
filename: "/home/sy/go/src/github.com/keybase/proofs/src/scrapers/generic_social.iced",
|
|
104
104
|
funcname: "GenericSocialScraper.check_status"
|
|
105
105
|
});
|
|
106
106
|
_this._get_url_body({
|
package/lib/scrapers/twitter.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// Generated by IcedCoffeeScript 108.0.
|
|
1
|
+
// Generated by IcedCoffeeScript 108.0.12
|
|
2
2
|
(function() {
|
|
3
|
-
var BaseScraper, BearerToken, Lock, TwitterScraper, bearer_token, constants, decode_sig, iced, make_ids, sncmp, urlmod, v_codes, ws_normalize, __iced_k, __iced_k_noop, _bearer_token, _ref,
|
|
3
|
+
var BaseScraper, BearerToken, Lock, TwitterScraper, bearer_token, constants, decode_sig, iced, make_ids, schema, sncmp, urlmod, v_codes, ws_normalize, __iced_k, __iced_k_noop, _bearer_token, _ref,
|
|
4
4
|
__hasProp = {}.hasOwnProperty,
|
|
5
5
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
|
6
6
|
|
|
@@ -21,6 +21,8 @@
|
|
|
21
21
|
|
|
22
22
|
urlmod = require('url');
|
|
23
23
|
|
|
24
|
+
schema = require('../schema3');
|
|
25
|
+
|
|
24
26
|
ws_normalize = function(x) {
|
|
25
27
|
var v;
|
|
26
28
|
v = x.split(/[\t\r\n ]+/);
|
|
@@ -50,11 +52,11 @@
|
|
|
50
52
|
return (function(__iced_k) {
|
|
51
53
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
52
54
|
parent: ___iced_passed_deferral,
|
|
53
|
-
filename: "/
|
|
55
|
+
filename: "/home/zapu/Projects/KB/proofs/src/scrapers/twitter.iced",
|
|
54
56
|
funcname: "BearerToken.get"
|
|
55
57
|
});
|
|
56
58
|
_this._lock.acquire(__iced_deferrals.defer({
|
|
57
|
-
lineno:
|
|
59
|
+
lineno: 32
|
|
58
60
|
}));
|
|
59
61
|
__iced_deferrals._fulfill();
|
|
60
62
|
});
|
|
@@ -80,7 +82,7 @@
|
|
|
80
82
|
(function(__iced_k) {
|
|
81
83
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
82
84
|
parent: ___iced_passed_deferral,
|
|
83
|
-
filename: "/
|
|
85
|
+
filename: "/home/zapu/Projects/KB/proofs/src/scrapers/twitter.iced",
|
|
84
86
|
funcname: "BearerToken.get"
|
|
85
87
|
});
|
|
86
88
|
_this.base._get_url_body(opts, __iced_deferrals.defer({
|
|
@@ -91,7 +93,7 @@
|
|
|
91
93
|
return body = arguments[2];
|
|
92
94
|
};
|
|
93
95
|
})(),
|
|
94
|
-
lineno:
|
|
96
|
+
lineno: 52
|
|
95
97
|
}));
|
|
96
98
|
__iced_deferrals._fulfill();
|
|
97
99
|
})(function() {
|
|
@@ -193,7 +195,7 @@
|
|
|
193
195
|
return (function(__iced_k) {
|
|
194
196
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
195
197
|
parent: ___iced_passed_deferral,
|
|
196
|
-
filename: "/
|
|
198
|
+
filename: "/home/zapu/Projects/KB/proofs/src/scrapers/twitter.iced",
|
|
197
199
|
funcname: "TwitterScraper.hunt2"
|
|
198
200
|
});
|
|
199
201
|
_this._get_body_api({
|
|
@@ -206,7 +208,7 @@
|
|
|
206
208
|
return json = arguments[2];
|
|
207
209
|
};
|
|
208
210
|
})(),
|
|
209
|
-
lineno:
|
|
211
|
+
lineno: 124
|
|
210
212
|
}));
|
|
211
213
|
__iced_deferrals._fulfill();
|
|
212
214
|
});
|
|
@@ -293,7 +295,7 @@
|
|
|
293
295
|
(function(__iced_k) {
|
|
294
296
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
295
297
|
parent: ___iced_passed_deferral,
|
|
296
|
-
filename: "/
|
|
298
|
+
filename: "/home/zapu/Projects/KB/proofs/src/scrapers/twitter.iced",
|
|
297
299
|
funcname: "TwitterScraper.users_lookup"
|
|
298
300
|
});
|
|
299
301
|
_this._get_body_api({
|
|
@@ -306,7 +308,7 @@
|
|
|
306
308
|
return json = arguments[2];
|
|
307
309
|
};
|
|
308
310
|
})(),
|
|
309
|
-
lineno:
|
|
311
|
+
lineno: 172
|
|
310
312
|
}));
|
|
311
313
|
__iced_deferrals._fulfill();
|
|
312
314
|
})(function() {
|
|
@@ -336,11 +338,11 @@
|
|
|
336
338
|
(function(__iced_k) {
|
|
337
339
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
338
340
|
parent: ___iced_passed_deferral,
|
|
339
|
-
filename: "/
|
|
341
|
+
filename: "/home/zapu/Projects/KB/proofs/src/scrapers/twitter.iced",
|
|
340
342
|
funcname: "TwitterScraper.users_lookup"
|
|
341
343
|
});
|
|
342
344
|
setTimeout(__iced_deferrals.defer({
|
|
343
|
-
lineno:
|
|
345
|
+
lineno: 186
|
|
344
346
|
}), cursor_wait);
|
|
345
347
|
__iced_deferrals._fulfill();
|
|
346
348
|
})(__iced_k);
|
|
@@ -422,7 +424,7 @@
|
|
|
422
424
|
(function(__iced_k) {
|
|
423
425
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
424
426
|
parent: ___iced_passed_deferral,
|
|
425
|
-
filename: "/
|
|
427
|
+
filename: "/home/zapu/Projects/KB/proofs/src/scrapers/twitter.iced",
|
|
426
428
|
funcname: "TwitterScraper.get_follower_ids"
|
|
427
429
|
});
|
|
428
430
|
_this._get_body_api({
|
|
@@ -435,7 +437,7 @@
|
|
|
435
437
|
return json = arguments[2];
|
|
436
438
|
};
|
|
437
439
|
})(),
|
|
438
|
-
lineno:
|
|
440
|
+
lineno: 224
|
|
439
441
|
}));
|
|
440
442
|
__iced_deferrals._fulfill();
|
|
441
443
|
})(function() {
|
|
@@ -468,11 +470,11 @@
|
|
|
468
470
|
(function(__iced_k) {
|
|
469
471
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
470
472
|
parent: ___iced_passed_deferral,
|
|
471
|
-
filename: "/
|
|
473
|
+
filename: "/home/zapu/Projects/KB/proofs/src/scrapers/twitter.iced",
|
|
472
474
|
funcname: "TwitterScraper.get_follower_ids"
|
|
473
475
|
});
|
|
474
476
|
setTimeout(__iced_deferrals.defer({
|
|
475
|
-
lineno:
|
|
477
|
+
lineno: 240
|
|
476
478
|
}), cursor_wait);
|
|
477
479
|
__iced_deferrals._fulfill();
|
|
478
480
|
})(__iced_k);
|
|
@@ -555,7 +557,7 @@
|
|
|
555
557
|
};
|
|
556
558
|
|
|
557
559
|
TwitterScraper.prototype.check_status = function(_arg, cb) {
|
|
558
|
-
var $, api_url,
|
|
560
|
+
var $, api_url, api_url_matches, author_url_matches, author_username, body_obj, err, new_api_url, proof_text_check, rc, remote_id, schm, tweet_id, tweet_p, u, username, username_from_url, _, ___iced_passed_deferral, __iced_deferrals, __iced_k;
|
|
559
561
|
__iced_k = __iced_k_noop;
|
|
560
562
|
___iced_passed_deferral = iced.findDeferral(arguments);
|
|
561
563
|
username = _arg.username, api_url = _arg.api_url, proof_text_check = _arg.proof_text_check, remote_id = _arg.remote_id;
|
|
@@ -565,48 +567,85 @@
|
|
|
565
567
|
this.log("null api_url for " + remote_id + "/" + username);
|
|
566
568
|
return cb(err, rc);
|
|
567
569
|
}
|
|
568
|
-
u = urlmod.
|
|
569
|
-
u.
|
|
570
|
+
u = new urlmod.URL('https://api.twitter.com/1/statuses/oembed.json');
|
|
571
|
+
u.searchParams.set('id', remote_id.toString());
|
|
572
|
+
u.searchParams.set('omit_script', '1');
|
|
570
573
|
new_api_url = urlmod.format(u);
|
|
571
|
-
this.log("|
|
|
572
|
-
api_url = new_api_url;
|
|
574
|
+
this.log("| use oembed API " + new_api_url + " for tweet at " + api_url + " (remote_id=" + remote_id + ")");
|
|
573
575
|
(function(_this) {
|
|
574
576
|
return (function(__iced_k) {
|
|
575
577
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
576
578
|
parent: ___iced_passed_deferral,
|
|
577
|
-
filename: "/
|
|
579
|
+
filename: "/home/zapu/Projects/KB/proofs/src/scrapers/twitter.iced",
|
|
578
580
|
funcname: "TwitterScraper.check_status"
|
|
579
581
|
});
|
|
580
582
|
_this._get_url_body({
|
|
581
|
-
url:
|
|
583
|
+
url: new_api_url,
|
|
584
|
+
json: true
|
|
582
585
|
}, __iced_deferrals.defer({
|
|
583
586
|
assign_fn: (function() {
|
|
584
587
|
return function() {
|
|
585
588
|
err = arguments[0];
|
|
586
589
|
rc = arguments[1];
|
|
587
|
-
return
|
|
590
|
+
return body_obj = arguments[2];
|
|
588
591
|
};
|
|
589
592
|
})(),
|
|
590
|
-
lineno:
|
|
593
|
+
lineno: 331
|
|
591
594
|
}));
|
|
592
595
|
__iced_deferrals._fulfill();
|
|
593
596
|
});
|
|
594
597
|
})(this)((function(_this) {
|
|
595
598
|
return function() {
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
599
|
+
if (!err && rc === v_codes.OK) {
|
|
600
|
+
schm = schema.dict({
|
|
601
|
+
url: schema.string().name('url'),
|
|
602
|
+
author_url: schema.string().name('author_url'),
|
|
603
|
+
html: schema.string().name('html')
|
|
604
|
+
}).allow_extra_keys();
|
|
605
|
+
if (err = schm.check(body_obj)) {
|
|
606
|
+
return cb(err, v_codes.CONTENT_FAILURE);
|
|
607
|
+
}
|
|
608
|
+
if (!(sncmp(body_obj.url, api_url))) {
|
|
609
|
+
err = new Error("returned url field doesn't match api_url (found: " + body_obj.url + ", expected: " + api_url + ")");
|
|
610
|
+
return cb(err, v_codes.CONTENT_FAILURE);
|
|
611
|
+
}
|
|
612
|
+
api_url_matches = api_url.match(new RegExp("^https://twitter\\.com/([^/]+)/status/(\\d+)(.*)$"));
|
|
613
|
+
if (!api_url_matches) {
|
|
614
|
+
err = new Error("api_url field doesn't match regexp, got: " + api_url_matches);
|
|
615
|
+
return cb(err, v_codes.CONTENT_FAILURE);
|
|
616
|
+
}
|
|
617
|
+
_ = api_url_matches[0], username_from_url = api_url_matches[1], tweet_id = api_url_matches[2];
|
|
618
|
+
if (!(sncmp(username, username_from_url))) {
|
|
619
|
+
err = new Error("username from api_url didn't match, expected: " + username + ", got: " + username_from_url);
|
|
620
|
+
return cb(err, v_codes.BAD_USERNAME);
|
|
621
|
+
}
|
|
622
|
+
if (tweet_id !== remote_id.toString()) {
|
|
623
|
+
return cb(err, v_codes.BAD_REMOTE_ID);
|
|
624
|
+
}
|
|
625
|
+
author_url_matches = body_obj.author_url.match(new RegExp("^https://twitter\\.com/(.+)$"));
|
|
626
|
+
if (!author_url_matches) {
|
|
627
|
+
err = new Error("author_url doesn't match regexp, got: " + body_obj.author_url);
|
|
628
|
+
return cb(err, v_codes.CONTENT_FAILURE);
|
|
629
|
+
}
|
|
630
|
+
_ = author_url_matches[0], author_username = author_url_matches[1];
|
|
631
|
+
if (!(sncmp(username, author_username))) {
|
|
632
|
+
err = new Error("username from author_url didn't match, expected: " + username + ", got: " + author_username);
|
|
633
|
+
return cb(err, v_codes.BAD_USERNAME);
|
|
634
|
+
}
|
|
635
|
+
if (body_obj.html.length > 1000) {
|
|
636
|
+
err = new Error("html is " + body_obj.html.length + " characters, not trying to parse it");
|
|
637
|
+
return cb(err, v_codes.CONTENT_FAILURE);
|
|
638
|
+
}
|
|
639
|
+
$ = _this.libs.cheerio.load(body_obj.html);
|
|
640
|
+
tweet_p = $('blockquote.twitter-tweet p');
|
|
641
|
+
if (tweet_p.length !== 1) {
|
|
642
|
+
err = new Error("failed to find tweet <p> in returned 'html' field");
|
|
643
|
+
return cb(err, v_codes.FAILED_PARSE);
|
|
609
644
|
}
|
|
645
|
+
rc = _this.find_sig_in_tweet({
|
|
646
|
+
tweet_p: tweet_p,
|
|
647
|
+
proof_text_check: proof_text_check
|
|
648
|
+
});
|
|
610
649
|
}
|
|
611
650
|
return cb(err, rc);
|
|
612
651
|
};
|
|
@@ -624,7 +663,7 @@
|
|
|
624
663
|
return (function(__iced_k) {
|
|
625
664
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
626
665
|
parent: ___iced_passed_deferral,
|
|
627
|
-
filename: "/
|
|
666
|
+
filename: "/home/zapu/Projects/KB/proofs/src/scrapers/twitter.iced",
|
|
628
667
|
funcname: "TwitterScraper._get_bearer_token"
|
|
629
668
|
});
|
|
630
669
|
bt.get(__iced_deferrals.defer({
|
|
@@ -634,7 +673,7 @@
|
|
|
634
673
|
return tok = arguments[1];
|
|
635
674
|
};
|
|
636
675
|
})(),
|
|
637
|
-
lineno:
|
|
676
|
+
lineno: 392
|
|
638
677
|
}));
|
|
639
678
|
__iced_deferrals._fulfill();
|
|
640
679
|
});
|
|
@@ -656,7 +695,7 @@
|
|
|
656
695
|
return (function(__iced_k) {
|
|
657
696
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
658
697
|
parent: ___iced_passed_deferral,
|
|
659
|
-
filename: "/
|
|
698
|
+
filename: "/home/zapu/Projects/KB/proofs/src/scrapers/twitter.iced",
|
|
660
699
|
funcname: "TwitterScraper._get_body_api"
|
|
661
700
|
});
|
|
662
701
|
_this._get_bearer_token(__iced_deferrals.defer({
|
|
@@ -667,7 +706,7 @@
|
|
|
667
706
|
return tok = arguments[2];
|
|
668
707
|
};
|
|
669
708
|
})(),
|
|
670
|
-
lineno:
|
|
709
|
+
lineno: 401
|
|
671
710
|
}));
|
|
672
711
|
__iced_deferrals._fulfill();
|
|
673
712
|
});
|
|
@@ -687,7 +726,7 @@
|
|
|
687
726
|
(function(__iced_k) {
|
|
688
727
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
689
728
|
parent: ___iced_passed_deferral,
|
|
690
|
-
filename: "/
|
|
729
|
+
filename: "/home/zapu/Projects/KB/proofs/src/scrapers/twitter.iced",
|
|
691
730
|
funcname: "TwitterScraper._get_body_api"
|
|
692
731
|
});
|
|
693
732
|
_this._get_url_body(args, __iced_deferrals.defer({
|
|
@@ -698,7 +737,7 @@
|
|
|
698
737
|
return body = arguments[2];
|
|
699
738
|
};
|
|
700
739
|
})(),
|
|
701
|
-
lineno:
|
|
740
|
+
lineno: 410
|
|
702
741
|
}));
|
|
703
742
|
__iced_deferrals._fulfill();
|
|
704
743
|
})(__iced_k);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "keybase-proofs",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.25",
|
|
4
4
|
"description": "Publicly-verifiable proofs of identity",
|
|
5
5
|
"main": "lib/main.js",
|
|
6
6
|
"scripts": {
|
|
@@ -36,4 +36,4 @@
|
|
|
36
36
|
"iced-coffee-script": "^108.0.11",
|
|
37
37
|
"iced-test": "0.0.22"
|
|
38
38
|
}
|
|
39
|
-
}
|
|
39
|
+
}
|
package/src/schema3.iced
CHANGED
|
@@ -39,6 +39,8 @@ class Node
|
|
|
39
39
|
class Dict extends Node
|
|
40
40
|
constructor : ({keys}) ->
|
|
41
41
|
@_keys = keys
|
|
42
|
+
# do not fail if there are extra keys unknown to schema
|
|
43
|
+
@_allow_extra_keys = false
|
|
42
44
|
super
|
|
43
45
|
|
|
44
46
|
_check : ({path, obj}) ->
|
|
@@ -46,7 +48,9 @@ class Dict extends Node
|
|
|
46
48
|
return mkerr path, "need a dictionary"
|
|
47
49
|
for k,v of obj
|
|
48
50
|
new_path = path.extend(k)
|
|
49
|
-
if not (checker = @_keys[k])?
|
|
51
|
+
if not (checker = @_keys[k])?
|
|
52
|
+
if @_allow_extra_keys then continue
|
|
53
|
+
return mkerr new_path, "key is not supported"
|
|
50
54
|
if (err = @_check_value { checker, path : new_path, obj : v }) then return err
|
|
51
55
|
for k,v of @_keys
|
|
52
56
|
new_path = path.extend(k)
|
|
@@ -62,6 +66,10 @@ class Dict extends Node
|
|
|
62
66
|
set_key : (k,v) ->
|
|
63
67
|
@_keys[k] = v
|
|
64
68
|
|
|
69
|
+
allow_extra_keys : () ->
|
|
70
|
+
@_allow_extra_keys = true
|
|
71
|
+
@
|
|
72
|
+
|
|
65
73
|
class Array extends Node
|
|
66
74
|
|
|
67
75
|
constructor : ({elem}) ->
|
package/src/scrapers/base.iced
CHANGED
|
@@ -5,6 +5,7 @@ pkg = require '../../package.json'
|
|
|
5
5
|
{space_normalize} = require '../util'
|
|
6
6
|
{b64find} = require '../b64extract'
|
|
7
7
|
urlmod = require 'url'
|
|
8
|
+
{callbackify} = require 'util'
|
|
8
9
|
|
|
9
10
|
#==============================================================
|
|
10
11
|
|
|
@@ -105,8 +106,12 @@ class BaseScraper
|
|
|
105
106
|
if rc is v_codes.OK
|
|
106
107
|
try
|
|
107
108
|
if opts.json
|
|
108
|
-
response.json
|
|
109
|
-
|
|
109
|
+
f = callbackify response.json
|
|
110
|
+
await f.call response, defer err, body
|
|
111
|
+
if err
|
|
112
|
+
@log "| _get_url_body response.json() failed with: #{err.toString()}"
|
|
113
|
+
rc = v_codes.CONTENT_FAILURE
|
|
114
|
+
cb err, rc, body
|
|
110
115
|
else
|
|
111
116
|
response.text().then (body) ->
|
|
112
117
|
cb err, rc, body
|
|
@@ -52,7 +52,7 @@ exports.GenericSocialScraper = class GenericSocialScraper extends BaseScraper
|
|
|
52
52
|
unless obj? and Array.isArray obj
|
|
53
53
|
err = new Error "did not find proof list on #{check_path.join('.')} in json data"
|
|
54
54
|
return [err, rc]
|
|
55
|
-
found = obj.find (x) -> sncmp(x.kb_username, kb_username) and sncmp(x.sig_hash, sig_id)
|
|
55
|
+
found = obj.find (x) -> x and sncmp(x.kb_username, kb_username) and sncmp(x.sig_hash, sig_id)
|
|
56
56
|
if found?
|
|
57
57
|
rc = v_codes.OK
|
|
58
58
|
else
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
{v_codes} = constants
|
|
6
6
|
{decode_sig} = require('kbpgp').ukm
|
|
7
7
|
urlmod = require 'url'
|
|
8
|
+
schema = require '../schema3'
|
|
8
9
|
|
|
9
10
|
#================================================================================
|
|
10
11
|
|
|
@@ -312,35 +313,76 @@ exports.TwitterScraper = class TwitterScraper extends BaseScraper
|
|
|
312
313
|
@log "null api_url for #{remote_id}/#{username}"
|
|
313
314
|
return cb err, rc
|
|
314
315
|
|
|
315
|
-
|
|
316
|
-
|
|
316
|
+
# Do not try to fetch api_url which is of form:
|
|
317
|
+
# "https://twitter.com/tacovontaco/status/673931888088625152"
|
|
318
|
+
# because Twitter serves a JavaScript-based page there and the contents of
|
|
319
|
+
# tweet are not available. Instead, construct a new url to oembed API with
|
|
320
|
+
# the tweet ID. That API doesn't require authentication and claims not to
|
|
321
|
+
# be rate limited:
|
|
322
|
+
# https://developer.twitter.com/en/docs/twitter-api/v1/tweets/post-and-engage/api-reference/get-statuses-oembed
|
|
323
|
+
u = new urlmod.URL('https://api.twitter.com/1/statuses/oembed.json')
|
|
324
|
+
u.searchParams.set('id', remote_id.toString())
|
|
325
|
+
# tell twitter not to include their <script> tag in result.
|
|
326
|
+
u.searchParams.set('omit_script', '1')
|
|
327
|
+
|
|
317
328
|
new_api_url = urlmod.format u
|
|
318
|
-
@log "|
|
|
319
|
-
api_url = new_api_url
|
|
329
|
+
@log "| use oembed API #{new_api_url} for tweet at #{api_url} (remote_id=#{remote_id})"
|
|
320
330
|
|
|
321
331
|
# calls back with a v_code or null if it was ok
|
|
322
|
-
await @_get_url_body { url :
|
|
323
|
-
|
|
324
|
-
if rc is v_codes.OK
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
332
|
+
await @_get_url_body { url : new_api_url, json : true }, defer err, rc, body_obj
|
|
333
|
+
|
|
334
|
+
if not err and rc is v_codes.OK
|
|
335
|
+
schm = schema.dict({
|
|
336
|
+
url: schema.string().name('url')
|
|
337
|
+
author_url: schema.string().name('author_url')
|
|
338
|
+
html: schema.string().name('html')
|
|
339
|
+
}).allow_extra_keys()
|
|
340
|
+
if err = schm.check body_obj
|
|
341
|
+
return cb err, v_codes.CONTENT_FAILURE
|
|
342
|
+
|
|
343
|
+
# "url" field returned by the API should match api_url.
|
|
344
|
+
if not(sncmp(body_obj.url, api_url))
|
|
345
|
+
err = new Error "returned url field doesn't match api_url (found: #{body_obj.url}, expected: #{api_url})"
|
|
346
|
+
return cb err, v_codes.CONTENT_FAILURE
|
|
347
|
+
|
|
348
|
+
# Extract username from URL, do not use "author_name" because it's the
|
|
349
|
+
# full name.
|
|
350
|
+
api_url_matches = api_url.match(new RegExp("^https://twitter\\.com/([^/]+)/status/(\\d+)(.*)$"))
|
|
351
|
+
if not api_url_matches
|
|
352
|
+
err = new Error "api_url field doesn't match regexp, got: #{api_url_matches}"
|
|
353
|
+
return cb err, v_codes.CONTENT_FAILURE
|
|
354
|
+
|
|
355
|
+
# Check username and tweet ID.
|
|
356
|
+
[_, username_from_url, tweet_id] = api_url_matches
|
|
357
|
+
if not(sncmp(username, username_from_url))
|
|
358
|
+
err = new Error("username from api_url didn't match, expected: #{username}, got: #{username_from_url}")
|
|
359
|
+
return cb err, v_codes.BAD_USERNAME
|
|
360
|
+
if tweet_id isnt remote_id.toString()
|
|
361
|
+
return cb err, v_codes.BAD_REMOTE_ID
|
|
362
|
+
|
|
363
|
+
# Check "author_url" field, it contains a link to user's twitter profile.
|
|
364
|
+
# It should match our username.
|
|
365
|
+
author_url_matches = body_obj.author_url.match(new RegExp("^https://twitter\\.com/(.+)$"))
|
|
366
|
+
if not author_url_matches
|
|
367
|
+
err = new Error("author_url doesn't match regexp, got: #{body_obj.author_url}")
|
|
368
|
+
return cb err, v_codes.CONTENT_FAILURE
|
|
369
|
+
|
|
370
|
+
[_, author_username] = author_url_matches
|
|
371
|
+
if not(sncmp(username, author_username))
|
|
372
|
+
err = new Error("username from author_url didn't match, expected: #{username}, got: #{author_username}")
|
|
373
|
+
return cb err, v_codes.BAD_USERNAME
|
|
374
|
+
|
|
375
|
+
if body_obj.html.length > 1000
|
|
376
|
+
err = new Error("html is #{body_obj.html.length} characters, not trying to parse it")
|
|
377
|
+
return cb err, v_codes.CONTENT_FAILURE
|
|
378
|
+
|
|
379
|
+
$ = @libs.cheerio.load body_obj.html
|
|
380
|
+
tweet_p = $('blockquote.twitter-tweet p')
|
|
381
|
+
if tweet_p.length isnt 1
|
|
382
|
+
err = new Error("failed to find tweet <p> in returned 'html' field")
|
|
383
|
+
return cb err, v_codes.FAILED_PARSE
|
|
384
|
+
|
|
385
|
+
rc = @find_sig_in_tweet { tweet_p, proof_text_check }
|
|
344
386
|
|
|
345
387
|
cb err, rc
|
|
346
388
|
|