cddl 0.10.1 → 0.10.3

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.
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.