uri-ni 0.1.5 → 0.2.1

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/uri/ni/version.rb +1 -1
  3. data/lib/uri/ni.rb +101 -18
  4. metadata +3 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee2d458c5f63ebc9a63552bc94b0141052952a2729b4647a0d5d5b43859288a4
4
- data.tar.gz: 21201a539b63b90db525760e20087b37c77167fd054b75bc38d1625dfd0fedd7
3
+ metadata.gz: c7f97e35f7fc6987d8051e1f09e23cc2cbc29b6e188496b5d1abd5d030a7ec32
4
+ data.tar.gz: 3a66e3863206978a52e1281318808f043de2b7e4409b09d8bdff37a589bfb3fd
5
5
  SHA512:
6
- metadata.gz: 78679d956ad359ca94076ed41d148708c1fe4e8b79afe3cbaf144e3e874b20ae0d90d390414a58ab17b9152944b1ae3147e3e3478f9bc07e111a198ed7039ea5
7
- data.tar.gz: 832ac38552ef80eccad02eb739da1471ad23c9c0aaa01b570ad2ffd829649ec93c02ee7b961d220e29ce06ad9858af322f829601e9a62da6a36d46bff8966eab
6
+ metadata.gz: eac81311c6e7e895c908b0d45db5a7b028ed1e9b2e1b65e35d264c5840837abc589a9c11ac315272bf751f1f326b753f1b5e2f1add14313ae66258eefeee7c88
7
+ data.tar.gz: 8456780c695e1ad060546e46bf8cc1fcccbee00c1d535e6a3845f19f2928fd1a13efb720e264f23091fcf24b82bae797365877ca3747d6701502f96df61c65ca
@@ -3,7 +3,7 @@ require 'uri/generic'
3
3
 
4
4
  module URI
5
5
  class NI < Generic
6
- VERSION = "0.1.5"
6
+ VERSION = "0.2.1"
7
7
  end
8
8
 
9
9
  # might as well put this here
data/lib/uri/ni.rb CHANGED
@@ -42,8 +42,24 @@ class URI::NI < URI::Generic
42
42
  "sha-256": Digest::SHA256,
43
43
  "sha-384": Digest::SHA384,
44
44
  "sha-512": Digest::SHA512,
45
+ # XXX not sure if i want to do this
46
+ "sha-256-32": Digest::SHA256,
47
+ "sha-256-64": Digest::SHA256,
48
+ "sha-256-96": Digest::SHA256,
49
+ "sha-256-120": Digest::SHA256,
50
+ "sha-256-128": Digest::SHA256,
45
51
  }
46
52
 
53
+ LENGTHS = DIGESTS.map do |k, v|
54
+ v = if m = /^sha-256-(\d+)$/.match(k)
55
+ m.captures.first.to_i / 8
56
+ else
57
+ v.new.digest_length
58
+ end
59
+
60
+ [k, v]
61
+ end.to_h
62
+
47
63
  # resolve first against digest length and then class
48
64
  DIGEST_REV = {
49
65
  64 => { Digest::SHA512 => :"sha-512", Digest::SHA2 => :"sha-512" },
@@ -95,11 +111,14 @@ class URI::NI < URI::Generic
95
111
  16 => [/^[0-9A-Fa-f]*$/, 'Data %s is not in hexadecimal'],
96
112
  }
97
113
 
98
- def assert_repr data, radix
114
+ ASSERT_REPR = -> data, radix do
99
115
  re, error = ASSERT[radix]
100
- raise ArgumentError, error % data unless re.match data
116
+ raise ArgumentError, error % data unless re.match? data
101
117
  end
102
118
 
119
+ define_method :assert_repr, &ASSERT_REPR
120
+ define_singleton_method :assert_repr, &ASSERT_REPR
121
+
103
122
  # from whatever to binary
104
123
  DECODE = {
105
124
  256 => -> x { x },
@@ -133,12 +152,15 @@ class URI::NI < URI::Generic
133
152
  16 => -> x { x.upcase },
134
153
  }
135
154
 
136
- def transcode data, from: 256, to: 256, alt: false
155
+ TRANSCODE = -> data, from: 256, to: 256, alt: false do
137
156
  assert_repr data, from
138
157
  data = ENCODE[to].call(DECODE[from].call data) unless from == to
139
158
  alt ? ALT[to].call(data) : CANON[to].call(data)
140
159
  end
141
160
 
161
+ define_method :transcode, &TRANSCODE
162
+ define_singleton_method :transcode, &TRANSCODE
163
+
142
164
  protected
143
165
 
144
166
  # holy crap you can override these?
@@ -160,6 +182,53 @@ class URI::NI < URI::Generic
160
182
 
161
183
  public
162
184
 
185
+ # Transform a digest for a known algorithm into a {URI::NI}. Takes a
186
+ # binary, Base64, Base32, or hexadecimal string.
187
+ #
188
+ # @param algorithm [Symbol,#to_sym] a supported algorithm
189
+ # @param digest [String, #to_s, Digest::Instance] the digest (or context)
190
+ #
191
+ # @raise [ArgumentError] if the algorithm is unsupported
192
+ # @raise [ArgumentError] if the input string is not the right length
193
+ # for the algorithm
194
+ # @raise [ArgumentError] if the input string is incorrectly encoded
195
+ #
196
+ # @return [URI::NI] the transformed identifier
197
+ #
198
+ def self.ingest algorithm = nil, digest
199
+ return compute(digest) if digest.is_a? Digest::Instance
200
+ return digest if digest.is_a? URI::NI # noop
201
+
202
+ # make sure we're indeed dealing with a string
203
+ digest = digest.to_s
204
+
205
+ # just parse if it's already a ni: URI string
206
+ return URI(digest) if /^ni:/i.match? digest
207
+
208
+ # get the expected length of the digest for the algorithm
209
+ len = LENGTHS[algorithm.to_s.downcase.to_sym] or raise ArgumentError,
210
+ "unsupported algorithm #{algorithm}"
211
+
212
+ # the length of the string is used to determine the expected encoding
213
+ radix = case digest.length
214
+ when len then 256
215
+ when -> x { x >= (len * 8 / 6.0).ceil && x < (len * 8 / 5.0).ceil }
216
+ # note that a length longer than base64 but shorter than base32
217
+ # can be assumed to be base64 with padding
218
+ 64
219
+ when (len * 8 / 5.0).ceil then 32
220
+ when len * 2 then 16
221
+ else
222
+ raise ArgumentError, "invalid string length: #{digest.length}"
223
+ end
224
+
225
+ # then we lint it to see if it's correct
226
+ digest = transcode digest, from: radix, to: 64
227
+
228
+ # then we transcode
229
+ URI("ni:///#{algorithm};#{digest}")
230
+ end
231
+
163
232
  # Compute an RFC6920 URI from a data source.
164
233
  #
165
234
  # @param data [#to_s, IO, Digest, nil]
@@ -171,8 +240,8 @@ class URI::NI < URI::Generic
171
240
  # @yieldparam ctx [Digest::Instance] The digest instance to the block
172
241
  # @yieldparam buf [String, nil] The current read buffer (if +data+ is set)
173
242
  # @yieldreturn [nil] The result of the block is ignored
174
- #
175
- # @return [URI::NI]
243
+ #
244
+ # @return [URI::NI]
176
245
  def self.compute data = nil, algorithm: :"sha-256", blocksize: 65536,
177
246
  authority: nil, query: nil, &block
178
247
 
@@ -192,7 +261,7 @@ class URI::NI < URI::Generic
192
261
  ctx = DIGESTS[algorithm]
193
262
  ctx.new
194
263
  end
195
-
264
+
196
265
  # (Re)-compute a digest using existing information from an instance.
197
266
  # @see .compute
198
267
  def compute data = nil, algorithm: nil, blocksize: 65536,
@@ -206,7 +275,8 @@ class URI::NI < URI::Generic
206
275
  # special case for when the data is a digest
207
276
  ctx = nil
208
277
  if data.is_a? Digest::Instance
209
- algorithm ||= algo_for data, algorithm
278
+ # note the self; this would have been a bug lol
279
+ self.algorithm = algorithm ||= algo_for data, algorithm
210
280
  ctx = data
211
281
  data = nil # unset data
212
282
  else
@@ -241,17 +311,26 @@ class URI::NI < URI::Generic
241
311
  block.call ctx, nil
242
312
  end
243
313
 
244
- self.set_path("/#{algorithm};" +
245
- ctx.base64digest.tr('+/', '-_').tr('=', ''))
314
+ set_digest ctx.digest
315
+
246
316
  self
247
317
  end
248
318
 
319
+ # Returns true if the digest length matches the algorithm.
320
+ #
321
+ # @return [false, true]
322
+ #
323
+ def valid?
324
+ LENGTHS[algorithm] and LENGTHS[algorithm] == digest.length
325
+ end
326
+
249
327
  # Display the available algorithms.
250
328
  #
251
329
  # @return [Array] containing the symbols representing the available
252
330
  # digest algorithms.
253
- def self.algorithms
254
- DIGESTS.keys.sort
331
+ def self.algorithms truncated: false
332
+ out = DIGESTS.keys.sort
333
+ truncated ? out : out.reject { |a| /^sha-256-/.match? a }
255
334
  end
256
335
 
257
336
  # Obtain the algorithm of the digest. May be nil.
@@ -329,7 +408,10 @@ class URI::NI < URI::Generic
329
408
  when Digest::Instance
330
409
  compute value
331
410
  when String
332
- value = transcode value, from: radix, to: 64
411
+ value = transcode value, from: radix
412
+ value = value[0, LENGTHS[a.to_sym]] # deal with truncation
413
+ value = transcode value, to: 64
414
+
333
415
  self.path = a ? "/#{a};#{value}" : "/;#{value}"
334
416
  when nil
335
417
  self.path = a ? "/#{a}" : ?/
@@ -475,16 +557,17 @@ class URI::NI < URI::Generic
475
557
  to_www https: false, authority: authority
476
558
  end
477
559
 
478
- # Returns the set of supported algorithms.
479
- # @return [Array] the algorithms
480
- def self.algorithms
481
- DIGESTS.keys
482
- end
483
560
 
484
561
  # Returns true if the algorithm is supported.
485
562
  # @param algorithm [Symbol,String] the algorithm identifier to test
486
563
  # @return [true, false] whether it is supported
487
564
  def self.valid_algo? algorithm
488
- DIGESTS.has_key? algorithm.to_s.downcase.to_sym
565
+ algorithm = algorithm.to_s.downcase.to_sym
566
+
567
+ # special case for truncated sha-256
568
+ return true if /^(sha-256)-(32|64|96|120|128)$/.match? algorithm
569
+
570
+ # etc
571
+ DIGESTS.has_key? algorithm
489
572
  end
490
573
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uri-ni
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dorian Taylor
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2023-07-12 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: bundler
@@ -65,7 +64,6 @@ licenses:
65
64
  - Apache-2.0
66
65
  metadata:
67
66
  homepage_uri: https://github.com/doriantaylor/rb-uri-ni
68
- post_install_message:
69
67
  rdoc_options: []
70
68
  require_paths:
71
69
  - lib
@@ -80,8 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
78
  - !ruby/object:Gem::Version
81
79
  version: '0'
82
80
  requirements: []
83
- rubygems_version: 3.3.15
84
- signing_key:
81
+ rubygems_version: 3.6.7
85
82
  specification_version: 4
86
83
  summary: URI handler for RFC6920 ni:/// URIs
87
84
  test_files: []