keybase-proofs 2.3.25 → 2.3.28

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.
@@ -1,18 +1,44 @@
1
- {sncmp,BaseScraper} = require './base'
1
+ {sncmp,user_agent,BaseScraper,BaseBearerToken} = require './base'
2
2
  {constants} = require '../constants'
3
3
  {v_codes} = constants
4
4
  {proof_text_check_to_med_id} = require '../base'
5
+ urlmod = require 'url'
6
+ {inspect} = require 'util'
5
7
 
6
8
  #================================================================================
7
9
 
8
10
  PREFIX = "https://www.reddit.com"
9
11
  SUBREDDIT = PREFIX + "/r/keybaseproofs"
12
+ OAUTH_REDDIT_URL = "https://oauth.reddit.com"
13
+
14
+ REDDIT_USER_AGENT = user_agent + " (by /u/maxtaco)"
15
+
16
+ #================================================================================
17
+
18
+ class RedditBearerToken extends BaseBearerToken
19
+ constructor : ({@base}) ->
20
+ super {
21
+ name: "Reddit"
22
+ @base
23
+ access_token_url : "#{OAUTH_REDDIT_URL}/api/v1/access_token"
24
+ scope : [ 'history', 'read' ]
25
+ user_agent : REDDIT_USER_AGENT
26
+ }
27
+
28
+ #================================================================================
29
+
30
+ _bearer_token = null
31
+ bearer_token = ({base}) ->
32
+ unless _bearer_token
33
+ _bearer_token = new RedditBearerToken { base }
34
+ return _bearer_token
10
35
 
11
36
  #================================================================================
12
37
 
13
38
  exports.RedditScraper = class RedditScraper extends BaseScraper
14
39
 
15
40
  constructor: (opts) ->
41
+ @auth = opts.auth
16
42
  super opts
17
43
 
18
44
  # ---------------------------------------------------------------------------
@@ -38,8 +64,8 @@ exports.RedditScraper = class RedditScraper extends BaseScraper
38
64
  if (err = @_check_args { username, name })?
39
65
  return cb err, { rc: v_codes.BAD_ARGS }
40
66
 
41
- await @_get_url_body
42
- url: "#{PREFIX}/user/#{encodeURIComponent(username)}/submitted.json?count=25&cachebust=#{Math.random()}"
67
+ await @_get_body_api
68
+ url: "#{OAUTH_REDDIT_URL}/user/#{encodeURIComponent(username)}/submitted.json?count=25&cachebust=#{Math.random()}"
43
69
  json: true
44
70
  , defer err, rc, json
45
71
 
@@ -68,6 +94,9 @@ exports.RedditScraper = class RedditScraper extends BaseScraper
68
94
  if not proof_post?
69
95
  return cb null, rc: v_codes.NOT_FOUND
70
96
 
97
+ # NOTE: Still return "www.reddit.com" api_url instead of "oauth.reddit.com",
98
+ # for compatibility with existing rows in the keybase db. `check_status`
99
+ # method is rewriting www.reddit.com into oauth.reddit.com.
71
100
  cb null,
72
101
  rc : v_codes.OK
73
102
  api_url : PREFIX + proof_post.permalink + ".json"
@@ -109,12 +138,24 @@ exports.RedditScraper = class RedditScraper extends BaseScraper
109
138
  # ---------------------------------------------------------------------------
110
139
 
111
140
  check_status: ({username, api_url, proof_text_check, remote_id}, cb) ->
141
+ u = urlmod.parse(api_url)
142
+ unless u
143
+ return cb new Error "Failed to parse api_url"
144
+
145
+ # Host should either be www.reddit.com or oauth.reddit.com.
146
+ if u.host not in ['www.reddit.com', 'oauth.reddit.com']
147
+ return cb new Error "Unexpected api_url host: #{host}"
148
+
149
+ u = urlmod.format {
150
+ host : 'oauth.reddit.com'
151
+ protocol : 'https:'
152
+ pathname : u.pathname
153
+ }
112
154
 
113
155
  # calls back with a v_code or null if it was ok
114
- await @_get_url_body {
115
- url : api_url + "?cachebust=#{Math.random()}"
156
+ await @_get_body_api {
157
+ url : u
116
158
  json : true
117
- user_agent : "linux:com.github/keybase/proofs:v2.1.41 (by /u/maxtaco)"
118
159
  }, defer err, rc, json
119
160
 
120
161
  rc = if rc isnt v_codes.OK then rc
@@ -122,5 +163,32 @@ exports.RedditScraper = class RedditScraper extends BaseScraper
122
163
  else @check_post { post, username, proof_text_check }
123
164
  cb err, rc
124
165
 
166
+ # ---------------------------------------------------------------------------
167
+
168
+ _get_bearer_token : (cb) ->
169
+ bt = bearer_token { base : @ }
170
+ await bt.get defer err, tok
171
+ rc = if err? then v_codes.AUTH_FAILED else v_codes.OK
172
+ cb err, rc, tok
173
+
174
+ # ---------------------------------------------------------------------------
175
+
176
+ _get_body_api : ({url, json}, cb) ->
177
+ rc = body = err = null
178
+ await @_get_bearer_token defer err, rc, tok
179
+ unless err?
180
+ @log "| HTTP API request for URL '#{url}'"
181
+ json ?= true
182
+ args =
183
+ url : url
184
+ json : json
185
+ headers :
186
+ Authorization : "Bearer #{tok}"
187
+ method : "get"
188
+ json : true
189
+ user_agent : REDDIT_USER_AGENT
190
+ await @_get_url_body args, defer err, rc, body
191
+ cb err, rc, body
192
+
125
193
  #================================================================================
126
194
 
@@ -1,7 +1,6 @@
1
- {sncmp,BaseScraper} = require './base'
1
+ {sncmp,BaseScraper,BaseBearerToken} = require './base'
2
2
  {make_ids} = require '../base'
3
3
  {constants} = require '../constants'
4
- {Lock} = require '../util'
5
4
  {v_codes} = constants
6
5
  {decode_sig} = require('kbpgp').ukm
7
6
  urlmod = require 'url'
@@ -17,78 +16,27 @@ ws_normalize = (x) ->
17
16
 
18
17
  #================================================================================
19
18
 
20
- class BearerToken
21
-
22
- #----------------
23
-
19
+ class TwitterBearerToken extends BaseBearerToken
24
20
  constructor : ({@base}) ->
25
- @_tok = null
26
- @_created = 0
27
- @_lock = new Lock()
28
- @auth = @base.auth
29
-
30
- #----------------
31
-
32
- get : (cb) ->
33
- await @_lock.acquire defer()
34
- err = null
35
- now = Math.floor(Date.now() / 1000)
36
-
37
- if not (res = @_tok)? or (now - @_created > @auth.lifespan)
38
-
39
- @base.log "+ Request for bearer token"
40
-
41
- # Very crypto! Not sure why this is done, but it's done
42
- cred = (Buffer.from [ @auth.key, @auth.secret].join(":")).toString('base64')
43
-
44
- req = 'grant_type=client_credentials'
45
- opts =
46
- url : "https://api.twitter.com/oauth2/token"
47
- headers :
48
- Authorization : "Basic #{cred}"
49
- 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
50
- 'Content-Length': req.length
51
- method : "post"
52
- body : req
53
- await @base._get_url_body opts, defer err, rc, body
54
-
55
- if err?
56
- @base.logl 'error', "In getting bearer_token: #{err.message}"
57
- else if (rc isnt v_codes.OK)
58
- @base.logl 'error', "HTTP error in getting bearer token: #{rc}"
59
- err = new Error "HTTP error: #{rc}"
60
- else
61
- try
62
- body = JSON.parse body
63
- catch e
64
- @base.logl 'warn', "Could not parse JSON reply: #{e}"
65
- err = e
66
-
67
- if err? then # noop
68
- else if not (tok = body.access_token)?
69
- @base.logl 'warn', "No access token found in reply"
70
- err = new Error "Twitter error: no access token"
71
- else
72
- @_tok = tok
73
- @_created = Math.floor(Date.now() / 1000)
74
- res = @_tok
75
-
76
- @base.log "- Request for bearer token -> #{err}"
77
-
78
- @_lock.release()
79
- cb err, res
21
+ super {
22
+ name: "Twitter"
23
+ @base
24
+ access_token_url : "https://api.twitter.com/oauth2/token"
25
+ scope : [ 'history', 'read' ]
26
+ }
80
27
 
81
28
  #================================================================================
82
29
 
83
30
  _bearer_token = null
84
31
  bearer_token = ({base}) ->
85
32
  unless _bearer_token
86
- _bearer_token = new BearerToken { base }
33
+ _bearer_token = new TwitterBearerToken { base }
87
34
  return _bearer_token
88
35
 
89
36
  #================================================================================
90
37
 
91
38
  exports.TwitterScraper = class TwitterScraper extends BaseScraper
39
+ username_regexp = /^[a-z0-9_-]{2,15}$/
92
40
 
93
41
  constructor: (opts) ->
94
42
  @auth = opts.auth
@@ -101,6 +49,8 @@ exports.TwitterScraper = class TwitterScraper extends BaseScraper
101
49
  new Error "Bad args to Twitter proof: no username given"
102
50
  else if not (args.name?) or (args.name isnt 'twitter')
103
51
  new Error "Bad args to Twitter proof: type is #{args.name}"
52
+ else if not args.username.match(username_regexp)
53
+ new Error "Invalid username passed to Twitter proof"
104
54
  else
105
55
  null
106
56
 
@@ -113,25 +63,26 @@ exports.TwitterScraper = class TwitterScraper extends BaseScraper
113
63
 
114
64
  return cb(err,out) if (err = @_check_args { username, name })?
115
65
 
66
+ endpoint_name = "/2/tweets/search/recent"
116
67
  u = urlmod.format {
117
68
  host : "api.twitter.com"
118
69
  protocol : "https:"
119
- pathname : "/1.1/statuses/user_timeline.json"
70
+ pathname : endpoint_name
120
71
  query :
121
- count : 100
122
- screen_name : username
72
+ query : "\"Verifying myself\" \"Keybase.io\" from:#{username}"
123
73
  }
124
-
125
- await @_get_body_api { url : u }, defer err, rc, json
74
+ await @_get_body_api { url : u, endpoint_name }, defer err, rc, json
126
75
  @log "| search index #{u} -> #{rc}"
127
76
  if rc isnt v_codes.OK then #noop
128
77
  else if not json? or (json.length is 0) then rc = v_codes.EMPTY_JSON
78
+ else if not json.data? then rc = v_codes.INVALID_JSON
129
79
  else
130
- for {text, id_str},i in json
80
+ rc = v_codes.NOT_FOUND
81
+ for {text, id},i in json.data
131
82
  if (@find_sig_in_tweet { inside : text, proof_text_check }) is v_codes.OK
132
83
  @log "| found valid tweet in stream @ #{i}"
133
84
  rc = v_codes.OK
134
- remote_id = id_str
85
+ remote_id = id
135
86
  api_url = human_url = @_id_to_url username, remote_id
136
87
  out = { remote_id, api_url, human_url }
137
88
  break
@@ -397,7 +348,7 @@ exports.TwitterScraper = class TwitterScraper extends BaseScraper
397
348
  # ---------------------------------------------------------------------------
398
349
 
399
350
  # Only the hunter needs this
400
- _get_body_api : ({url}, cb) ->
351
+ _get_body_api : ({url, endpoint_name}, cb) ->
401
352
  rc = body = err = null
402
353
  await @_get_bearer_token defer err, rc, tok
403
354
  unless err?
@@ -408,6 +359,8 @@ exports.TwitterScraper = class TwitterScraper extends BaseScraper
408
359
  Authorization : "Bearer #{tok}"
409
360
  method : "get"
410
361
  json : true
362
+ log_ratelimit : endpoint_name?
363
+ endpoint_name : endpoint_name
411
364
  await @_get_url_body args, defer err, rc, body
412
365
  cb err, rc, body
413
366
 
package/SIGNED.md DELETED
@@ -1,131 +0,0 @@
1
- ##### Signed by https://keybase.io/max
2
- ```
3
- -----BEGIN PGP SIGNATURE-----
4
- Comment: GPGTools - https://gpgtools.org
5
-
6
- iQEcBAABCgAGBQJWBZ3PAAoJEJgKPw0B/gTfPrkIALMDLUb+CS2oPrFZlILoC31o
7
- FUKtCiN+hzC9+FgMYp18kWsWDh3DxzqPIRs28mwt9QMQTHdywv6K+nfQw2dE4wns
8
- 1Wi7ZVPbvR5P0/ANIQ0QwetYxbkNow20dU67CRj0aEvvbopQDBgBgyH9b6LjSb+n
9
- 8OTUFLhtiXN0PeZJ5/OyMtq8jyrjT7MEpxAb+8uFt95fPax17TNjCBEF4mlNqvtl
10
- YIOd/1v6YTlaqbYSzEZoMZsSI12UGK/tLaPG6qYf+5gGi96YjEMuQyDsL7ANQpkG
11
- jplkuKpykiY1Ndc1B3TOnTK8n+lrRaWesLmHnhldhR047ZNYgETunz+NYks7MHI=
12
- =96ur
13
- -----END PGP SIGNATURE-----
14
-
15
- ```
16
-
17
- <!-- END SIGNATURES -->
18
-
19
- ### Begin signed statement
20
-
21
- #### Expect
22
-
23
- ```
24
- size exec file contents
25
- ./
26
- 109 .gitignore ec278daeb8f83cac2579d262b92ee6d7d872c4d1544e881ba515d8bcc05361ab
27
- 10709 CHANGELOG.md 8ce81ae853a72be10648f712497199b316dfe57c8519853687cee1b508965af1
28
- 66 CONTIBUTORS.md e5a536ada9dc7f25b352f28cc8936db4ded1a0860f6f23ef61d0b14aeae351da
29
- 1483 LICENSE 333be7050513d91d9e77ca9acb4a91261721f0050209636076ed58676bfc643d
30
- 1383 Makefile b90c2b9165497660a610d5ec6177b854aafaa318aa1252af23484c755f1d959a
31
- 43 README.md b2db580fc880756ae739bb148570f6afb1c250e5c0d2c5fa56ce41491753ca6c
32
- lib/
33
- 2498 alloc.js af1347e6f17197fee04fba783839279b07b07f79bf407ddf44e09d360289aa48
34
- 1189 announcement.js ff01f39dca21c1387faa8b79633dec40414f5645886015a46bd795772987c79e
35
- 1383 auth.js 86403419686d1cac766c8d3d6c8f6e10176694e33de84faafca652fd01e54e0e
36
- 766 b64extract.js 1466f81bb930ddc439f877ef0cba4d20048f5477aafda294290f0fd0da527073
37
- 33694 base.js b57791baad7fd3b648749320875ada1adc6e8d0dc3265c6f2fe4faeb960c05bb
38
- 2043 constants.js e88df2ce555fe3fa8f70bbac3ebdca7c169571cbd5055948ecd8215e231d75fb
39
- 1382 cryptocurrency.js 40536713081183e8b698a345df9a288a0967e1c95bd0699fe8ea18b618a6de6a
40
- 1087 device.js f77d694ccf19c81b8c1977bb5c0280979a8b15983ced95675d6f5d44cedf67a7
41
- 1294 eldest.js 878cc36219a2d25c1e1897a672f03b5d97ece05581b6ece7707e78cbb0a8e02e
42
- 909 main.js 1cc4c7fd9cfee3ce317d8993507a953c8a22803eaea69eb16d4c7be9c0d7731b
43
- 1549 pgp_update.js c084bee65b6e7cee2d9fd7ddeea107751a319c03831205005ed997fa4840f939
44
- 2578 revoke.js 57106f23d108ce01a6d781a795417c86a09633af73ff1c9630d3893a8bc47e5f
45
- scrapers/
46
- 6392 base.js db98e2349217287c98feba718b0bdd9570c5e1108370942af9ca2a2b59be5ed9
47
- 15450 bitbucket.js 7530f245a6836d29177cae7e2a1e0efa9860e1adc9965731cf1e79c5f82f3f4c
48
- 4137 coinbase.js 5d28f2c525f69e64881d0ae5dd38c535a324f894d98b67d1a5b8217a4c564ce3
49
- 8239 dns.js 74ced258122595b80997594c4f8fb82c210b5f316848b035b2b66582bb6052e8
50
- 9369 generic_web_site.js aa3fff8c4d36f86182666642117ec71c4c1574d44eeeba675f698d08fb9a1edd
51
- 9901 github.js 221586b7fd13ec28a51479319902fdb143a1b37d25dcdb7926826b100917ffbd
52
- 5995 hackernews.js 0e73885c9dba4dbba56fc042afe6002aeae1699094f77555c831d2a15348033c
53
- 8535 reddit.js 508d1b349ce6a992afe5c882d7c541c1ff85990645343dbfd748c09888d8ce3f
54
- 27418 twitter.js fda7930b6de79013601c22d0585833e6c2bf09594ec7890a4852ef3e21d24df5
55
- 1774 sibkey.js b434bb5e226214d5113eae44201ead14e7430bc92e56e2446e80d2cf9076ab1d
56
- 10983 subkey.js 76aca817ffb548ffe3dd668d9c2b189c3c3040300f748c6acf105c5f5a5dae82
57
- 1669 track.js b85423eb1309ac58f5cb2b68697f612c091ef2d44fa8cc9e4b85ab6039ae8b9a
58
- 1506 update_passphrase_hash.js f2cfce382fd677e31a88f3646eb2d90258583a1ef68fe74dcd178a2e178229f6
59
- 1544 util.js 1760f3955e71bed8a332c02a1c9a96733f9af0e0f297c89ec354f83ed5bf3908
60
- 19530 web_service.js 769a2c81aeb9b76ec627126776c346c20209ed588536dca528a617b5fbcdc553
61
- 744 package.json b670f8f7efdd7d69fa92f089729bdfe4486ded548e03b677bab888e3e21f2ab0
62
- src/
63
- 2376 alloc.iced bce30dc075d16e0551aeb8ce89f2a0515e8b061f7cbd1c9842a93756c028254b
64
- 537 announcement.iced 98ddc17f5c6b66874ed2a273032d5c5e118d1ef3a7f5a08f4c7fb9cf06e811cf
65
- 671 auth.iced 3f0f211734a2f8408a5f5e1f5c353cad3373f952b01209f0f2d644b681612b0e
66
- 704 b64extract.iced 47b06460fd61d8eb788878566c62086b1fd1f792a1712b3e8736766401bc8fee
67
- 15746 base.iced cbd3229cab90232ce33ca7ced8c2d492c2eaa5091a48019486f401f3df689f4a
68
- 2264 constants.iced ed833b20ade7e8e95d1e4c65577cfb8e7de20b554afaf7aaa7963e86d5f2b370
69
- 609 cryptocurrency.iced 9c839bdd1c12591ca73c6fbc86d44c51f1803718d37286e9eade945bee0761d1
70
- 489 device.iced b0c028eb2598c48d9d24be615e066e0a03e8b7b1930a4ca58f29d23517daf0bc
71
- 566 eldest.iced 8dd63bec35fca4ab933de049888777e957827a862ecf2dec7e91e91e4265917c
72
- 741 main.iced 0c4af12c6c069e3ece0f446c922ba8f306df4f386e3bee3c4ba852bc92a4df0b
73
- 589 pgp_update.iced cdc5fed1d47c0bfe144062cf7985d466ced99fb8ec7bd17901d504127359fc64
74
- 788 revoke.iced 2b94671a923dcdd274d0f769f186f0757a27db64828eaad5fa5eb1a24f9e479f
75
- scrapers/
76
- 4029 base.iced e110786284dda6cd78bc0be507ff9ac0add3a128c959c073562416b513d8b2d8
77
- 3967 bitbucket.iced f22e9c29d781afbecccc0c720513fa63710e3c199cc9780ef34b87a4db0e1fd9
78
- 2370 coinbase.iced 5b1132561f0c33d4c35ba2d7d9c32200e77d83c68a3bce3d770b27085d649bcd
79
- 4081 dns.iced 773ea8e65f46b2db994e41ed4849c4637200ee2e978f280524d63b06a42ff454
80
- 3249 generic_web_site.iced 7a70be6c922e5adb73459973b81143ec9020b109cdbcc5acf349e47c5ca1f68d
81
- 3305 github.iced f10410ccca3bb3fc5045024dada97a4974984ee433476bea30c1ab47f870da90
82
- 2909 hackernews.iced cb14793b3ea889bcbc2121430bc3728655e125806001211864d3c90c1104505a
83
- 4082 reddit.iced 8a4f6902eee7e1609df18bf9a00b5934d2e9a16eaf20bd6231b3d11b2554effe
84
- 11418 twitter.iced 9bbb6cfdc464a5ed3261cc8f1a14a12e18325d6b0edc753c7a9e133b58d9328e
85
- 761 sibkey.iced 308c4cfef33dbc79809600a46c4f1704d4240be18478d2e5e8f71e523fd6962d
86
- 3503 subkey.iced 6f41a5aa38813486cbcb5a3c918c2e7aa464665b9dac852f92bb62ffa1e0a3b1
87
- 838 track.iced d72d0eb5cda7f0f9800f17225fedf552f45111b802f66c463c4408794bd11aca
88
- 658 update_passphrase_hash.iced ea87dd15d3a36ee581e48a5436f4c64f38a102906efcdc20bc925b821210bfd9
89
- 1052 util.iced 88092afaf23bf8dfe42a72252ac156be45e94588911584ecf535d228b108f2b9
90
- 10177 web_service.iced bb436e165233be85342d0abe01237fcfb5773b0cc050abef49f1f19094abd8f0
91
- 1673 test_scraper.iced 099823ea87768b45dd205bd6dc36773999730dadb26fe3844e0a05f8668bb9d1
92
- ```
93
-
94
- #### Ignore
95
-
96
- ```
97
- /SIGNED.md
98
- ```
99
-
100
- #### Presets
101
-
102
- ```
103
- git # ignore .git and anything as described by .gitignore files
104
- dropbox # ignore .dropbox-cache and other Dropbox-related files
105
- kb # ignore anything as described by .kbignore files
106
- ```
107
-
108
- <!-- summarize version = 0.0.9 -->
109
-
110
- ### End signed statement
111
-
112
- <hr>
113
-
114
- #### Notes
115
-
116
- With keybase you can sign any directory's contents, whether it's a git repo,
117
- source code distribution, or a personal documents folder. It aims to replace the drudgery of:
118
-
119
- 1. comparing a zipped file to a detached statement
120
- 2. downloading a public key
121
- 3. confirming it is in fact the author's by reviewing public statements they've made, using it
122
-
123
- All in one simple command:
124
-
125
- ```bash
126
- keybase dir verify
127
- ```
128
-
129
- There are lots of options, including assertions for automating your checks.
130
-
131
- For more info, check out https://keybase.io/docs/command_line/code_signing