keybase-proofs 2.3.33 → 2.3.34
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/.github/workflows/ci.yml +37 -0
- package/.z-scratch/codex-session-01a08545-90c5-73c0-b2c2-68d94481fb63.md +9075 -0
- package/CHANGELOG.md +5 -0
- package/Makefile +0 -1
- package/lib/alloc.js +6 -8
- package/lib/main.js +1 -3
- package/lib/parse3.js +21 -6
- package/lib/schema3.js +51 -31
- package/lib/scrapers/twitter.js +13 -13
- package/lib/util.js +15 -1
- package/package.json +1 -1
- package/src/alloc.iced +2 -4
- package/src/constants.iced +4 -0
- package/src/main.iced +0 -2
- package/src/parse3.iced +9 -3
- package/src/schema3.iced +20 -7
- package/src/scrapers/twitter.iced +3 -3
- package/src/util.iced +11 -0
- package/test/files/alloc.iced +40 -0
- package/test/files/parse3.iced +61 -0
- package/test/files/schema3.iced +258 -0
- package/.travis.yml +0 -10
- package/lib/wot.js +0 -147
- package/src/wot.iced +0 -96
- package/test/files/wot.iced +0 -99
- package/test/make_esc.iced +0 -48
package/src/schema3.iced
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
|
|
2
2
|
parse = require './parse3'
|
|
3
|
+
{has_own,get_own} = require './util'
|
|
3
4
|
|
|
4
5
|
mkerr = (path, err) -> new Error "At #{path.toString()}: #{err}"
|
|
5
6
|
|
|
7
|
+
# __proto__ is not a data key. `{ __proto__: x }` and `obj["__proto__"] = x`
|
|
8
|
+
# set [[Prototype]] instead of an own property. JSON.parse may store it as an
|
|
9
|
+
# own key; msgpack unpack may throw. Ban it as a schema and payload key.
|
|
10
|
+
# constructor, toString, hasOwnProperty, etc. are allowed; has_own treats them
|
|
11
|
+
# as own keys.
|
|
12
|
+
is_reserved_key_name = (k) -> k is '__proto__'
|
|
13
|
+
|
|
6
14
|
class Path
|
|
7
15
|
constructor : (v) ->
|
|
8
16
|
@_v = v or []
|
|
@@ -33,11 +41,13 @@ class Node
|
|
|
33
41
|
|
|
34
42
|
_check_value : ({checker, path, obj}) ->
|
|
35
43
|
if not obj? and checker.is_optional() then return null
|
|
36
|
-
if not obj? then mkerr path, "value cannot be null"
|
|
44
|
+
if not obj? then return mkerr path, "value cannot be null"
|
|
37
45
|
return checker._check { path, obj }
|
|
38
46
|
|
|
39
47
|
class Dict extends Node
|
|
40
48
|
constructor : ({keys}) ->
|
|
49
|
+
for k of keys
|
|
50
|
+
if is_reserved_key_name k then throw new Error "schema key name is not allowed: #{k}"
|
|
41
51
|
@_keys = keys
|
|
42
52
|
# do not fail if there are extra keys unknown to schema
|
|
43
53
|
@_allow_extra_keys = false
|
|
@@ -48,22 +58,24 @@ class Dict extends Node
|
|
|
48
58
|
return mkerr path, "need a dictionary"
|
|
49
59
|
for k,v of obj
|
|
50
60
|
new_path = path.extend(k)
|
|
51
|
-
if
|
|
61
|
+
if is_reserved_key_name k then return mkerr new_path, "key name is not allowed"
|
|
62
|
+
if not (checker = get_own(@_keys, k))?
|
|
52
63
|
if @_allow_extra_keys then continue
|
|
53
64
|
return mkerr new_path, "key is not supported"
|
|
54
65
|
if (err = @_check_value { checker, path : new_path, obj : v }) then return err
|
|
55
66
|
for k,v of @_keys
|
|
56
67
|
new_path = path.extend(k)
|
|
57
|
-
if not obj
|
|
68
|
+
if not has_own(obj, k) and not v.is_optional() then return mkerr new_path, "key is missing but is mandatory"
|
|
58
69
|
return null
|
|
59
70
|
|
|
60
71
|
debug_localize : (obj) ->
|
|
61
72
|
ret = {}
|
|
62
|
-
for k,v of @_keys when obj
|
|
73
|
+
for k,v of @_keys when has_own obj, k
|
|
63
74
|
ret[v._name or k] = v.debug_localize obj[k]
|
|
64
75
|
ret
|
|
65
76
|
|
|
66
77
|
set_key : (k,v) ->
|
|
78
|
+
if is_reserved_key_name k then throw new Error "schema key name is not allowed: #{k}"
|
|
67
79
|
@_keys[k] = v
|
|
68
80
|
|
|
69
81
|
allow_extra_keys : () ->
|
|
@@ -125,7 +137,7 @@ class Binary extends Node
|
|
|
125
137
|
|
|
126
138
|
_convert_and_check : ({path, obj}) ->
|
|
127
139
|
if @_convert and typeof(obj) is 'string'
|
|
128
|
-
obj =
|
|
140
|
+
obj = parse.decode_hex(obj)
|
|
129
141
|
unless Buffer.isBuffer(obj) and obj.length is @_len
|
|
130
142
|
return [ (mkerr path, "value needs to be buffer of length #{@_len}"), null ]
|
|
131
143
|
if @_bottom_bytes?
|
|
@@ -186,10 +198,11 @@ class StringEnum extends Node
|
|
|
186
198
|
constructor : ({values}) ->
|
|
187
199
|
@_values = {}
|
|
188
200
|
for v in values
|
|
201
|
+
if is_reserved_key_name v then throw new Error "enum value is not allowed: #{v}"
|
|
189
202
|
@_values[v] = true
|
|
190
203
|
_check : ({path, obj}) ->
|
|
191
204
|
if typeof(obj) isnt 'string' then return mkerr path, "value must be a string"
|
|
192
|
-
if not @_values
|
|
205
|
+
if not has_own(@_values, obj) then return mkerr path, "unknown enum value (#{obj})"
|
|
193
206
|
return null
|
|
194
207
|
|
|
195
208
|
class Value extends Node
|
|
@@ -218,7 +231,7 @@ class Or extends Node
|
|
|
218
231
|
@_terms = terms
|
|
219
232
|
_check : ({path, obj}) ->
|
|
220
233
|
ok = false
|
|
221
|
-
for t in @_terms when t.check(obj)
|
|
234
|
+
for t in @_terms when not t.check(obj)
|
|
222
235
|
ok = true
|
|
223
236
|
break
|
|
224
237
|
if not ok then return mkerr path, "no structure worked"
|
|
@@ -148,12 +148,12 @@ exports.TwitterScraper = class TwitterScraper extends BaseScraper
|
|
|
148
148
|
|
|
149
149
|
# twitter may not obey our matching request order
|
|
150
150
|
if responses?.length
|
|
151
|
-
|
|
151
|
+
map = new Map
|
|
152
152
|
key = if ids? then "id_str" else "screen_name"
|
|
153
|
-
|
|
153
|
+
map.set String(r[key]), r for r in responses
|
|
154
154
|
res = []
|
|
155
155
|
for identifier, i in input_list
|
|
156
|
-
res[i] =
|
|
156
|
+
res[i] = map.get(String(identifier)) or null
|
|
157
157
|
|
|
158
158
|
cb err, res
|
|
159
159
|
|
package/src/util.iced
CHANGED
|
@@ -5,6 +5,17 @@ crypto = require 'crypto'
|
|
|
5
5
|
|
|
6
6
|
#----------
|
|
7
7
|
|
|
8
|
+
# Native hasOwnProperty, captured so schema/input keys named
|
|
9
|
+
# "hasOwnProperty" cannot shadow the method. Use instead of obj[k] or
|
|
10
|
+
# obj.hasOwnProperty(k) — those see Object.prototype (constructor, toString, …).
|
|
11
|
+
_has_own = {}.constructor.prototype.hasOwnProperty
|
|
12
|
+
exports.has_own = has_own = (o, k) -> _has_own.call o, k
|
|
13
|
+
exports.get_own = get_own = (o, k) ->
|
|
14
|
+
if _has_own.call(o, k) then o[k]
|
|
15
|
+
else undefined
|
|
16
|
+
|
|
17
|
+
#----------
|
|
18
|
+
|
|
8
19
|
exports.json_secure_compare = json_secure_compare = (a,b) ->
|
|
9
20
|
[o1,o2] = (json_stringify_sorted(x) for x in [a,b])
|
|
10
21
|
err = if bufeq_secure((Buffer.from o1, 'utf8'), (Buffer.from o2, 'utf8')) then null
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{alloc,get_klass} = require '../../'
|
|
2
|
+
|
|
3
|
+
exports.test_unknown_type = (T,cb) ->
|
|
4
|
+
for type in ["", "not_a_real_type", "toString", "constructor", "__proto__"]
|
|
5
|
+
[err, klass] = get_klass type
|
|
6
|
+
T.assert err?, "error"
|
|
7
|
+
T.equal err.message, "Unknown proof class: #{type}", "right message"
|
|
8
|
+
T.assert not klass?, "no klass"
|
|
9
|
+
T.assert not(alloc type, {}), "alloc returns null"
|
|
10
|
+
|
|
11
|
+
cb null
|
|
12
|
+
|
|
13
|
+
exports.test_extra_lookup_tab = (T,cb) ->
|
|
14
|
+
class Dummy
|
|
15
|
+
constructor : (args) -> @args = args
|
|
16
|
+
|
|
17
|
+
# only used in keybase-proofs-test
|
|
18
|
+
extra_lookup_tab = {
|
|
19
|
+
"test.web_service_binding.rooter" : Dummy
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
[err, klass] = get_klass "test.web_service_binding.rooter", extra_lookup_tab
|
|
23
|
+
T.assert not err?, "no error for extra type"
|
|
24
|
+
T.equal klass, Dummy, "extra type klass"
|
|
25
|
+
obj = alloc "test.web_service_binding.rooter", {foo : 1}, extra_lookup_tab
|
|
26
|
+
T.assert obj?, "alloc extra type"
|
|
27
|
+
T.equal obj.args.foo, 1, "args passed through"
|
|
28
|
+
|
|
29
|
+
[err, klass] = get_klass "track", extra_lookup_tab
|
|
30
|
+
T.assert not err?, "builtin still found"
|
|
31
|
+
T.assert klass?, "builtin klass"
|
|
32
|
+
|
|
33
|
+
for type in ["", "not_a_real_type", "toString", "constructor", "__proto__"]
|
|
34
|
+
[err, klass] = get_klass type, extra_lookup_tab
|
|
35
|
+
T.assert err?, "error"
|
|
36
|
+
T.equal err.message, "Unknown proof class: #{type}", "right message"
|
|
37
|
+
T.assert not klass?, "no klass"
|
|
38
|
+
T.assert not(alloc type, {}, extra_lookup_tab), "alloc returns null"
|
|
39
|
+
|
|
40
|
+
cb null
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
parse3 = require '../../lib/parse3'
|
|
2
|
+
schema = require '../../lib/schema3'
|
|
3
|
+
|
|
4
|
+
exports.hex_rejects_trailing_junk = (T, cb) ->
|
|
5
|
+
uid = "00".repeat(15) + "19"
|
|
6
|
+
hash = "00".repeat(32)
|
|
7
|
+
|
|
8
|
+
uid_upper = "AA".repeat(15) + "19"
|
|
9
|
+
|
|
10
|
+
T.assert parse3.is_hex(uid, 16), "valid uid hex is accepted"
|
|
11
|
+
T.assert parse3.is_hex(uid_upper, 16), "uppercase uid hex is accepted"
|
|
12
|
+
T.assert not parse3.is_hex(uid + "zz", 16), "uid hex plus junk is rejected"
|
|
13
|
+
T.assert not parse3.is_hex(uid + "a", 16), "odd-length uid hex is rejected"
|
|
14
|
+
T.assert not parse3.is_hex(hash + "nothex", 32), "hash hex plus junk is rejected"
|
|
15
|
+
|
|
16
|
+
T.assert not parse3.is_uid(hash), "length has to match"
|
|
17
|
+
|
|
18
|
+
err = schema.uid().convert().check uid
|
|
19
|
+
T.assert not err?, "valid uid converts"
|
|
20
|
+
|
|
21
|
+
err = schema.uid().convert().check uid_upper
|
|
22
|
+
T.assert not err?, "uppercase uid converts"
|
|
23
|
+
|
|
24
|
+
err = schema.uid().convert().check hash
|
|
25
|
+
T.assert err?, "length has to match"
|
|
26
|
+
|
|
27
|
+
err = schema.uid().convert().check uid + "zz"
|
|
28
|
+
T.assert err?, "uid with trailing junk is rejected"
|
|
29
|
+
|
|
30
|
+
err = schema.uid().convert().check uid + "a"
|
|
31
|
+
T.assert err?, "odd-length uid is rejected"
|
|
32
|
+
|
|
33
|
+
err = schema.hash().convert().check hash + "zz"
|
|
34
|
+
T.assert err?, "hash with trailing junk is rejected"
|
|
35
|
+
|
|
36
|
+
out = parse3.unhex uid
|
|
37
|
+
T.assert Buffer.isBuffer(out) and out.length is 16, "unhex accepts valid uid"
|
|
38
|
+
|
|
39
|
+
out = parse3.unhex uid_upper
|
|
40
|
+
T.assert Buffer.isBuffer(out) and out.length is 16, "unhex accepts uppercase uid"
|
|
41
|
+
|
|
42
|
+
for bad in [uid + "zz", uid + "a"]
|
|
43
|
+
err = null
|
|
44
|
+
try
|
|
45
|
+
parse3.unhex bad
|
|
46
|
+
catch e
|
|
47
|
+
err = e
|
|
48
|
+
T.assert err?, "unhex rejects #{bad}"
|
|
49
|
+
T.assert err.toString().indexOf("bad binary or hex string") >= 0, "unhex error message"
|
|
50
|
+
|
|
51
|
+
cb null
|
|
52
|
+
|
|
53
|
+
exports.hex_rejects_length_like_objects = (T, cb) ->
|
|
54
|
+
uid_buf = Buffer.alloc 16
|
|
55
|
+
T.assert parse3.is_hex(uid_buf, 16), "buffer of the right length is accepted"
|
|
56
|
+
T.assert not parse3.is_hex(Buffer.alloc(15), 16), "buffer of the wrong length is rejected"
|
|
57
|
+
T.assert not parse3.is_hex({length : 16}, 16), "plain object with length is rejected"
|
|
58
|
+
T.assert not parse3.is_hex((0 for i in [0...16]), 16), "array of the right length is rejected"
|
|
59
|
+
T.assert not parse3.is_uid({length : 16}), "is_uid rejects a length-like object"
|
|
60
|
+
|
|
61
|
+
cb null
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
schema = require '../../lib/schema3'
|
|
2
|
+
{pack,unpack} = require 'purepack'
|
|
3
|
+
|
|
4
|
+
# These collide with Object.prototype and with lookups like obj[k] /
|
|
5
|
+
# obj.hasOwnProperty(k).
|
|
6
|
+
_object_proto_names = [
|
|
7
|
+
"__proto__"
|
|
8
|
+
"constructor"
|
|
9
|
+
"hasOwnProperty"
|
|
10
|
+
"isPrototypeOf"
|
|
11
|
+
"propertyIsEnumerable"
|
|
12
|
+
"toLocaleString"
|
|
13
|
+
"toString"
|
|
14
|
+
"valueOf"
|
|
15
|
+
]
|
|
16
|
+
# "Weird key names" - Object prototype keys but handled by schema3 library.
|
|
17
|
+
# With the exception of __proto__ - this one is banned because it requires
|
|
18
|
+
# extra care to get right and has more footguns. See src/schema3.iced
|
|
19
|
+
# is_reserved_key_name
|
|
20
|
+
_weird_key_names = (n for n in _object_proto_names when n isnt "__proto__")
|
|
21
|
+
|
|
22
|
+
exports.prototype_pollution_json = (T, cb) ->
|
|
23
|
+
# parsing "__proto__" property should not change resulting object's
|
|
24
|
+
# prototype.
|
|
25
|
+
obj = JSON.parse('{"__proto__":1}')
|
|
26
|
+
T.assert Object.getPrototypeOf(obj) is Object.prototype, "is Object.prototype"
|
|
27
|
+
T.assert Object::hasOwnProperty.call(obj, '__proto__'), "hasOwnProperty __proto__"
|
|
28
|
+
|
|
29
|
+
cb null
|
|
30
|
+
|
|
31
|
+
exports.prototype_pollution_purepack = (T, cb) ->
|
|
32
|
+
# purepack does not allow __proto__ keys, although accidentially.
|
|
33
|
+
|
|
34
|
+
# Create a purepack with aaaaaaaaa property
|
|
35
|
+
aaa = Buffer.from (pack { aaaaaaaaa : 1 })
|
|
36
|
+
|
|
37
|
+
# Sanity check, 'aaaaaaaaa' is just a normal key in an unpacked object.
|
|
38
|
+
obj = unpack aaa
|
|
39
|
+
T.assert Object.getPrototypeOf(obj) is Object.prototype, "is Object.prototype"
|
|
40
|
+
T.assert Object::hasOwnProperty.call(obj, 'aaaaaaaaa'), "hasOwnProperty aaaaaaaaa"
|
|
41
|
+
|
|
42
|
+
# Str-replace aaaaaaaaa into __proto__
|
|
43
|
+
bin = Buffer.from(aaa.toString('binary').replace('aaaaaaaaa', '__proto__'), 'binary')
|
|
44
|
+
err = null
|
|
45
|
+
try
|
|
46
|
+
unpack(bin)
|
|
47
|
+
catch e
|
|
48
|
+
err = e
|
|
49
|
+
T.assert err?
|
|
50
|
+
T.equal err?.message, "duplicate key '__proto__'"
|
|
51
|
+
|
|
52
|
+
cb null
|
|
53
|
+
|
|
54
|
+
exports.or_combinator = (T, cb) ->
|
|
55
|
+
schm = schema.or([
|
|
56
|
+
schema.dict({
|
|
57
|
+
name : schema.string()
|
|
58
|
+
username : schema.string()
|
|
59
|
+
})
|
|
60
|
+
schema.dict({
|
|
61
|
+
protocol : schema.string()
|
|
62
|
+
hostname : schema.string()
|
|
63
|
+
})
|
|
64
|
+
])
|
|
65
|
+
|
|
66
|
+
err = schm.check { name : "reddit", username : "alice" }
|
|
67
|
+
T.assert not err?, "object matching first term is accepted"
|
|
68
|
+
|
|
69
|
+
err = schm.check { protocol : "https:", hostname : "example.com" }
|
|
70
|
+
T.assert not err?, "object matching second term is accepted"
|
|
71
|
+
|
|
72
|
+
err = schm.check { invalid : 1, obj : 2 }
|
|
73
|
+
T.assert err?, "object matching no term is rejected"
|
|
74
|
+
T.equal err?.message, "At <top>: no structure worked"
|
|
75
|
+
|
|
76
|
+
cb null
|
|
77
|
+
|
|
78
|
+
exports.required_null_rejected = (T, cb) ->
|
|
79
|
+
for val in [null, undefined]
|
|
80
|
+
err = schema.array(schema.obj()).check [val]
|
|
81
|
+
T.assert err?, "array of obj() rejects null"
|
|
82
|
+
T.equal err?.message, "At <top>.0: value cannot be null"
|
|
83
|
+
|
|
84
|
+
err = schema.array(schema.string()).check [val]
|
|
85
|
+
T.assert err?, "array of obj() rejects null"
|
|
86
|
+
T.equal err?.message, "At <top>.0: value cannot be null"
|
|
87
|
+
|
|
88
|
+
err = schema.struct([schema.obj()]).check [val]
|
|
89
|
+
T.assert err?, "struct of obj() rejects null"
|
|
90
|
+
T.equal err?.message, "At <top>.0: value cannot be null"
|
|
91
|
+
|
|
92
|
+
err = schema.struct([schema.string()]).check [val]
|
|
93
|
+
T.assert err?, "struct of obj() rejects null"
|
|
94
|
+
T.equal err?.message, "At <top>.0: value cannot be null"
|
|
95
|
+
|
|
96
|
+
err = schema.dict({ x : schema.obj() }).check { x : val }
|
|
97
|
+
T.assert err?, "dict required obj() null is rejected"
|
|
98
|
+
T.equal err?.message, "At <top>.x: value cannot be null"
|
|
99
|
+
|
|
100
|
+
err = schema.dict({ x : schema.string() }).check { x : val }
|
|
101
|
+
T.assert err?, "dict required string null is rejected"
|
|
102
|
+
T.equal err?.message, "At <top>.x: value cannot be null"
|
|
103
|
+
|
|
104
|
+
err = schema.dict({ x : schema.string().optional() }).check { x : val }
|
|
105
|
+
T.assert not err?, "dict optional string null is accepted"
|
|
106
|
+
|
|
107
|
+
cb null
|
|
108
|
+
|
|
109
|
+
exports.dict_missing_mandatory_key = (T, cb) ->
|
|
110
|
+
schm = schema.dict({
|
|
111
|
+
n : schema.string().name("name")
|
|
112
|
+
nick : schema.string().optional()
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
err = schm.check { n : "alice" }
|
|
116
|
+
T.assert not err?, "optional key may be omitted"
|
|
117
|
+
|
|
118
|
+
err = schm.check { nick : "a" }
|
|
119
|
+
T.assert err?, "missing mandatory key is rejected"
|
|
120
|
+
T.equal err?.message, "At <top>.n: key is missing but is mandatory"
|
|
121
|
+
|
|
122
|
+
err = schm.check {}
|
|
123
|
+
T.assert err?, "empty dict missing mandatory key is rejected"
|
|
124
|
+
T.equal err?.message, "At <top>.n: key is missing but is mandatory"
|
|
125
|
+
|
|
126
|
+
localized = schm.debug_localize { n : "alice" }
|
|
127
|
+
T.equal localized.name, "alice", "debug_localize uses schema names"
|
|
128
|
+
T.assert not localized.n?, "short key is replaced"
|
|
129
|
+
|
|
130
|
+
cb null
|
|
131
|
+
|
|
132
|
+
exports.string_enum_rejects_unknown_weird_names = (T, cb) ->
|
|
133
|
+
schm = schema.string_enum ["in_person", "proofs", "video"]
|
|
134
|
+
err = schm.check "video"
|
|
135
|
+
T.assert not err?, "listed enum value is accepted"
|
|
136
|
+
|
|
137
|
+
err = schm.check "nope"
|
|
138
|
+
T.assert err?, "unknown enum value is rejected"
|
|
139
|
+
|
|
140
|
+
# Make sure that Object prototype names are not bugging out with string enum check.
|
|
141
|
+
for name in _object_proto_names
|
|
142
|
+
err = schm.check name
|
|
143
|
+
T.assert err?, "#{name} is not an enum value just because it is a prototype name"
|
|
144
|
+
T.assert (err?.message.indexOf("unknown enum value") >= 0), "#{name} error message"
|
|
145
|
+
|
|
146
|
+
cb null
|
|
147
|
+
|
|
148
|
+
exports.string_enum_allows_weird_names = (T, cb) ->
|
|
149
|
+
for name in _weird_key_names
|
|
150
|
+
# Allow a string enum with weird name.
|
|
151
|
+
schm = schema.string_enum [name]
|
|
152
|
+
# And it can also be checked properly
|
|
153
|
+
err = schm.check name
|
|
154
|
+
T.assert not err?, "#{name} can be an enum value"
|
|
155
|
+
err = schm.check "nope"
|
|
156
|
+
T.assert err?, "other values still rejected next to #{name}"
|
|
157
|
+
|
|
158
|
+
# Do not allow banned __proto__ name.
|
|
159
|
+
threw = null
|
|
160
|
+
try
|
|
161
|
+
schema.string_enum ["__proto__"]
|
|
162
|
+
catch e
|
|
163
|
+
threw = e
|
|
164
|
+
T.assert threw?, "__proto__ is not a valid enum value"
|
|
165
|
+
T.equal threw?.message, "enum value is not allowed: __proto__"
|
|
166
|
+
|
|
167
|
+
cb null
|
|
168
|
+
|
|
169
|
+
exports.dict_rejects_unknown_weird_keys = (T, cb) ->
|
|
170
|
+
schm = schema.dict { name : schema.string() }
|
|
171
|
+
err = schm.check { name : "ok" }
|
|
172
|
+
T.assert not err?, "valid dict is accepted"
|
|
173
|
+
|
|
174
|
+
err = schm.check { name : "ok", extra : 1 }
|
|
175
|
+
T.assert err?, "unknown key is rejected"
|
|
176
|
+
T.equal err?.message, "At <top>.extra: key is not supported"
|
|
177
|
+
|
|
178
|
+
# Allow weird key names to be checked against the schema, they are just not
|
|
179
|
+
# defined as dict fields and payloads with these fields are correctly
|
|
180
|
+
# rejected. They are not rejected / banned, and are treated as any other name
|
|
181
|
+
# (also see next test).
|
|
182
|
+
for name in _weird_key_names
|
|
183
|
+
obj = JSON.parse "{\"name\":\"ok\",\"#{name}\":1}"
|
|
184
|
+
err = null
|
|
185
|
+
threw = null
|
|
186
|
+
try
|
|
187
|
+
err = schm.check obj
|
|
188
|
+
catch e
|
|
189
|
+
threw = e
|
|
190
|
+
T.assert not threw?, "#{name} should not throw"
|
|
191
|
+
T.assert err?, "#{name} extra key is not a schema field"
|
|
192
|
+
T.equal err?.message, "At <top>.#{name}: key is not supported"
|
|
193
|
+
|
|
194
|
+
obj = JSON.parse '{"name":"ok","__proto__":1}'
|
|
195
|
+
err = schm.check obj
|
|
196
|
+
T.assert err?, "__proto__ extra key is rejected"
|
|
197
|
+
T.equal err?.message, "At <top>.__proto__: key name is not allowed"
|
|
198
|
+
|
|
199
|
+
schm = schema.dict({ name : schema.string() }).allow_extra_keys()
|
|
200
|
+
obj = JSON.parse '{"name":"ok","constructor":1}'
|
|
201
|
+
err = schm.check obj
|
|
202
|
+
T.assert not err?, "constructor extra key is allowed when extra keys are allowed"
|
|
203
|
+
|
|
204
|
+
obj = JSON.parse '{"name":"ok","__proto__":1}'
|
|
205
|
+
err = schm.check obj
|
|
206
|
+
T.assert err?, "__proto__ is rejected even with allow_extra_keys"
|
|
207
|
+
T.equal err?.message, "At <top>.__proto__: key name is not allowed"
|
|
208
|
+
|
|
209
|
+
cb null
|
|
210
|
+
|
|
211
|
+
exports.dict_weird_schema_keys = (T, cb) ->
|
|
212
|
+
# Weird keys can be used in the schema as well, and objects with these
|
|
213
|
+
# keys can be checked against the schemas.
|
|
214
|
+
for name in _weird_key_names
|
|
215
|
+
keys = {}
|
|
216
|
+
keys[name] = schema.string()
|
|
217
|
+
schm = schema.dict keys
|
|
218
|
+
|
|
219
|
+
own = JSON.parse "{\"#{name}\":\"ok\"}"
|
|
220
|
+
err = schm.check own
|
|
221
|
+
T.assert not err?, "own #{name} key is accepted"
|
|
222
|
+
|
|
223
|
+
err = schm.check {}
|
|
224
|
+
T.assert err?, "inherited #{name} does not satisfy a required schema key"
|
|
225
|
+
T.equal err?.message, "At <top>.#{name}: key is missing but is mandatory"
|
|
226
|
+
|
|
227
|
+
localized = schm.debug_localize {}
|
|
228
|
+
T.assert not Object::hasOwnProperty.call(localized, name), "debug_localize ignores inherited #{name}"
|
|
229
|
+
localized = schm.debug_localize own
|
|
230
|
+
T.equal localized[name], "ok", "own #{name} key is localized"
|
|
231
|
+
|
|
232
|
+
schm = schema.dict { name : schema.string() }
|
|
233
|
+
schm.set_key name, schema.string()
|
|
234
|
+
obj = JSON.parse "{\"name\":\"ok\",\"#{name}\":\"ok\"}"
|
|
235
|
+
err = schm.check obj
|
|
236
|
+
T.assert not err?, "set_key can install #{name}"
|
|
237
|
+
|
|
238
|
+
# With the exception of __proto__ which is rejected in the schema construction stage.
|
|
239
|
+
keys = {}
|
|
240
|
+
Object.defineProperty keys, "__proto__", { value : schema.string(), enumerable : true }
|
|
241
|
+
threw = null
|
|
242
|
+
try
|
|
243
|
+
schema.dict keys
|
|
244
|
+
catch e
|
|
245
|
+
threw = e
|
|
246
|
+
T.assert threw?, "__proto__ is not a valid schema key"
|
|
247
|
+
T.equal threw?.message, "schema key name is not allowed: __proto__"
|
|
248
|
+
|
|
249
|
+
schm = schema.dict { name : schema.string() }
|
|
250
|
+
threw = null
|
|
251
|
+
try
|
|
252
|
+
schm.set_key "__proto__", schema.string()
|
|
253
|
+
catch e
|
|
254
|
+
threw = e
|
|
255
|
+
T.assert threw?, "set_key rejects __proto__"
|
|
256
|
+
T.equal threw?.message, "schema key name is not allowed: __proto__"
|
|
257
|
+
|
|
258
|
+
cb null
|
package/.travis.yml
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
language: node_js
|
|
2
|
-
node_js:
|
|
3
|
-
- "node"
|
|
4
|
-
notifications:
|
|
5
|
-
slack:
|
|
6
|
-
rooms:
|
|
7
|
-
secure: W5hUm0MPWJ3v2VGRAq9fxgroVvqFOkwnbrxllEX3Zadf3e909fwQzm7KEUvSEd9fhsKrdBxPrphCZd1UCq5cXjCkfokKFojnbgnYPKZYgL4M7GWqiURCfIUY7r0gQCDnFzIIANacIbhT8089IkQva8QWCdfX4zVycTKOvMC0msE=
|
|
8
|
-
branches:
|
|
9
|
-
only:
|
|
10
|
-
- master
|
package/lib/wot.js
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
// Generated by IcedCoffeeScript 108.0.11
|
|
2
|
-
(function() {
|
|
3
|
-
var Base, React, Vouch, constants, json_stringify_sorted, make_esc, pgp_utils, schema, streq_secure, unix_time, _ref,
|
|
4
|
-
__hasProp = {}.hasOwnProperty,
|
|
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
|
-
|
|
7
|
-
Base = require('./base').Base;
|
|
8
|
-
|
|
9
|
-
constants = require('./constants').constants;
|
|
10
|
-
|
|
11
|
-
make_esc = require('iced-error').make_esc;
|
|
12
|
-
|
|
13
|
-
pgp_utils = require('pgp-utils');
|
|
14
|
-
|
|
15
|
-
_ref = pgp_utils.util, json_stringify_sorted = _ref.json_stringify_sorted, unix_time = _ref.unix_time, streq_secure = _ref.streq_secure;
|
|
16
|
-
|
|
17
|
-
schema = require('./schema3');
|
|
18
|
-
|
|
19
|
-
exports.Vouch = Vouch = (function(_super) {
|
|
20
|
-
__extends(Vouch, _super);
|
|
21
|
-
|
|
22
|
-
function Vouch(obj) {
|
|
23
|
-
this.wot = obj.wot;
|
|
24
|
-
Vouch.__super__.constructor.call(this, obj);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
Vouch.prototype._v_stub_paths = function() {
|
|
28
|
-
return ["body.wot_vouch"];
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
Vouch.prototype._type = function() {
|
|
32
|
-
return constants.sig_types.wot.vouch;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
Vouch.prototype._type_v2 = function(revoke_flag) {
|
|
36
|
-
if ((this.revoke != null) || revoke_flag) {
|
|
37
|
-
return constants.sig_types_v2.wot.vouch_with_revoke;
|
|
38
|
-
} else {
|
|
39
|
-
return constants.sig_types_v2.wot.vouch;
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
Vouch.prototype._v_check = function(_arg, cb) {
|
|
44
|
-
var err, json, obj, proof_schema, schm;
|
|
45
|
-
json = _arg.json;
|
|
46
|
-
obj = json.body.wot_vouch;
|
|
47
|
-
if (obj == null) {
|
|
48
|
-
return cb(null);
|
|
49
|
-
}
|
|
50
|
-
proof_schema = schema.or([
|
|
51
|
-
schema.dict({
|
|
52
|
-
proof_type: schema.int(),
|
|
53
|
-
name: schema.string(),
|
|
54
|
-
username: schema.string()
|
|
55
|
-
}), schema.dict({
|
|
56
|
-
proof_type: schema.int(),
|
|
57
|
-
protocol: schema.string(),
|
|
58
|
-
hostname: schema.string()
|
|
59
|
-
}), schema.dict({
|
|
60
|
-
proof_type: schema.int(),
|
|
61
|
-
protocol: schema.string(),
|
|
62
|
-
domain: schema.string()
|
|
63
|
-
})
|
|
64
|
-
]);
|
|
65
|
-
schm = schema.dict({
|
|
66
|
-
user: schema.dict({
|
|
67
|
-
username: schema.string(),
|
|
68
|
-
uid: schema.uid().convert(),
|
|
69
|
-
eldest: schema.dict({
|
|
70
|
-
seqno: schema.int(),
|
|
71
|
-
kid: schema.kid().convert()
|
|
72
|
-
}),
|
|
73
|
-
seq_tail: schema.dict({
|
|
74
|
-
seqno: schema.int(),
|
|
75
|
-
sig_id: schema.sig_id().convert(),
|
|
76
|
-
payload_hash: schema.hash().convert()
|
|
77
|
-
})
|
|
78
|
-
}),
|
|
79
|
-
confidence: schema.dict({
|
|
80
|
-
username_verified_via: schema.string_enum(["in_person", "proofs", "video", "audio", "other_chat", "familiar", "other"]).optional(),
|
|
81
|
-
proofs: schema.array(proof_schema).optional(),
|
|
82
|
-
other: schema.string({
|
|
83
|
-
max_length: 90
|
|
84
|
-
}).optional()
|
|
85
|
-
}),
|
|
86
|
-
vouch_text: schema.string({
|
|
87
|
-
max_length: 700
|
|
88
|
-
})
|
|
89
|
-
});
|
|
90
|
-
err = schm.check(obj);
|
|
91
|
-
return cb(err);
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
Vouch.prototype._v_customize_json = function(ret) {
|
|
95
|
-
var t, _ref1;
|
|
96
|
-
if ((t = (_ref1 = this.wot) != null ? _ref1.vouch : void 0) != null) {
|
|
97
|
-
return ret.body.wot_vouch = t;
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
return Vouch;
|
|
102
|
-
|
|
103
|
-
})(Base);
|
|
104
|
-
|
|
105
|
-
exports.React = React = (function(_super) {
|
|
106
|
-
__extends(React, _super);
|
|
107
|
-
|
|
108
|
-
function React(obj) {
|
|
109
|
-
this.wot = obj.wot;
|
|
110
|
-
React.__super__.constructor.call(this, obj);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
React.prototype._v_stub_paths = function() {
|
|
114
|
-
return ["body.wot_react"];
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
React.prototype._type = function() {
|
|
118
|
-
return constants.sig_types.wot.react;
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
React.prototype._type_v2 = function(revoke_flag) {
|
|
122
|
-
return constants.sig_types_v2.wot.react;
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
React.prototype._v_check = function(_arg, cb) {
|
|
126
|
-
var json, obj, schm;
|
|
127
|
-
json = _arg.json;
|
|
128
|
-
obj = json.body.wot_react;
|
|
129
|
-
schm = schema.dict({
|
|
130
|
-
sig_id: schema.sig_id().convert(),
|
|
131
|
-
reaction: schema.string_enum(["accept", "reject"])
|
|
132
|
-
});
|
|
133
|
-
return cb(schm.check(obj));
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
React.prototype._v_customize_json = function(ret) {
|
|
137
|
-
var t;
|
|
138
|
-
if ((t = this.wot.react) != null) {
|
|
139
|
-
return ret.body.wot_react = t;
|
|
140
|
-
}
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
return React;
|
|
144
|
-
|
|
145
|
-
})(Base);
|
|
146
|
-
|
|
147
|
-
}).call(this);
|