cddl 0.10.1 → 0.10.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ce024a0c0c43374c481b2f099e23dfd2d5da6cda62791111cf767bc12684bd92
4
- data.tar.gz: b7bea63f7fb1bc927f3ffad3d602b6544719a7bd9657e7836faae0edd2355bfe
3
+ metadata.gz: 9e60b48882767d7e76926473b44c79369891e4203326d4e31f5693a3819f391d
4
+ data.tar.gz: 6ed2f45e7fa8468557e73c96a4dbfdd142d65fdebeeb362efeebec8007b7948f
5
5
  SHA512:
6
- metadata.gz: 59344f19904e61edaecb196d0ba9106a97e5d9cbcb6b77bb3abd8f0a41fc72f0a30e51325253fb718e4f8f928ad979da968b48206c0594e80a6f82e2315252aa
7
- data.tar.gz: 17415dd68f227a7c642369563bb38923adc54706b104468aa05c40d322697db1fa9cf22be2c5bc18d1036835f9cf588fc8eb4c514512b4e4b9dd459d8aaf95ce
6
+ metadata.gz: 2124a4fc046c3dc03d007ca949e4f9191497b359fe19fafe307ed2227c4b5654d909815575504e452add310dfc8487bfc13db94794d4b6c06a7af0bb2701e55f
7
+ data.tar.gz: 8a223332d81282eb9ad651dad887579ceb7b44a01d05ccff6458e271ea999a3c5fad5f81c87a6a2ccf927307b3bb9c4e06075361b0f8fc8b02005926a3d9a5b7
data/cddl.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  spec = Gem::Specification.new do |s|
2
2
  s.name = 'cddl'
3
- s.version = '0.10.1'
3
+ s.version = '0.10.3'
4
4
  s.summary = "CDDL generator and validator."
5
5
  s.description = %{A parser, generator, and validator for CDDL}
6
6
  s.add_dependency('cbor-diag')
@@ -9,6 +9,7 @@ spec = Gem::Specification.new do |s|
9
9
  s.add_dependency('abnftt')
10
10
  s.add_dependency('regexp-examples') # , '1.1.0')
11
11
  s.add_dependency('colorize')
12
+ s.add_dependency('base32', '~> 0.3')
12
13
  s.files = `git ls-files`.split("\n").grep(/^[a-z]/)
13
14
  s.files = Dir['lib/**/*.rb'] + %w(cddl.gemspec) + Dir['data/**/*.abnf'] + Dir['data/**/*.cddl'] + Dir['test-data/**/*.cddl'] + Dir['test/**/*.rb']
14
15
  s.require_path = 'lib'
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2022 Weihang Jian <https://tonytonyjan.net>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ # An implementation of draft-faltstrom-base45-10, see
24
+ # https://datatracker.ietf.org/doc/draft-faltstrom-base45/
25
+ module Base45Lite
26
+ class Error < ::StandardError; end
27
+ class OverflowError < Error; end
28
+ class InvalidCharacterError < Error; end
29
+ class ForbiddenLengthError < Error; end
30
+
31
+ MAX_UINT18 = 2**16 - 1
32
+ SQUARED_45 = 45**2
33
+ MAPPING = [
34
+ *'0'..'9',
35
+ *'A'..'Z',
36
+ ' ', '$', '%', '*', '+', '-', '.', '/', ':'
37
+ ].map!.with_index { |x, i| [i, x] }.to_h.freeze
38
+ REVERSE_MAPPING = MAPPING.invert.freeze
39
+
40
+ def self.encode(input)
41
+ sequence = []
42
+ input.unpack('n*').map! do |uint16|
43
+ i, c = uint16.divmod(45)
44
+ i, d = i.divmod(45)
45
+ _, e = i.divmod(45)
46
+ sequence.push(c, d, e)
47
+ end
48
+ if input.bytesize.odd?
49
+ i, c = input.getbyte(-1).divmod(45)
50
+ _, d = i.divmod(45)
51
+ sequence.push(c, d)
52
+ end
53
+ sequence.map!{ |n| MAPPING[n] }.join
54
+ end
55
+
56
+ def self.decode(input)
57
+ input
58
+ .chars.map! { |c| REVERSE_MAPPING[c] || raise(InvalidCharacterError) }
59
+ .each_slice(3).map do |slice|
60
+ c, d, e = slice
61
+ raise ForbiddenLengthError if d.nil?
62
+
63
+ sum = c + d * 45
64
+ sum += e * SQUARED_45 if e
65
+ raise OverflowError if sum > MAX_UINT18
66
+
67
+ sum
68
+ end
69
+ .pack((input.length % 3).zero? ? 'n*' : "n#{input.length / 3}C")
70
+ end
71
+ end
data/lib/cddl.rb CHANGED
@@ -2,10 +2,13 @@ require 'abnc'
2
2
  require 'pp'
3
3
  require 'pathname'
4
4
  require 'cbor-pure' unless defined?(CBOR::Tagged)
5
+ require 'cbor-deterministic'
5
6
  require 'regexp-examples'
6
7
  require 'abnftt'
7
8
  require 'colorize'
8
9
  require 'base64'
10
+ require 'base32'
11
+ require 'base45_lite'
9
12
 
10
13
  module CDDL
11
14
 
@@ -266,6 +269,21 @@ module CDDL
266
269
  l.map {|l| l.sub(/^ {0,#{indent}}/, "")}.join
267
270
  end
268
271
 
272
+ def unpack_array_to_sequence(content, where)
273
+ # remove the first head
274
+ n = case content.getbyte(0) - (4 << 5)
275
+ when 0..23; 1
276
+ when 24; 2
277
+ when 25; 3
278
+ when 26; 5
279
+ when 27; 9 # unlikely :-)
280
+ else fail ".cborseq sequence for #{where} not an array"
281
+ end
282
+ content[0...n] = ''
283
+ content
284
+ end
285
+
286
+
269
287
  # Memoize a bit here
270
288
 
271
289
  REGEXP_FOR_STRING = Hash.new {|h, k|
@@ -560,23 +578,67 @@ module CDDL
560
578
  end
561
579
  enc = bytes ? Encoding::BINARY : Encoding::UTF_8
562
580
  out.force_encoding(enc)
563
- when :cbor, :cborseq
581
+ when :cbor, :cborseq, :cbordet, :cborseqdet
564
582
  unless target == [:prim, 2]
565
583
  fail "Don't know yet how to generate #{where}"
566
584
  end
567
- content = CBOR::encode(generate1(control))
568
- if conop == :cborseq
585
+ input = generate1(control)
586
+ if conop == :cbordet || conop == :cborseqdet
587
+ input = input.cbor_prepare_deterministic
588
+ end
589
+ content = CBOR::encode(input)
590
+ if conop == :cborseq || conop == :cborseqdet
569
591
  # remove the first head
570
- n = case content.getbyte(0) - (4 << 5)
571
- when 0..23; 1
572
- when 24; 2
573
- when 25; 3
574
- when 26; 5
575
- when 27; 9 # unlikely :-)
576
- else fail "Generated .cborseq sequence for #{where} not an array"
577
- end
578
- content[0...n] = ''
592
+ content = unpack_array_to_sequence(content, where)
593
+ end
594
+ content
595
+ when :json
596
+ unless target == [:prim, 3]
597
+ fail "Don't know yet how to generate #{where}"
598
+ end
599
+ content = JSON::dump(generate1(control))
600
+ content
601
+ when :decimal
602
+ unless target == [:prim, 3]
603
+ fail "Don't know yet how to generate #{where}"
604
+ end
605
+ content = Integer(generate1(control)).to_s
606
+ content
607
+ when :join
608
+ content = generate1(control)
609
+ unless Array === content &&
610
+ content.all? {|x| String === x &&
611
+ ((target == [:prim, 2] && x.encoding == Encoding::BINARY) ||
612
+ (target == [:prim, 3] && x.encoding != Encoding::BINARY))}
613
+ fail "Don't know yet how to generate #{where}"
614
+ end
615
+ content = content.join
616
+ content
617
+ when :b64u, :"b64u-sloppy", :b64c, :"b64c-sloppy",
618
+ :b45, :b32, :h32, :hex, :hexlc, :hexuc
619
+ content = generate1(control)
620
+ unless String === content
621
+ fail "Don't know yet how to generate #{where}"
579
622
  end
623
+ content = case conop
624
+ when :b64u, :"b64u-sloppy"
625
+ Base64.urlsafe_encode64(content, padding: false)
626
+ when :b64c, :"b64c-sloppy"
627
+ Base64.strict_encode64(content)
628
+ when :b45
629
+ Base45Lite.encode(content)
630
+ when :b32
631
+ Base32.table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
632
+ Base32.encode(content).gsub("=", "")
633
+ when :h32
634
+ Base32.table = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
635
+ Base32.encode(content).gsub("=", "")
636
+ when :hex, :hexuc
637
+ content.unpack("H*")[0].upcase
638
+ when :hexlc
639
+ content.unpack("H*")[0]
640
+ else fail "Cannot happen"
641
+ end
580
642
  content
581
643
  when :within, :and
582
644
  32.times do
@@ -994,6 +1056,76 @@ module CDDL
994
1056
  ann if validate1((CBOR::decode(d) rescue :BAD_CBOR), control)
995
1057
  when :cborseq
996
1058
  ann if validate1((CBOR::decode("\x9f".b << d << "\xff".b) rescue :BAD_CBOR), control)
1059
+ when :cbordet
1060
+ decoded = CBOR::decode(d) rescue :BAD_CBOR
1061
+ if d != decoded.to_deterministic_cbor
1062
+ @last_message = "CBOR #{d.inspect} not deterministically encoded"
1063
+ nil
1064
+ else
1065
+ ann if validate1(decoded, control)
1066
+ end
1067
+ when :cborseqdet
1068
+ decoded = CBOR::decode("\x9f".b << d << "\xff".b) rescue :BAD_CBOR
1069
+ if d != unpack_array_to_sequence(decoded.to_deterministic_cbor, d.inspect)
1070
+ @last_message = "CBOR Sequence #{d.inspect} not deterministically encoded"
1071
+ nil
1072
+ else
1073
+ ann if validate1(decoded, control)
1074
+ end
1075
+ when :json
1076
+ ann if validate1((JSON::load(d) rescue :BAD_JSON), control)
1077
+ when :decimal
1078
+ ann if (
1079
+ if /\A0|-?[1-9][0-9]*\z/ === d
1080
+ validate1((d.to_i rescue :BAD_JSON), control)
1081
+ end
1082
+ )
1083
+ when :join
1084
+ ok, *v = extract_array(control)
1085
+ # warn "@@@JJJ@@@ #{ok.inspect} #{v.inspect}"
1086
+ if ok
1087
+ expected = v.map {|ve|
1088
+ fail "Not a string in #{where}" unless String === ve[0]
1089
+ ve[0]
1090
+ }.join
1091
+ ann if d == expected
1092
+ else
1093
+ fail "Don't know yet how to validate against #{where}"
1094
+ end
1095
+ when :b64u, :"b64u-sloppy", :b64c, :"b64c-sloppy", :b45, :b32, :h32, :hex, :hexlc, :hexuc
1096
+ ann if (
1097
+ String === d && (
1098
+ decoded = case conop
1099
+ when :b64u
1100
+ /=/ !~ d &&
1101
+ Base64.urlsafe_decode64(d)
1102
+ when :"b64u-sloppy"
1103
+ /[-_=]/ !~ d &&
1104
+ Base64.decode64(d.tr("+/", "-_"))
1105
+ when :b64c
1106
+ Base64.strict_decode64(d)
1107
+ when :"b64c-sloppy"
1108
+ Base64.decode64(d)
1109
+ when :b32
1110
+ /=/ !~ d &&
1111
+ (Base32.table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567") &&
1112
+ Base32.decode(d)
1113
+ when :b45
1114
+ Base45Lite.decode(d)
1115
+ when :h32
1116
+ /=/ !~ d &&
1117
+ (Base32.table = "0123456789ABCDEFGHIJKLMNOPQRSTUV") &&
1118
+ Base32.decode(d)
1119
+ when :hex
1120
+ /\A[0-9a-fA-F]*\z/ =~ d && [d].pack("H*")
1121
+ when :hexuc
1122
+ /\A[0-9A-F]*\z/ =~ d && [d].pack("H*")
1123
+ when :hexlc
1124
+ /\A[0-9a-f]*\z/ =~ d && [d].pack("H*")
1125
+ else fail "Cannot happen"
1126
+ end
1127
+ ) && validate1(decoded.b, control)
1128
+ )
997
1129
  when :within
998
1130
  if validate1(d, control)
999
1131
  ann
@@ -1348,9 +1480,15 @@ module CDDL
1348
1480
 
1349
1481
  BRACE = {"{" => :map, "[" => :array}
1350
1482
  RANGE_EXCLUDE_END = {".." => false, "..." => true}
1351
- SUPPORTED_ANNOTATIONS = [:bits, :size, :regexp, :cbor, :cborseq, :within, :and,
1483
+ SUPPORTED_ANNOTATIONS = [:bits, :size, :regexp,
1484
+ :cbor, :cborseq, :cbordet, :cborseqdet,
1485
+ :within, :and,
1352
1486
  :default, :lt, :le, :gt, :ge, :eq, :ne,
1353
- :feature, :abnf, :abnfb, :det, :cat, :plus]
1487
+ :feature, :abnf, :abnfb, :det, :cat, :plus,
1488
+ :json, :decimal, :join,
1489
+ :b64u, :"b64u-sloppy", :b64c, :"b64c-sloppy",
1490
+ :b45, :b32, :h32, :hex, :hexlc, :hexuc,
1491
+ ]
1354
1492
 
1355
1493
  def type1(n, canbegroup = false)
1356
1494
  # puts "NVALUE #{n.value.inspect}"
data/test/test-cddl.rb CHANGED
@@ -275,7 +275,7 @@ b = (
275
275
  (x: int // y: int), z: int
276
276
  )
277
277
  HERE
278
- assert parser.validate_for_test({})
278
+ refute parser.validate_for_test({}, false)
279
279
  assert parser.validate_for_test({"x" => 2, "z" => 1})
280
280
  assert parser.validate_for_test({"y" => 1, "z" => 2})
281
281
  refute parser.validate_for_test({"z" => 1}, false)
@@ -293,7 +293,7 @@ b = ( z: int
293
293
  (x: int // y: int)
294
294
  )
295
295
  HERE
296
- assert parser.validate_for_test({})
296
+ refute parser.validate_for_test({}, false)
297
297
  assert parser.validate_for_test({"x" => 2, "z" => 1})
298
298
  assert parser.validate_for_test({"y" => 1, "z" => 2})
299
299
  refute parser.validate_for_test({"z" => 1}, false)
@@ -0,0 +1 @@
1
+ a = text .b64c-sloppy 'mnoabcdue=='
@@ -0,0 +1 @@
1
+ a = text .b64c 'mnoabcd'
@@ -0,0 +1 @@
1
+ a = text .b64u 'mnoabcd'
@@ -0,0 +1 @@
1
+ a = text .b32 'mnoabcd'
@@ -0,0 +1 @@
1
+ a = text .h32 'mnoabcd'
@@ -0,0 +1 @@
1
+ a = text .decimal uint
@@ -0,0 +1 @@
1
+ a = text .decimal 4711
@@ -0,0 +1 @@
1
+ a = text .hex 'mnoabcd'
@@ -0,0 +1 @@
1
+ a = text .hexlc 'mnoabcd'
@@ -0,0 +1 @@
1
+ a = text .hexuc 'mnoabcd'
@@ -0,0 +1 @@
1
+ a = text .join (["a", "b", "c"])
@@ -0,0 +1 @@
1
+ a = text .join (["a", "b", 3])
@@ -0,0 +1 @@
1
+ a = text .join (["a", "b", text])
@@ -0,0 +1 @@
1
+ a = text .json ([4, uint .size 1, {"a": "b"}])
@@ -0,0 +1 @@
1
+ a = text .json ([4, uint .size 2, {"a": "b"}])
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cddl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 0.10.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carsten Bormann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-17 00:00:00.000000000 Z
11
+ date: 2023-03-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cbor-diag
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: base32
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.3'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.3'
97
111
  description: A parser, generator, and validator for CDDL
98
112
  email: cabo@tzi.org
99
113
  executables:
@@ -105,6 +119,7 @@ files:
105
119
  - cddl.gemspec
106
120
  - data/cddl.abnf
107
121
  - data/prelude.cddl
122
+ - lib/base45_lite.rb
108
123
  - lib/cbor-pp-play.rb
109
124
  - lib/cbor-pp.rb
110
125
  - lib/cddl.rb
@@ -119,7 +134,12 @@ files:
119
134
  - test-data/abnf3.cddl
120
135
  - test-data/ambig.cddl
121
136
  - test-data/b.cddl
137
+ - test-data/b64c-sloppy.cddl
138
+ - test-data/b64c.cddl
139
+ - test-data/b64u.cddl
122
140
  - test-data/badaddr.cddl
141
+ - test-data/base32.cddl
142
+ - test-data/base32hex.cddl
123
143
  - test-data/basic_syntax_example.cddl
124
144
  - test-data/bat.cddl
125
145
  - test-data/bpv7.cddl
@@ -135,6 +155,8 @@ files:
135
155
  - test-data/cose.cddl
136
156
  - test-data/dcaf.cddl
137
157
  - test-data/dcaf1.cddl
158
+ - test-data/decimal.cddl
159
+ - test-data/decimal2.cddl
138
160
  - test-data/det1.cddl
139
161
  - test-data/dotsize.cddl
140
162
  - test-data/extractor-demo.cddl
@@ -148,6 +170,9 @@ files:
148
170
  - test-data/grasp-09.cddl
149
171
  - test-data/grasp-v1.cddl
150
172
  - test-data/grasp-v2X.cddl
173
+ - test-data/hex.cddl
174
+ - test-data/hexlc.cddl
175
+ - test-data/hexuc.cddl
151
176
  - test-data/homenet-de.cddl
152
177
  - test-data/homenet-fe.cddl
153
178
  - test-data/ifmap-base-2.0v17.cddl
@@ -157,6 +182,11 @@ files:
157
182
  - test-data/jcr-ex.cddl
158
183
  - test-data/jim-cut-2.cddl
159
184
  - test-data/jim-cut.cddl
185
+ - test-data/join.cddl
186
+ - test-data/joini.cddl
187
+ - test-data/joinx.cddl
188
+ - test-data/json.cddl
189
+ - test-data/json2.cddl
160
190
  - test-data/jsoniodef.cddl
161
191
  - test-data/kevin5.cddl
162
192
  - test-data/lint1.cddl
@@ -217,7 +247,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
217
247
  - !ruby/object:Gem::Version
218
248
  version: '0'
219
249
  requirements: []
220
- rubygems_version: 3.3.11
250
+ rubygems_version: 3.4.6
221
251
  signing_key:
222
252
  specification_version: 4
223
253
  summary: CDDL generator and validator.