keybase-proofs 2.3.30 → 2.3.32
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 +9 -0
- package/lib/constants.js +1 -0
- package/lib/scrapers/generic_web_site.js +10 -8
- package/lib/scrapers/twitter.js +33 -18
- package/package.json +1 -1
- package/src/constants.iced +2 -0
- package/src/scrapers/generic_web_site.iced +3 -1
- package/src/scrapers/twitter.iced +29 -6
- package/test/make_esc.iced +48 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## 2.3.32 (2026-05-28)
|
|
2
|
+
|
|
3
|
+
- Fix Twitter scraper, allow returned URL to be either in x.com or twitter.com
|
|
4
|
+
domain.
|
|
5
|
+
|
|
6
|
+
## 2.3.31 (2025-12-18)
|
|
7
|
+
|
|
8
|
+
- Set response size limit when making a request in GenericWebSiteScraper.
|
|
9
|
+
|
|
1
10
|
## 2.3.30 (2025-02-28)
|
|
2
11
|
|
|
3
12
|
- Fix BaseScraper not properly handling promise rejections when fetching text
|
package/lib/constants.js
CHANGED
|
@@ -58,19 +58,21 @@
|
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
GenericWebSiteScraper.prototype._check_url = function(_arg, cb) {
|
|
61
|
-
var err, proof_text_check, raw, rc, url, ___iced_passed_deferral, __iced_deferrals, __iced_k;
|
|
61
|
+
var err, proof_text_check, raw, rc, size, url, ___iced_passed_deferral, __iced_deferrals, __iced_k;
|
|
62
62
|
__iced_k = __iced_k_noop;
|
|
63
63
|
___iced_passed_deferral = iced.findDeferral(arguments);
|
|
64
64
|
url = _arg.url, proof_text_check = _arg.proof_text_check;
|
|
65
|
+
size = constants.generic_website_max_size;
|
|
65
66
|
(function(_this) {
|
|
66
67
|
return (function(__iced_k) {
|
|
67
68
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
68
69
|
parent: ___iced_passed_deferral,
|
|
69
|
-
filename: "/Users/
|
|
70
|
+
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/proofs/src/scrapers/generic_web_site.iced",
|
|
70
71
|
funcname: "GenericWebSiteScraper._check_url"
|
|
71
72
|
});
|
|
72
73
|
_this._get_url_body({
|
|
73
|
-
url: url
|
|
74
|
+
url: url,
|
|
75
|
+
size: size
|
|
74
76
|
}, __iced_deferrals.defer({
|
|
75
77
|
assign_fn: (function() {
|
|
76
78
|
return function() {
|
|
@@ -79,7 +81,7 @@
|
|
|
79
81
|
return raw = arguments[2];
|
|
80
82
|
};
|
|
81
83
|
})(),
|
|
82
|
-
lineno:
|
|
84
|
+
lineno: 50
|
|
83
85
|
}));
|
|
84
86
|
__iced_deferrals._fulfill();
|
|
85
87
|
});
|
|
@@ -132,7 +134,7 @@
|
|
|
132
134
|
(function(__iced_k) {
|
|
133
135
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
134
136
|
parent: ___iced_passed_deferral,
|
|
135
|
-
filename: "/Users/
|
|
137
|
+
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/proofs/src/scrapers/generic_web_site.iced",
|
|
136
138
|
funcname: "GenericWebSiteScraper.hunt2"
|
|
137
139
|
});
|
|
138
140
|
_this._check_url({
|
|
@@ -145,7 +147,7 @@
|
|
|
145
147
|
return rc = arguments[1];
|
|
146
148
|
};
|
|
147
149
|
})(),
|
|
148
|
-
lineno:
|
|
150
|
+
lineno: 68
|
|
149
151
|
}));
|
|
150
152
|
__iced_deferrals._fulfill();
|
|
151
153
|
})(function() {
|
|
@@ -215,7 +217,7 @@ _break()
|
|
|
215
217
|
return (function(__iced_k) {
|
|
216
218
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
217
219
|
parent: ___iced_passed_deferral,
|
|
218
|
-
filename: "/Users/
|
|
220
|
+
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/proofs/src/scrapers/generic_web_site.iced",
|
|
219
221
|
funcname: "GenericWebSiteScraper.check_status"
|
|
220
222
|
});
|
|
221
223
|
_this._check_url({
|
|
@@ -228,7 +230,7 @@ _break()
|
|
|
228
230
|
return rc = arguments[1];
|
|
229
231
|
};
|
|
230
232
|
})(),
|
|
231
|
-
lineno:
|
|
233
|
+
lineno: 97
|
|
232
234
|
}));
|
|
233
235
|
__iced_deferrals._fulfill();
|
|
234
236
|
});
|
package/lib/scrapers/twitter.js
CHANGED
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
return (function(__iced_k) {
|
|
114
114
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
115
115
|
parent: ___iced_passed_deferral,
|
|
116
|
-
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/
|
|
116
|
+
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/proofs/src/scrapers/twitter.iced",
|
|
117
117
|
funcname: "TwitterScraper.hunt2"
|
|
118
118
|
});
|
|
119
119
|
_this._get_body_api({
|
|
@@ -222,7 +222,7 @@
|
|
|
222
222
|
(function(__iced_k) {
|
|
223
223
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
224
224
|
parent: ___iced_passed_deferral,
|
|
225
|
-
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/
|
|
225
|
+
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/proofs/src/scrapers/twitter.iced",
|
|
226
226
|
funcname: "TwitterScraper.users_lookup"
|
|
227
227
|
});
|
|
228
228
|
_this._get_body_api({
|
|
@@ -265,7 +265,7 @@
|
|
|
265
265
|
(function(__iced_k) {
|
|
266
266
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
267
267
|
parent: ___iced_passed_deferral,
|
|
268
|
-
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/
|
|
268
|
+
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/proofs/src/scrapers/twitter.iced",
|
|
269
269
|
funcname: "TwitterScraper.users_lookup"
|
|
270
270
|
});
|
|
271
271
|
setTimeout(__iced_deferrals.defer({
|
|
@@ -351,7 +351,7 @@
|
|
|
351
351
|
(function(__iced_k) {
|
|
352
352
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
353
353
|
parent: ___iced_passed_deferral,
|
|
354
|
-
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/
|
|
354
|
+
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/proofs/src/scrapers/twitter.iced",
|
|
355
355
|
funcname: "TwitterScraper.get_follower_ids"
|
|
356
356
|
});
|
|
357
357
|
_this._get_body_api({
|
|
@@ -397,7 +397,7 @@
|
|
|
397
397
|
(function(__iced_k) {
|
|
398
398
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
399
399
|
parent: ___iced_passed_deferral,
|
|
400
|
-
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/
|
|
400
|
+
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/proofs/src/scrapers/twitter.iced",
|
|
401
401
|
funcname: "TwitterScraper.get_follower_ids"
|
|
402
402
|
});
|
|
403
403
|
setTimeout(__iced_deferrals.defer({
|
|
@@ -483,6 +483,21 @@
|
|
|
483
483
|
return rc;
|
|
484
484
|
};
|
|
485
485
|
|
|
486
|
+
TwitterScraper.prototype._comp_twitter_url = function(url_a_str, url_b_str) {
|
|
487
|
+
var twitter_hosts, url_a, url_b;
|
|
488
|
+
if (!url_a_str || !url_b_str) {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
twitter_hosts = ['x.com', 'twitter.com'];
|
|
492
|
+
try {
|
|
493
|
+
url_a = new urlmod.URL(url_a_str.toLowerCase());
|
|
494
|
+
url_b = new urlmod.URL(url_b_str.toLowerCase());
|
|
495
|
+
return twitter_hosts.includes(url_a.host) && twitter_hosts.includes(url_b.host) && url_a.protocol === url_b.protocol && url_a.pathname === url_b.pathname && url_a.search === url_b.search && url_a.hash === url_b.hash;
|
|
496
|
+
} catch (_error) {
|
|
497
|
+
return false;
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
|
|
486
501
|
TwitterScraper.prototype.check_status = function(_arg, cb) {
|
|
487
502
|
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;
|
|
488
503
|
__iced_k = __iced_k_noop;
|
|
@@ -503,7 +518,7 @@
|
|
|
503
518
|
return (function(__iced_k) {
|
|
504
519
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
505
520
|
parent: ___iced_passed_deferral,
|
|
506
|
-
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/
|
|
521
|
+
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/proofs/src/scrapers/twitter.iced",
|
|
507
522
|
funcname: "TwitterScraper.check_status"
|
|
508
523
|
});
|
|
509
524
|
_this._get_url_body({
|
|
@@ -517,7 +532,7 @@
|
|
|
517
532
|
return body_obj = arguments[2];
|
|
518
533
|
};
|
|
519
534
|
})(),
|
|
520
|
-
lineno:
|
|
535
|
+
lineno: 309
|
|
521
536
|
}));
|
|
522
537
|
__iced_deferrals._fulfill();
|
|
523
538
|
});
|
|
@@ -532,16 +547,16 @@
|
|
|
532
547
|
if (err = schm.check(body_obj)) {
|
|
533
548
|
return cb(err, v_codes.CONTENT_FAILURE);
|
|
534
549
|
}
|
|
535
|
-
if (!(
|
|
550
|
+
if (!(_this._comp_twitter_url(body_obj.url, api_url))) {
|
|
536
551
|
err = new Error("returned url field doesn't match api_url (found: " + body_obj.url + ", expected: " + api_url + ")");
|
|
537
552
|
return cb(err, v_codes.CONTENT_FAILURE);
|
|
538
553
|
}
|
|
539
|
-
api_url_matches = api_url.match(new RegExp("^https://twitter\\.com/([^/]+)/status/(\\d+)(.*)$"));
|
|
554
|
+
api_url_matches = api_url.match(new RegExp("^https://(x|twitter)\\.com/([^/]+)/status/(\\d+)(.*)$"));
|
|
540
555
|
if (!api_url_matches) {
|
|
541
556
|
err = new Error("api_url field doesn't match regexp, got: " + api_url_matches);
|
|
542
557
|
return cb(err, v_codes.CONTENT_FAILURE);
|
|
543
558
|
}
|
|
544
|
-
_ = api_url_matches[0],
|
|
559
|
+
_ = api_url_matches[0], _ = api_url_matches[1], username_from_url = api_url_matches[2], tweet_id = api_url_matches[3];
|
|
545
560
|
if (!(sncmp(username, username_from_url))) {
|
|
546
561
|
err = new Error("username from api_url didn't match, expected: " + username + ", got: " + username_from_url);
|
|
547
562
|
return cb(err, v_codes.BAD_USERNAME);
|
|
@@ -549,12 +564,12 @@
|
|
|
549
564
|
if (tweet_id !== remote_id.toString()) {
|
|
550
565
|
return cb(err, v_codes.BAD_REMOTE_ID);
|
|
551
566
|
}
|
|
552
|
-
author_url_matches = body_obj.author_url.match(new RegExp("^https://twitter\\.com/(.+)$"));
|
|
567
|
+
author_url_matches = body_obj.author_url.match(new RegExp("^https://(x|twitter)\\.com/(.+)$"));
|
|
553
568
|
if (!author_url_matches) {
|
|
554
569
|
err = new Error("author_url doesn't match regexp, got: " + body_obj.author_url);
|
|
555
570
|
return cb(err, v_codes.CONTENT_FAILURE);
|
|
556
571
|
}
|
|
557
|
-
_ = author_url_matches[0],
|
|
572
|
+
_ = author_url_matches[0], _ = author_url_matches[1], author_username = author_url_matches[2];
|
|
558
573
|
if (!(sncmp(username, author_username))) {
|
|
559
574
|
err = new Error("username from author_url didn't match, expected: " + username + ", got: " + author_username);
|
|
560
575
|
return cb(err, v_codes.BAD_USERNAME);
|
|
@@ -590,7 +605,7 @@
|
|
|
590
605
|
return (function(__iced_k) {
|
|
591
606
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
592
607
|
parent: ___iced_passed_deferral,
|
|
593
|
-
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/
|
|
608
|
+
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/proofs/src/scrapers/twitter.iced",
|
|
594
609
|
funcname: "TwitterScraper._get_bearer_token"
|
|
595
610
|
});
|
|
596
611
|
bt.get(__iced_deferrals.defer({
|
|
@@ -600,7 +615,7 @@
|
|
|
600
615
|
return tok = arguments[1];
|
|
601
616
|
};
|
|
602
617
|
})(),
|
|
603
|
-
lineno:
|
|
618
|
+
lineno: 372
|
|
604
619
|
}));
|
|
605
620
|
__iced_deferrals._fulfill();
|
|
606
621
|
});
|
|
@@ -622,7 +637,7 @@
|
|
|
622
637
|
return (function(__iced_k) {
|
|
623
638
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
624
639
|
parent: ___iced_passed_deferral,
|
|
625
|
-
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/
|
|
640
|
+
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/proofs/src/scrapers/twitter.iced",
|
|
626
641
|
funcname: "TwitterScraper._get_body_api"
|
|
627
642
|
});
|
|
628
643
|
_this._get_bearer_token(__iced_deferrals.defer({
|
|
@@ -633,7 +648,7 @@
|
|
|
633
648
|
return tok = arguments[2];
|
|
634
649
|
};
|
|
635
650
|
})(),
|
|
636
|
-
lineno:
|
|
651
|
+
lineno: 381
|
|
637
652
|
}));
|
|
638
653
|
__iced_deferrals._fulfill();
|
|
639
654
|
});
|
|
@@ -655,7 +670,7 @@
|
|
|
655
670
|
(function(__iced_k) {
|
|
656
671
|
__iced_deferrals = new iced.Deferrals(__iced_k, {
|
|
657
672
|
parent: ___iced_passed_deferral,
|
|
658
|
-
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/
|
|
673
|
+
filename: "/Users/michal/SourceCode/keybase/go/src/github.com/keybase/proofs/src/scrapers/twitter.iced",
|
|
659
674
|
funcname: "TwitterScraper._get_body_api"
|
|
660
675
|
});
|
|
661
676
|
_this._get_url_body(args, __iced_deferrals.defer({
|
|
@@ -666,7 +681,7 @@
|
|
|
666
681
|
return body = arguments[2];
|
|
667
682
|
};
|
|
668
683
|
})(),
|
|
669
|
-
lineno:
|
|
684
|
+
lineno: 392
|
|
670
685
|
}));
|
|
671
686
|
__iced_deferrals._fulfill();
|
|
672
687
|
})(__iced_k);
|
package/package.json
CHANGED
package/src/constants.iced
CHANGED
|
@@ -115,8 +115,10 @@ exports.constants = constants =
|
|
|
115
115
|
generic_web_site : 1000
|
|
116
116
|
dns : 1001
|
|
117
117
|
pgp : 1002
|
|
118
|
+
|
|
118
119
|
expire_in : 60*60*24*365*5 # 5 years....
|
|
119
120
|
http_timeout : 15*1000 # give up after 15 seconds....
|
|
121
|
+
generic_website_max_size : 128000 # do not download more than 128KB from generic websites
|
|
120
122
|
short_id_bytes : 27
|
|
121
123
|
shortest_pgp_signature : 100 # can't have a PGP signature shorter than this...
|
|
122
124
|
critical_clock_skew_secs : 65*60 # if you clock is ~1 hour off, we won't accept the sig
|
|
@@ -45,8 +45,10 @@ exports.GenericWebSiteScraper = class GenericWebSiteScraper extends BaseScraper
|
|
|
45
45
|
# ---------------------------------------------------------------------------
|
|
46
46
|
|
|
47
47
|
_check_url : ( { url, proof_text_check }, cb) ->
|
|
48
|
+
# limit how much data we want to receive from arbitrary websites
|
|
49
|
+
size = constants.generic_website_max_size
|
|
48
50
|
# calls back with a v_code or null if it was ok
|
|
49
|
-
await @_get_url_body {url }, defer err, rc, raw
|
|
51
|
+
await @_get_url_body { url, size }, defer err, rc, raw
|
|
50
52
|
rc = if rc isnt v_codes.OK then rc
|
|
51
53
|
else if @_find_sig_in_raw(proof_text_check, raw) then v_codes.OK
|
|
52
54
|
else v_codes.NOT_FOUND
|
|
@@ -262,6 +262,27 @@ exports.TwitterScraper = class TwitterScraper extends BaseScraper
|
|
|
262
262
|
|
|
263
263
|
# ---------------------------------------------------------------------------
|
|
264
264
|
|
|
265
|
+
_comp_twitter_url : (url_a_str, url_b_str) ->
|
|
266
|
+
# Do a smarter check for twitter URL but allowing hosts to be either
|
|
267
|
+
# x.com or twitter.com. Rest of the URL has to match (protocol, path,
|
|
268
|
+
# hash etc.)
|
|
269
|
+
if not url_a_str or not url_b_str
|
|
270
|
+
return false
|
|
271
|
+
twitter_hosts = ['x.com', 'twitter.com']
|
|
272
|
+
try
|
|
273
|
+
url_a = new urlmod.URL(url_a_str.toLowerCase())
|
|
274
|
+
url_b = new urlmod.URL(url_b_str.toLowerCase())
|
|
275
|
+
return (
|
|
276
|
+
twitter_hosts.includes(url_a.host) and
|
|
277
|
+
twitter_hosts.includes(url_b.host) and
|
|
278
|
+
url_a.protocol is url_b.protocol and
|
|
279
|
+
url_a.pathname is url_b.pathname and
|
|
280
|
+
url_a.search is url_b.search and
|
|
281
|
+
url_a.hash is url_b.hash
|
|
282
|
+
)
|
|
283
|
+
catch
|
|
284
|
+
return false
|
|
285
|
+
|
|
265
286
|
check_status: ({username, api_url, proof_text_check, remote_id}, cb) ->
|
|
266
287
|
|
|
267
288
|
if not api_url?.length
|
|
@@ -297,20 +318,22 @@ exports.TwitterScraper = class TwitterScraper extends BaseScraper
|
|
|
297
318
|
if err = schm.check body_obj
|
|
298
319
|
return cb err, v_codes.CONTENT_FAILURE
|
|
299
320
|
|
|
300
|
-
# "url" field returned by the API should match api_url
|
|
301
|
-
|
|
321
|
+
# "url" field returned by the API should match api_url, but twitter may
|
|
322
|
+
# return x.com domain in the "url" field. Our `api_url` is always
|
|
323
|
+
# twitter.com right now (for new and existing proofs).
|
|
324
|
+
if not(@_comp_twitter_url(body_obj.url, api_url))
|
|
302
325
|
err = new Error "returned url field doesn't match api_url (found: #{body_obj.url}, expected: #{api_url})"
|
|
303
326
|
return cb err, v_codes.CONTENT_FAILURE
|
|
304
327
|
|
|
305
328
|
# Extract username from URL, do not use "author_name" because it's the
|
|
306
329
|
# full name.
|
|
307
|
-
api_url_matches = api_url.match(new RegExp("^https://twitter\\.com/([^/]+)/status/(\\d+)(.*)$"))
|
|
330
|
+
api_url_matches = api_url.match(new RegExp("^https://(x|twitter)\\.com/([^/]+)/status/(\\d+)(.*)$"))
|
|
308
331
|
if not api_url_matches
|
|
309
332
|
err = new Error "api_url field doesn't match regexp, got: #{api_url_matches}"
|
|
310
333
|
return cb err, v_codes.CONTENT_FAILURE
|
|
311
334
|
|
|
312
335
|
# Check username and tweet ID.
|
|
313
|
-
[_, username_from_url, tweet_id] = api_url_matches
|
|
336
|
+
[_, _, username_from_url, tweet_id] = api_url_matches
|
|
314
337
|
if not(sncmp(username, username_from_url))
|
|
315
338
|
err = new Error("username from api_url didn't match, expected: #{username}, got: #{username_from_url}")
|
|
316
339
|
return cb err, v_codes.BAD_USERNAME
|
|
@@ -319,12 +342,12 @@ exports.TwitterScraper = class TwitterScraper extends BaseScraper
|
|
|
319
342
|
|
|
320
343
|
# Check "author_url" field, it contains a link to user's twitter profile.
|
|
321
344
|
# It should match our username.
|
|
322
|
-
author_url_matches = body_obj.author_url.match(new RegExp("^https://twitter\\.com/(.+)$"))
|
|
345
|
+
author_url_matches = body_obj.author_url.match(new RegExp("^https://(x|twitter)\\.com/(.+)$"))
|
|
323
346
|
if not author_url_matches
|
|
324
347
|
err = new Error("author_url doesn't match regexp, got: #{body_obj.author_url}")
|
|
325
348
|
return cb err, v_codes.CONTENT_FAILURE
|
|
326
349
|
|
|
327
|
-
[_, author_username] = author_url_matches
|
|
350
|
+
[_, _, author_username] = author_url_matches
|
|
328
351
|
if not(sncmp(username, author_username))
|
|
329
352
|
err = new Error("username from author_url didn't match, expected: #{username}, got: #{author_username}")
|
|
330
353
|
return cb err, v_codes.BAD_USERNAME
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
C = require('iced-runtime').const
|
|
2
|
+
|
|
3
|
+
exports.skip = true
|
|
4
|
+
|
|
5
|
+
ipush = (e, msg) ->
|
|
6
|
+
if msg?
|
|
7
|
+
# Note: `e.istack = []` will be a noop if e is a primitive type
|
|
8
|
+
# like number or string. We have to check if `e.istack` exists
|
|
9
|
+
# before pushing so we don't crash.
|
|
10
|
+
e.istack = [] unless e.istack?
|
|
11
|
+
e.istack?.push msg
|
|
12
|
+
|
|
13
|
+
copy_trace = (src, dst) ->
|
|
14
|
+
dst[C.trace] = src[C.trace]
|
|
15
|
+
dst
|
|
16
|
+
|
|
17
|
+
# Error short-circuit connector with more verbose istack.
|
|
18
|
+
|
|
19
|
+
# When resulting `esc` function is called, an istack entry will be constructed
|
|
20
|
+
# based on iced trace object. This way istack will be populated by not only esc
|
|
21
|
+
# identifiers (usually call site function names) but also filenames and line
|
|
22
|
+
# numbers of call sites of individual esc() calls. If an error happens and
|
|
23
|
+
# short-circuited back from deep in some test, it should be easier to identify
|
|
24
|
+
# where exactly it originates from using the new istack.
|
|
25
|
+
|
|
26
|
+
exports.make_esc = make_esc = (gcb, where) ->
|
|
27
|
+
# Create "global where" based on make_esc() call site.
|
|
28
|
+
where = make_esc.caller?.name unless where?
|
|
29
|
+
return (lcb) ->
|
|
30
|
+
# Create "local where" based on esc() call site. So every
|
|
31
|
+
# esc(defer(...)) will have its own istack entry, if iced
|
|
32
|
+
# trace object is available.
|
|
33
|
+
sb = [ where ]
|
|
34
|
+
if (tr = lcb[C.trace])
|
|
35
|
+
sb.push "Trace:"
|
|
36
|
+
sb.push tr[C.funcname]
|
|
37
|
+
sb.push "(#{tr[C.filename]}:#{tr[C.lineno] + 1})"
|
|
38
|
+
local_where = sb.filter((x) -> x).join(' ')
|
|
39
|
+
copy_trace lcb, (err, args...) ->
|
|
40
|
+
if not err? then lcb args...
|
|
41
|
+
else if not gcb.__esc
|
|
42
|
+
gcb.__esc = true
|
|
43
|
+
ipush err, local_where
|
|
44
|
+
gcb err
|
|
45
|
+
|
|
46
|
+
exports.patch_make_esc = () ->
|
|
47
|
+
iced_error = require 'iced-error'
|
|
48
|
+
iced_error.make_esc = make_esc
|