linzer 0.5.0 → 0.5.2

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: 026db131a5602b1f62b4f930086a0612b99f17a3aa6aa0eb649baa7bc8ba574b
4
- data.tar.gz: 8f29e81e3083257c4731c9e408f4a66a95125fdb4d0678fd8d16cc410637d694
3
+ metadata.gz: 0befd6a2ae7ba008f6b2a343a24845be1941b6645615d8a029e698c083cd4481
4
+ data.tar.gz: ebd92e2c6b0991067753079c8b1bac87a6dfe644caa6380dedc63f88e74877e4
5
5
  SHA512:
6
- metadata.gz: 6edb3a943f2bcf408ed865fe8bec013c3b13e609ea791981474a84bb21936b2e5fa61d86e64f9e9917c0a3e440e6246d443761c81cd94c094898c78423137789
7
- data.tar.gz: 82074df18649f3f85af7c187762dbcf90b602c9748c9f6dba4695db42ee53ce24c5a546589f96011ab9d47564e1f9d2436a35616b54678e24f4222cd12f97837
6
+ metadata.gz: c7c5b9d9568402b2b4894ef8180c321281b420a156e7386abf12f069780a6ba7e2bc79d58bd0b7c97372058f974a25a1a138e9306434c28025e39f3267562b81
7
+ data.tar.gz: 7b997d06b2764171d5375baf1b889f4d98231961b86f89bea321155766932ffcd6913462df080f7edf09731d6d78332b474cda381ea4d0d8bdafba3dee76e6b3
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.5.2] - 2024-04-02
4
+
5
+ - Make all unit tests pass on Ruby 3.0:
6
+ * Set minimum required version on openssl and uri gems.
7
+ - Small refactor on ECDSA module.
8
+
9
+ ## [0.5.1] - 2024-04-01
10
+
11
+ - Add support for additional derived components:
12
+ @target-uri, @scheme, @request-target, @query and @query-param.
13
+
3
14
  ## [0.5.0] - 2024-03-30
4
15
 
5
16
  - Build Linzer::Message instances from Rack request and response objects
data/README.md CHANGED
@@ -1,4 +1,11 @@
1
- # Linzer
1
+ # Linzer [![Latest Version][gem-badge]][gem-link] [![License: MIT][license-image]][license-link] [![CI Status][ci-image]][ci-link]
2
+
3
+ [gem-badge]: https://badge.fury.io/rb/linzer.svg
4
+ [gem-link]: https://rubygems.org/gems/linzer
5
+ [license-image]: https://img.shields.io/badge/license-MIT-blue.svg
6
+ [license-link]: https://github.com/nomadium/linzer/blob/master/LICENSE.txt
7
+ [ci-image]: https://github.com/nomadium/linzer/actions/workflows/main.yml/badge.svg?branch=master
8
+ [ci-link]: https://github.com/nomadium/linzer/actions/workflows/main.yml
2
9
 
3
10
  Linzer is a Ruby library for [HTTP Message Signatures (RFC 9421)](https://www.rfc-editor.org/rfc/rfc9421.html).
4
11
 
@@ -93,7 +100,10 @@ response = http.post("/some_uri", "data", headers.merge(signature.to_h))
93
100
  test_ed25519_key_pub = Base64.strict_encode64(key.material.verify_key.to_bytes)
94
101
  # => "EUra7KsJ8B/lSZJVhDaopMycmZ6T7KtJqKVNJTHKIw0="
95
102
 
96
- pubkey = Linzer.new_ed25519_public_key(test_ed25519_key_pub, "some-key-ed25519")
103
+ raw_pubkey = Base64.strict_decode64(test_ed25519_key_pub)
104
+ # => "\xB1rM\xFFR\x1F\xDDw\x00\x89\..."
105
+
106
+ pubkey = Linzer.new_ed25519_public_key(raw_pubkey, "some-key-ed25519")
97
107
  # => #<Linzer::Ed25519::Key:0x00000fe19b9384b0
98
108
 
99
109
  # if you have to, there is a helper method to build a request object on the server side
data/lib/linzer/ecdsa.rb CHANGED
@@ -18,23 +18,25 @@ module Linzer
18
18
 
19
19
  private
20
20
 
21
+ DIGEST_PARAMS = {
22
+ "SHA256" => {hex_format: "%.64x", hex_length: 64},
23
+ "SHA384" => {hex_format: "%.96x", hex_length: 96}
24
+ }
25
+ private_constant :DIGEST_PARAMS
26
+
21
27
  def der_signature(sig)
22
28
  digest = @params[:digest]
23
29
  msg = "Cannot verify invalid signature."
30
+ raise Linzer::Error.new(msg) unless DIGEST_PARAMS.key?(digest)
31
+ digest_params = DIGEST_PARAMS[digest]
32
+
33
+ l = digest_params[:hex_length]
34
+ raise Linzer::Error.new(msg) if sig.length != l
35
+ h = l / 2
36
+ fmt = "H#{l}"
24
37
 
25
- case digest
26
- when "SHA256"
27
- raise Linzer::Error.new(msg) if sig.length != 64
28
- r_bn = OpenSSL::BN.new(sig[0..31].unpack1("H64").to_i(16))
29
- s_bn = OpenSSL::BN.new(sig[32..63].unpack1("H64").to_i(16))
30
- when "SHA384"
31
- raise Linzer::Error.new(msg) if sig.length != 96
32
- r_bn = OpenSSL::BN.new(sig[0..47].unpack1("H96").to_i(16))
33
- s_bn = OpenSSL::BN.new(sig[48..95].unpack1("H96").to_i(16))
34
- else
35
- msg = "Cannot verify signature, unsupported digest algorithm: '%s'" % digest
36
- raise Linzer::Error.new(msg)
37
- end
38
+ r_bn = OpenSSL::BN.new(sig[0..(h - 1)].unpack1(fmt).to_i(16))
39
+ s_bn = OpenSSL::BN.new(sig[h..(l - 1)].unpack1(fmt).to_i(16))
38
40
 
39
41
  r = OpenSSL::ASN1::Integer(r_bn)
40
42
  s = OpenSSL::ASN1::Integer(s_bn)
@@ -46,17 +48,15 @@ module Linzer
46
48
  def decode_der_signature(der_sig)
47
49
  digest = @params[:digest]
48
50
  msg = "Unsupported digest algorithm: '%s'" % digest
51
+ raise Linzer::Error.new(msg) unless DIGEST_PARAMS.key?(digest)
52
+ digest_params = DIGEST_PARAMS[digest]
53
+ fmt = "H#{digest_params[:hex_length]}"
54
+
49
55
  OpenSSL::ASN1
50
56
  .decode(der_sig)
51
57
  .value
52
- .map do |n|
53
- case digest
54
- when "SHA256" then "%.64x" % n.value
55
- when "SHA384" then "%.96x" % n.value
56
- else raise Linzer::Error.new(msg)
57
- end
58
- end
59
- .map { |s| [s].pack("H#{s.length}") }
58
+ .map { |bn| digest_params[:hex_format] % bn.value }
59
+ .map { |hex| [hex].pack(fmt) }
60
60
  .reduce(:<<)
61
61
  .encode(Encoding::ASCII_8BIT)
62
62
  end
@@ -25,20 +25,33 @@ module Linzer
25
25
  !!self[f]
26
26
  end
27
27
 
28
+ DERIVED_COMPONENT = {
29
+ "@method" => :request_method,
30
+ "@authority" => :authority,
31
+ "@path" => :path_info,
32
+ "@status" => :status,
33
+ "@target-uri" => :url,
34
+ "@scheme" => :scheme,
35
+ "@request-target" => :fullpath,
36
+ "@query" => :query_string
37
+ }.freeze
38
+
28
39
  def [](field_name)
29
40
  if !field_name.start_with?("@")
30
41
  return @operation.env[Request.rack_header_name(field_name)] if request?
31
42
  return @operation.headers[field_name] # if response?
32
43
  end
33
44
 
45
+ method = DERIVED_COMPONENT[field_name]
46
+
34
47
  case field_name
35
- when "@method" then @operation.request_method
36
- when "@authority" then @operation.authority
37
- when "@path" then @operation.path_info
38
- when "@status" then @operation.status
39
- else # XXX: improve this and add support for all fields in the RFC
40
- raise Error.new "Unknown/unsupported field: \"#{field_name}\""
48
+ when "@query"
49
+ return "?#{@operation.public_send(method)}"
50
+ when /\A(?<field>(?<prefix>@query-param)(?<rest>;name=.+)\Z)/
51
+ return parse_query_param Regexp.last_match
41
52
  end
53
+
54
+ method ? @operation.public_send(method) : nil
42
55
  end
43
56
 
44
57
  class << self
@@ -48,5 +61,17 @@ module Linzer
48
61
  raise Error.new "Cannot parse \"#{field_name}\" field. Bailing out!"
49
62
  end
50
63
  end
64
+
65
+ private
66
+
67
+ def parse_query_param(match_data)
68
+ raw_item = '"%s"%s' % [match_data[:prefix], match_data[:rest]]
69
+ parsed_item = Starry.parse_item(raw_item)
70
+ fail unless parsed_item.value == "@query-param"
71
+ param_name = URI.decode_uri_component(parsed_item.parameters["name"])
72
+ URI.encode_uri_component(@operation.params.fetch(param_name))
73
+ rescue => _
74
+ nil
75
+ end
51
76
  end
52
77
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Linzer
4
- VERSION = "0.5.0"
4
+ VERSION = "0.5.2"
5
5
  end
data/lib/linzer.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require "starry"
4
4
  require "openssl"
5
5
  require "rack"
6
+ require "uri"
6
7
 
7
8
  require_relative "linzer/version"
8
9
  require_relative "linzer/common"
data/linzer.gemspec CHANGED
@@ -29,7 +29,9 @@ Gem::Specification.new do |spec|
29
29
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
30
  spec.require_paths = ["lib"]
31
31
 
32
+ spec.add_runtime_dependency "openssl", ">= 3.0.0"
32
33
  spec.add_runtime_dependency "ed25519", "~> 1.3", ">= 1.3.0"
33
34
  spec.add_runtime_dependency "starry", "~> 0.1"
34
35
  spec.add_runtime_dependency "rack", "~> 3.0"
36
+ spec.add_runtime_dependency "uri", ">= 0.12.0"
35
37
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: linzer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Landaeta
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-03-30 00:00:00.000000000 Z
11
+ date: 2024-04-01 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: openssl
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 3.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.0
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: ed25519
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -58,6 +72,20 @@ dependencies:
58
72
  - - "~>"
59
73
  - !ruby/object:Gem::Version
60
74
  version: '3.0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: uri
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: 0.12.0
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 0.12.0
61
89
  description:
62
90
  email:
63
91
  - miguel@miguel.cc