linzer 0.5.0 → 0.5.2

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