uri-ni 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +15 -7
- data/lib/uri/ni/version.rb +1 -1
- data/lib/uri/ni.rb +131 -52
- data/uri-ni.gemspec +2 -1
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eff8af7f69a76b24ce06948c53ad963d39552ec2dee0b08179496a1a8eb5d2a1
|
4
|
+
data.tar.gz: d7d285ac8eb47acf9acd0cd3de7dbcad6110c9e80f1860817534b18c1e25d87c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4bbdf0f3d6fd23db734e13403e20d96f6e29730c43f93351556a47ab10250508b743497c02870bcb7447d643e31254686a889277e5bbf10941caef329b6b71d2
|
7
|
+
data.tar.gz: b777dc59e94aff9e947cfd4661b64aecc727baeae4a2c5cc14fed58c8b59fd4495bb6ae935864a2e61a8fb9dbb86098e3665475baa2c59127975d97b734f5046
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -48,20 +48,28 @@ result and compute a new digest with it:
|
|
48
48
|
ni
|
49
49
|
# => #<URI::NI ni:///lol;wut>
|
50
50
|
ni.compute 'derp'
|
51
|
-
|
51
|
+
# URI::InvalidComponentError: Can't resolve a Digest context for the algorithm lol.
|
52
52
|
```
|
53
53
|
|
54
|
-
|
55
|
-
|
54
|
+
The purpose of this configuration is so that the parser doesn't croak
|
55
|
+
on unexpected input, but otherwise assumes you know what you're
|
56
|
+
doing. As such, there is no attempt to measure or otherwise divine the
|
57
|
+
representation of any updates to the `digest` component:
|
56
58
|
|
57
|
-
```
|
58
|
-
ni
|
59
|
-
|
59
|
+
```ruby
|
60
|
+
ni = URI::NI.compute 'some data'
|
61
|
+
# => #<URI::NI ni:///sha-256;EweZDmulyhRes16ZGCqb7EZTG8VN32VqYCx4D6AkDe4>
|
62
|
+
ni.digest = 'whatever'
|
63
|
+
# => "whatever"
|
64
|
+
ni
|
65
|
+
# => #<URI::NI ni:///sha-256;d2hhdGV2ZXI>
|
60
66
|
```
|
61
67
|
|
62
68
|
In addition to computing new digest URIs, this module will return the
|
63
|
-
interesting part of its contents in binary,
|
69
|
+
interesting part of its contents in binary, hexadecimal, base64, and
|
64
70
|
(with a soft dependency), [base32](https://rubygems.org/gems/base32).
|
71
|
+
There are accessors and mutators for `digest`, `hexdigest`,
|
72
|
+
`b32digest`, and `b64digest`.
|
65
73
|
|
66
74
|
Finally, this module will also reuse any extant `Digest::Instance`
|
67
75
|
object as long as it is in the inventory, and furthermore the
|
data/lib/uri/ni/version.rb
CHANGED
data/lib/uri/ni.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
require 'uri/ni/version'
|
2
3
|
require 'uri'
|
3
4
|
require 'uri/generic'
|
@@ -79,6 +80,65 @@ class URI::NI < URI::Generic
|
|
79
80
|
m.captures
|
80
81
|
end
|
81
82
|
|
83
|
+
def assert_radix radix
|
84
|
+
raise ArgumentError,
|
85
|
+
"Radix must be 16, 32, 64, or 256, not #{radix.inspect}" unless
|
86
|
+
[256, 64, 32, 16].include? radix
|
87
|
+
radix
|
88
|
+
end
|
89
|
+
|
90
|
+
# assertions about data representation
|
91
|
+
ASSERT = {
|
92
|
+
256 => [/.*/, ''],
|
93
|
+
64 => [/^[0-9A-Za-z+\/_-]*=*$/, 'Data %s is not in base64'],
|
94
|
+
32 => [/^[2-7A-Za-z]*=*$/, 'Data %s is not in base32'],
|
95
|
+
16 => [/^[0-9A-Fa-f]*$/, 'Data %s is not in hexadecimal'],
|
96
|
+
}
|
97
|
+
|
98
|
+
def assert_repr data, radix
|
99
|
+
re, error = ASSERT[radix]
|
100
|
+
raise ArgumentError, error % data unless re.match data
|
101
|
+
end
|
102
|
+
|
103
|
+
# from whatever to binary
|
104
|
+
DECODE = {
|
105
|
+
256 => -> x { x },
|
106
|
+
64 => -> x { Base64.decode64 x.tr('-_', '+/') },
|
107
|
+
32 => -> x { require 'base32'; Base32.decode x },
|
108
|
+
16 => -> x { [x].pack 'H*' },
|
109
|
+
}
|
110
|
+
|
111
|
+
# from binary to whatever
|
112
|
+
ENCODE = {
|
113
|
+
256 => -> x { x },
|
114
|
+
64 => -> x { Base64.urlsafe_encode64(x).tr '=', '' },
|
115
|
+
32 => -> x { require 'base32'; Base32.encode(x).tr '=', '' },
|
116
|
+
16 => -> x { x.unpack1 'H*' },
|
117
|
+
}
|
118
|
+
|
119
|
+
# canonical and alternative representations
|
120
|
+
CANON = {
|
121
|
+
256 => -> x { x },
|
122
|
+
64 => -> x { x.tr('=', '').tr '+/', '-_' },
|
123
|
+
32 => -> x { x.tr('=', '').upcase },
|
124
|
+
16 => -> x { x.downcase },
|
125
|
+
}
|
126
|
+
|
127
|
+
# note if we put the padding here then we sanitize input as well
|
128
|
+
|
129
|
+
ALT = {
|
130
|
+
256 => -> x { x },
|
131
|
+
64 => -> x { x.tr('=', '').tr '-_', '+/' },
|
132
|
+
32 => -> x { x.tr('=', '').downcase },
|
133
|
+
16 => -> x { x.upcase },
|
134
|
+
}
|
135
|
+
|
136
|
+
def transcode data, from: 256, to: 256, alt: false
|
137
|
+
assert_repr data, from
|
138
|
+
data = ENCODE[to].call(DECODE[from].call data) unless from == to
|
139
|
+
alt ? ALT[to].call(data) : CANON[to].call(data)
|
140
|
+
end
|
141
|
+
|
82
142
|
protected
|
83
143
|
|
84
144
|
# holy crap you can override these?
|
@@ -127,8 +187,8 @@ class URI::NI < URI::Generic
|
|
127
187
|
else
|
128
188
|
# make sure we're all on the same page hurr
|
129
189
|
self.algorithm = algorithm ||= self.algorithm
|
130
|
-
raise
|
131
|
-
"
|
190
|
+
raise URI::InvalidComponentError,
|
191
|
+
"Can't resolve a Digest context for the algorithm #{algorithm}." unless
|
132
192
|
ctx = DIGESTS[algorithm]
|
133
193
|
ctx = ctx.new
|
134
194
|
end
|
@@ -157,8 +217,7 @@ class URI::NI < URI::Generic
|
|
157
217
|
end
|
158
218
|
|
159
219
|
self.set_path("/#{algorithm};" +
|
160
|
-
ctx.base64digest.
|
161
|
-
|
220
|
+
ctx.base64digest.tr('+/', '-_').tr('=', ''))
|
162
221
|
self
|
163
222
|
end
|
164
223
|
|
@@ -184,7 +243,7 @@ class URI::NI < URI::Generic
|
|
184
243
|
def algorithm= algo
|
185
244
|
a, b = assert_path
|
186
245
|
self.path = "/#{algo}"
|
187
|
-
self.
|
246
|
+
self.set_digest(b, radix: 64) if b
|
188
247
|
a.to_sym if a
|
189
248
|
end
|
190
249
|
|
@@ -223,46 +282,51 @@ class URI::NI < URI::Generic
|
|
223
282
|
# @return [String] The digest of the URI in the given representation
|
224
283
|
#
|
225
284
|
def digest radix: 256, alt: false
|
226
|
-
|
227
|
-
|
228
|
-
# XXX do not use urlsafe_decode64; it will complain if the
|
229
|
-
# thingies aren't aligned
|
230
|
-
Base64.decode64(raw_digest.tr('-_', '+/'))
|
231
|
-
when 64
|
232
|
-
b64digest alt: alt
|
233
|
-
when 32
|
234
|
-
b32digest alt: alt
|
235
|
-
when 16
|
236
|
-
hexdigest alt: alt
|
237
|
-
else
|
238
|
-
raise ArgumentError, "Radix must be 16, 32, 64, 256, not #{radix}"
|
239
|
-
end
|
285
|
+
assert_radix radix
|
286
|
+
transcode raw_digest, from: 64, to: radix, alt: alt
|
240
287
|
end
|
241
288
|
|
242
|
-
# Set the digest to the data. Data may
|
243
|
-
# +Digest::Instance
|
244
|
-
#
|
245
|
-
# RFC 3548} base64url, i.e. +\+/+ will be replaced with +-_+ and
|
246
|
-
# padding (+=+) will be removed. +Digest::Instance+ objects will
|
289
|
+
# Set the digest to the data, with an optional radix. Data may
|
290
|
+
# either be a +Digest::Instance+—in which case the radix is
|
291
|
+
# ignored–a string, or +nil+. +Digest::Instance+ objects will
|
247
292
|
# just be run through #compute, with all that entails.
|
248
|
-
|
249
|
-
|
250
|
-
|
293
|
+
#
|
294
|
+
# @param value [String, nil, Digest::Instance] The new digest
|
295
|
+
# @param radix [256, 64, 32, 16] The radix of the encoding (default 256)
|
296
|
+
# @return [String] The _old_ digest in the given radix
|
297
|
+
#
|
298
|
+
def set_digest value, radix: 256
|
299
|
+
assert_radix radix
|
300
|
+
|
301
|
+
a, d = assert_path
|
302
|
+
|
303
|
+
case value
|
251
304
|
when Digest::Instance
|
252
|
-
compute
|
305
|
+
compute value
|
253
306
|
when String
|
254
|
-
|
255
|
-
|
256
|
-
data = data.tr('+/', '-_').tr('=', '')
|
257
|
-
self.path = a ? "/#{a};#{data}" : "/;#{data}"
|
307
|
+
value = transcode value, from: radix, to: 64
|
308
|
+
self.path = a ? "/#{a};#{value}" : "/;#{value}"
|
258
309
|
when nil
|
259
310
|
self.path = a ? "/#{a}" : ?/
|
260
311
|
else
|
261
312
|
raise ArgumentError,
|
262
|
-
"
|
313
|
+
"Value must be a string or Digest::Instance, not #{value.class}"
|
263
314
|
end
|
264
315
|
|
265
|
-
|
316
|
+
# bail out if nil
|
317
|
+
return unless d
|
318
|
+
transcode d, from: 64, to: radix
|
319
|
+
end
|
320
|
+
|
321
|
+
# Set the digest to the data. Data may either be a
|
322
|
+
# +Digest::Instance+ or a _binary_ string. +Digest::Instance+
|
323
|
+
# objects will just be run through #compute, with all that entails.
|
324
|
+
#
|
325
|
+
# @param value [String, nil, Digest::Instance] the new digest
|
326
|
+
# @return [String, nil, Digest::Instance] the value passed in
|
327
|
+
#
|
328
|
+
def digest= value
|
329
|
+
return set_digest value
|
266
330
|
end
|
267
331
|
|
268
332
|
# Return the digest in its hexadecimal notation. Optionally give
|
@@ -273,44 +337,59 @@ class URI::NI < URI::Generic
|
|
273
337
|
# @return [String] The hexadecimal digest
|
274
338
|
#
|
275
339
|
def hexdigest alt: false
|
276
|
-
|
277
|
-
|
278
|
-
|
340
|
+
transcode raw_digest, from: 64, to: 16, alt: alt
|
341
|
+
end
|
342
|
+
|
343
|
+
# Set the digest value, assuming a hexadecimal input.
|
344
|
+
# @param value [String, nil, Digest::Instance] the new digest
|
345
|
+
# @return [String, nil, Digest::Instance] the value passed in
|
346
|
+
def hexdigest= value
|
347
|
+
set_digest value, radix: 16
|
279
348
|
end
|
280
349
|
|
281
350
|
# Return the digest in its base32 notation. Optionally give
|
282
351
|
# +alt:+ a truthy value to return an alternate (lowercase)
|
283
|
-
# representation. Note this method requires
|
352
|
+
# representation. Note this method requires the base32 module.
|
284
353
|
#
|
285
354
|
# @param alt [false, true] Return the alternative representation
|
286
355
|
# @return [String] The base32 digest
|
287
356
|
#
|
288
357
|
def b32digest alt: false
|
289
|
-
|
290
|
-
ret = Base32.encode(digest).gsub(/=+/, '')
|
291
|
-
return ret.downcase if alt
|
292
|
-
ret.upcase
|
358
|
+
transcode raw_digest, from: 64, to: 32, alt: alt
|
293
359
|
end
|
294
360
|
|
295
|
-
#
|
296
|
-
#
|
297
|
-
#
|
361
|
+
# Set the digest value, assuming a base32 input (requires base32).
|
362
|
+
# @param value [String, nil, Digest::Instance] the new digest
|
363
|
+
# @return [String, nil, Digest::Instance] the value passed in
|
364
|
+
def b32digest= value
|
365
|
+
set_digest value, radix: 32
|
366
|
+
end
|
367
|
+
|
368
|
+
# Return the digest in its base64 notation. Note it is the
|
369
|
+
# _default_ representation that is URL-safe, for parity with the
|
370
|
+
# identifier itself. Give +alt:+ a truthy value to return a plain
|
371
|
+
# (_non_-URL-safe) base64 representation.
|
298
372
|
#
|
299
373
|
# @param alt [false, true] Return the alternative representation
|
300
374
|
# @return [String] The base64 digest
|
301
375
|
#
|
302
376
|
def b64digest alt: false
|
303
|
-
|
304
|
-
|
305
|
-
|
377
|
+
transcode raw_digest, from: 64, to: 64, alt: alt
|
378
|
+
end
|
379
|
+
|
380
|
+
# Set the digest value, assuming a base64 input.
|
381
|
+
# @param value [String, nil, Digest::Instance] the new digest
|
382
|
+
# @return [String, nil, Digest::Instance] the value passed in
|
383
|
+
def b64digest= value
|
384
|
+
set_digest value, radix: 64
|
306
385
|
end
|
307
386
|
|
308
387
|
# Returns a +/.well-known/...+, either HTTPS or HTTP URL, given the
|
309
388
|
# contents of the +ni:+ URI.
|
310
389
|
#
|
311
390
|
# @param authority [#to_s, URI] Override the authority part of the URI
|
312
|
-
# @param https [true, false]
|
313
|
-
# @return [URI::HTTPS, URI::HTTP]
|
391
|
+
# @param https [true, false] Whether the URL is to be HTTPS.
|
392
|
+
# @return [URI::HTTPS, URI::HTTP] The generated URL.
|
314
393
|
#
|
315
394
|
def to_www https: true, authority: nil
|
316
395
|
a, d = assert_path
|
@@ -327,13 +406,13 @@ class URI::NI < URI::Generic
|
|
327
406
|
if authority
|
328
407
|
uhp = []
|
329
408
|
if authority.is_a? URI
|
330
|
-
raise
|
409
|
+
raise URI::InvalidComponentError, "Bad authority #{authority}" unless
|
331
410
|
%i[userinfo host port].all? {|c| authority.respond_to? c }
|
332
411
|
uhp = [authority.userinfo, authority.host, authority.port]
|
333
412
|
uhp[2] = nil if authority.port == authority.class::DEFAULT_PORT
|
334
413
|
else
|
335
414
|
authority = authority.to_s
|
336
|
-
uhp = AUTH_RE.match(authority) or raise
|
415
|
+
uhp = AUTH_RE.match(authority) or raise URI::InvalidComponentError,
|
337
416
|
"Invalid authority #{authority}"
|
338
417
|
uhp = uhp.captures
|
339
418
|
end
|
data/uri-ni.gemspec
CHANGED
@@ -24,10 +24,11 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.require_paths = ['lib']
|
25
25
|
|
26
26
|
# ruby
|
27
|
-
spec.required_ruby_version =
|
27
|
+
spec.required_ruby_version = '>= 2.3.0'
|
28
28
|
|
29
29
|
# dev/test dependencies
|
30
30
|
spec.add_development_dependency 'bundler', '~> 2'
|
31
|
+
spec.add_development_dependency 'base32', '~> 0.3'
|
31
32
|
# bundler put these in the gemfile i dunno wtf
|
32
33
|
#spec.add_development_dependency 'rake', '~> 12.0'
|
33
34
|
#spec.add_development_dependency 'rspec', '~> 3.0'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uri-ni
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dorian Taylor
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-01-
|
11
|
+
date: 2020-01-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: base32
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.3'
|
27
41
|
description: ''
|
28
42
|
email:
|
29
43
|
- code@doriantaylor.com
|
@@ -57,7 +71,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
71
|
requirements:
|
58
72
|
- - ">="
|
59
73
|
- !ruby/object:Gem::Version
|
60
|
-
version:
|
74
|
+
version: 2.3.0
|
61
75
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
76
|
requirements:
|
63
77
|
- - ">="
|