linzer 0.7.3 → 0.7.4

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: 13262f7f33737c2ad3aec4007e612001dc9d72c97f9a0636681f0ae695d98315
4
- data.tar.gz: c9663a699455f8cab8cc2214c0af3da835a4e46542f6029dcddece40ad5b9a35
3
+ metadata.gz: 7ca1f4d456be7ceedda5bbe7cfd205e696689da336408324c6ec06ed10440d07
4
+ data.tar.gz: 1db3b82c5644c65b6037cb844bea963aa803dd4bf74c93673aac8473dc647d38
5
5
  SHA512:
6
- metadata.gz: f4e7386cf5bb74bd20d2c74bd3fd8054c068ccc1b8704a088296ead0f61c5029cccd51744d974ef1123166a30068790590cafe6c4e3f27c55c67e0637a0073bb
7
- data.tar.gz: 798032dd1a2c345f51fd23281bd9028a1ff31495f41e8d4c241d653d1857233e1c9c3bb327539c2296a399d0b5df4bbf02b9954e252ba486a022c80f79066785
6
+ metadata.gz: ce767d2e1c8df88b72321e8fbb513a9dadadb6436a4cefe6caa1a873f82cd4332b4f676ca0f355170156175077af2f675dabb22fbcb16ec7984950ca826a307c
7
+ data.tar.gz: affedd0f107f8ae2e9073ceb007896e5de9b45d2b50086bec7ff9dc6e771d208cffa7edb1e12ff414771a13eecc2597f2559b0d9c68a1a2ddb1010732afa2663
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.7.4] - 2025-06-30
4
+
5
+ - Add validation routines on key instances before performing
6
+ signing and verifying operations. This will catch obvious errors
7
+ like trying to sign a request with a public key.
8
+
9
+ - Fix bug with incorrect signature generation and verification on
10
+ messages with HTTP field identifiers including parameters. Those
11
+ fields were not serialized correctly and messages were being signed
12
+ with incorrect signature base.
13
+
3
14
  ## [0.7.3] - 2025-06-01
4
15
 
5
16
  - Fix broken retrieval of header names from Rack responses.
data/lib/linzer/common.rb CHANGED
@@ -2,23 +2,39 @@
2
2
 
3
3
  module Linzer
4
4
  module Common
5
- def signature_base(message, components, parameters)
6
- signature_base = components.each_with_object(+"") do |component, base|
7
- base << "\"#{component}\": #{message[component]}\n"
8
- end
5
+ def signature_base(message, serialized_components, parameters)
6
+ signature_base =
7
+ serialized_components.each_with_object(+"") do |component, base|
8
+ base << "%s\n" % signature_base_line(component, message)
9
+ end
9
10
 
10
- signature_params =
11
- Starry.serialize([Starry::InnerList.new(components, parameters)])
11
+ signature_base << signature_params_line(serialized_components, parameters)
12
12
 
13
- signature_base << "\"@signature-params\": #{signature_params}"
14
13
  signature_base
15
14
  end
16
15
  module_function :signature_base
17
16
 
17
+ def signature_base_line(component, message)
18
+ field_id = FieldId.new(field_name: component)
19
+ "%s: %s" % [field_id.serialize, message[field_id]]
20
+ end
21
+ module_function :signature_base_line
22
+
23
+ def signature_params_line(serialized_components, parameters)
24
+ identifiers = serialized_components.map { |c| Starry.parse_item(c) }
25
+
26
+ signature_params =
27
+ Starry.serialize([Starry::InnerList.new(identifiers, parameters)])
28
+
29
+ "%s: %s" % [Starry.serialize("@signature-params"), signature_params]
30
+ end
31
+ module_function :signature_params_line
32
+
18
33
  private
19
34
 
20
35
  def validate_components(message, components)
21
- if components.include?("@signature-params")
36
+ if components.include?('"@signature-params"') ||
37
+ components.any? { |c| c.start_with?('"@signature-params"') }
22
38
  raise Error.new "Invalid component in signature input"
23
39
  end
24
40
 
data/lib/linzer/ecdsa.rb CHANGED
@@ -9,10 +9,12 @@ module Linzer
9
9
  end
10
10
 
11
11
  def sign(data)
12
+ validate_signing_key
12
13
  decode_der_signature(material.sign(@params[:digest], data))
13
14
  end
14
15
 
15
16
  def verify(signature, data)
17
+ validate_verify_key
16
18
  material.verify(@params[:digest], der_signature(signature), data)
17
19
  end
18
20
 
@@ -4,12 +4,22 @@ module Linzer
4
4
  module Ed25519
5
5
  class Key < Linzer::Key
6
6
  def sign(data)
7
+ validate_signing_key
7
8
  material.sign(nil, data)
8
9
  end
9
10
 
10
11
  def verify(signature, data)
12
+ validate_verify_key
11
13
  material.verify(nil, signature, data)
12
14
  end
15
+
16
+ def public?
17
+ has_pem_public?
18
+ end
19
+
20
+ def private?
21
+ has_pem_private?
22
+ end
13
23
  end
14
24
  end
15
25
  end
data/lib/linzer/hmac.rb CHANGED
@@ -18,6 +18,14 @@ module Linzer
18
18
  signature == sign(data)
19
19
  end
20
20
 
21
+ def private?
22
+ !material.nil?
23
+ end
24
+
25
+ def public?
26
+ false
27
+ end
28
+
21
29
  def inspect
22
30
  vars =
23
31
  instance_variables
data/lib/linzer/jws.rb CHANGED
@@ -27,16 +27,21 @@ module Linzer
27
27
 
28
28
  class Key < Linzer::Key
29
29
  def sign(data)
30
- raise Linzer::SigningError, "Private key is missing!" if !material.private?
30
+ validate_signing_key
31
31
  algo = resolve_algorithm
32
32
  algo.sign(data: data, signing_key: signing_key)
33
33
  end
34
34
 
35
35
  def verify(signature, data)
36
+ validate_verify_key
36
37
  algo = resolve_algorithm
37
38
  algo.verify(data: data, signature: signature, verification_key: verify_key)
38
39
  end
39
40
 
41
+ def public?
42
+ !!verify_key
43
+ end
44
+
40
45
  private
41
46
 
42
47
  def resolve_algorithm
data/lib/linzer/key.rb CHANGED
@@ -17,12 +17,20 @@ module Linzer
17
17
 
18
18
  def sign(*args)
19
19
  abstract_error = "Cannot sign data, \"#{self.class}\" is an abstract class."
20
- raise Error.new abstract_error
20
+ raise Error, abstract_error
21
21
  end
22
22
 
23
23
  def verify(*args)
24
24
  abstract_error = "Cannot verify signature, \"#{self.class}\" is an abstract class."
25
- raise Error.new abstract_error
25
+ raise Error, abstract_error
26
+ end
27
+
28
+ def public?
29
+ material.public?
30
+ end
31
+
32
+ def private?
33
+ material.private?
26
34
  end
27
35
 
28
36
  private
@@ -34,7 +42,25 @@ module Linzer
34
42
  def validate_digest
35
43
  no_digest = !@params.key?(:digest) || @params[:digest].nil? || String(@params[:digest]).empty?
36
44
  no_digest_error = "Invalid key definition, no digest algorithm was selected."
37
- raise Linzer::Error.new no_digest_error if no_digest
45
+ raise Error, no_digest_error if no_digest
46
+ end
47
+
48
+ def validate_signing_key
49
+ raise SigningError, "Private key is needed!" unless private?
50
+ end
51
+
52
+ def validate_verify_key
53
+ raise VerifyError, "Public key is needed!" unless public?
54
+ end
55
+
56
+ def has_pem_public?
57
+ material.public_to_pem.match?(/^-----BEGIN PUBLIC KEY-----/)
58
+ end
59
+
60
+ def has_pem_private?
61
+ material.private_to_pem.match?(/^-----BEGIN PRIVATE KEY-----/)
62
+ rescue
63
+ false
38
64
  end
39
65
  end
40
66
  end
@@ -26,15 +26,10 @@ module Linzer
26
26
  !!self[f]
27
27
  end
28
28
 
29
- def [](field_name)
30
- name = parse_field_name(field_name)
31
- return nil if name.nil?
32
-
33
- if field_name.start_with?("@")
34
- retrieve(name, :derived)
35
- else
36
- retrieve(name, :field)
37
- end
29
+ def [](field)
30
+ field_id = field.is_a?(FieldId) ? field : parse_field_name(field)
31
+ return nil if field_id.nil? || field_id.item.nil?
32
+ retrieve(field_id.item, field_id.derived? ? :derived : :field)
38
33
  end
39
34
 
40
35
  def header(name)
@@ -48,13 +43,16 @@ module Linzer
48
43
  private
49
44
 
50
45
  def parse_field_name(field_name)
51
- if field_name&.start_with?("@")
52
- Starry.parse_item(field_name[1..])
53
- else
54
- Starry.parse_item(field_name)
55
- end
56
- rescue => _
57
- nil
46
+ field_id = FieldId.new(field_name: field_name)
47
+ component = field_id.item
48
+
49
+ return nil if component.nil?
50
+
51
+ # 2.2.9
52
+ invalid = "@status component identifier is invalid in a request message"
53
+ raise Error, invalid if request? && component.value == "@status"
54
+
55
+ field_id
58
56
  end
59
57
 
60
58
  def validate_attached_request(message)
@@ -73,7 +71,7 @@ module Linzer
73
71
  value = name.value
74
72
 
75
73
  # Section 2.2.8 of RFC 9421
76
- return nil if has_name && value != :"query-param"
74
+ return nil if has_name && value != "@query-param"
77
75
 
78
76
  # No derived values come from trailers section
79
77
  return nil if method == :derived && name.parameters["tr"]
@@ -141,10 +139,7 @@ module Linzer
141
139
  end
142
140
 
143
141
  def req(field, method)
144
- case method
145
- when :derived then @attached_request["@#{field}"]
146
- when :field then @attached_request[field.to_s]
147
- end
142
+ attached_request? ? @attached_request[String(field)] : nil
148
143
  end
149
144
  end
150
145
  end
@@ -12,7 +12,7 @@ module Linzer
12
12
  private
13
13
 
14
14
  def derived(name)
15
- return @operation.verb.to_s.upcase if name.value == :method
15
+ return @operation.verb.to_s.upcase if name.value == "@method"
16
16
  super
17
17
  end
18
18
  end
@@ -25,14 +25,14 @@ module Linzer
25
25
 
26
26
  def derived(name)
27
27
  case name.value
28
- when :method then @operation.method
29
- when :"target-uri" then @operation.uri.to_s
30
- when :authority then @operation.uri.authority.downcase
31
- when :scheme then @operation.uri.scheme.downcase
32
- when :"request-target" then @operation.uri.request_uri
33
- when :path then @operation.uri.path
34
- when :query then "?%s" % String(@operation.uri.query)
35
- when :"query-param" then query_param(name)
28
+ when "@method" then @operation.method
29
+ when "@target-uri" then @operation.uri.to_s
30
+ when "@authority" then @operation.uri.authority.downcase
31
+ when "@scheme" then @operation.uri.scheme.downcase
32
+ when "@request-target" then @operation.uri.request_uri
33
+ when "@path" then @operation.uri.path
34
+ when "@query" then "?%s" % String(@operation.uri.query)
35
+ when "@query-param" then query_param(name)
36
36
  end
37
37
  end
38
38
 
@@ -17,16 +17,26 @@ module Linzer
17
17
  @operation[name]
18
18
  end
19
19
 
20
- # XXX: this implementation is incomplete, e.g.: ;tr parameter is not supported yet
21
- def [](field_name)
22
- return @operation.code.to_i if field_name == "@status"
23
- @operation[field_name]
24
- end
25
-
26
20
  def attach!(signature)
27
21
  signature.to_h.each { |h, v| @operation[h] = v }
28
22
  @operation
29
23
  end
24
+
25
+ private
26
+
27
+ def derived(name)
28
+ case name.value
29
+ when "@status" then @operation.code.to_i
30
+ end
31
+ end
32
+
33
+ # XXX: this implementation is incomplete, e.g.: ;bs parameter is not supported yet
34
+ def field(name)
35
+ has_tr = name.parameters["tr"]
36
+ return nil if has_tr # Net::HTTP doesn't support trailers
37
+ value = @operation[name.value.to_s]
38
+ value.dup&.strip
39
+ end
30
40
  end
31
41
  end
32
42
  end
@@ -6,14 +6,14 @@ module Linzer
6
6
  module Rack
7
7
  module Common
8
8
  DERIVED_COMPONENT = {
9
- method: :request_method,
10
- authority: :authority,
11
- path: :path_info,
12
- status: :status,
13
- "target-uri": :url,
14
- scheme: :scheme,
15
- "request-target": :fullpath,
16
- query: :query_string
9
+ "@method" => :request_method,
10
+ "@authority" => :authority,
11
+ "@path" => :path_info,
12
+ "@status" => :status,
13
+ "@target-uri" => :url,
14
+ "@scheme" => :scheme,
15
+ "@request-target" => :fullpath,
16
+ "@query" => :query_string
17
17
  }.freeze
18
18
  private_constant :DERIVED_COMPONENT
19
19
 
@@ -51,8 +51,8 @@ module Linzer
51
51
  method = DERIVED_COMPONENT[name.value]
52
52
 
53
53
  value = case name.value
54
- when :query then derive(@operation, method)
55
- when :"query-param" then query_param(name)
54
+ when "@query" then derive(@operation, method)
55
+ when "@query-param" then query_param(name)
56
56
  end
57
57
 
58
58
  return nil if !method && !value
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Linzer
4
+ class Message
5
+ class Field
6
+ class Identifier
7
+ module Parser
8
+ extend self
9
+
10
+ def parse(field_name)
11
+ case
12
+ when field_name.match?(/";/), field_name.start_with?('"')
13
+ Starry.parse_item(field_name)
14
+ when field_name.match?(/;/)
15
+ parse_unserialized_input(field_name)
16
+ when field_name.start_with?("@"), field_name.match?(/^[a-z]/)
17
+ Starry.parse_item(Starry.serialize(field_name))
18
+ else
19
+ raise Error, "Invalid component identifier: '#{field_name}'!"
20
+ end
21
+ rescue Starry::ParseError => ex
22
+ parse_error = "Failed to parse component identifier: '#{field_name}'!"
23
+ raise Error, parse_error, cause: ex
24
+ end
25
+
26
+ private
27
+
28
+ def parse_unserialized_input(field_name)
29
+ field, *raw_params = field_name.split(";")
30
+ item = Starry.parse_item(Starry.serialize(field))
31
+ item.parameters = collect_parameters(raw_params)
32
+ item
33
+ end
34
+
35
+ def collect_parameters(str)
36
+ params = str.map do |param|
37
+ if (tokens = param.split("=")) == [param] # e.g.: ";bs"
38
+ {param => true}
39
+ else
40
+ Hash[*tokens.first(2)] # e.g.: ";key=\"foo\""
41
+ .transform_values! { |v| Starry.parse_item(v).value }
42
+ end
43
+ end
44
+ params.reduce({}, :merge)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Linzer
4
+ class Message
5
+ class Field
6
+ module IdentifierMethods
7
+ def initialize(field_name:)
8
+ @item = Identifier::Parser.parse(field_name) rescue nil
9
+ super
10
+ end
11
+
12
+ attr_reader :item
13
+
14
+ def derived?
15
+ item&.value&.start_with?("@")
16
+ end
17
+
18
+ def serialize
19
+ raise Error, "Invalid component identifier: '#{field_name}'!" unless item
20
+ Starry.serialize(@item)
21
+ end
22
+ end
23
+
24
+ # Excluded from coverage as obviously both branches cannot be covered
25
+ # on a single test run.
26
+ # :nocov:
27
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.2.0")
28
+ class Identifier < Struct.new(:field_name, keyword_init: true); end
29
+ else
30
+ class Identifier < Data.define(:field_name); end
31
+ end
32
+ # :nocov:
33
+
34
+ Identifier.include Message::Field::IdentifierMethods
35
+
36
+ class Identifier
37
+ class << self
38
+ def serialize(component)
39
+ new(field_name: component).serialize
40
+ end
41
+
42
+ def serialize_components(components)
43
+ components.map(&method(:serialize))
44
+ end
45
+
46
+ def deserialize_components(components)
47
+ components.map do |c|
48
+ item = Starry.parse_item(c)
49
+ item.parameters.empty? ? item.value : Starry.serialize(item)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
data/lib/linzer/rsa.rb CHANGED
@@ -9,14 +9,13 @@ module Linzer
9
9
  end
10
10
 
11
11
  def sign(data)
12
- # XXX: should check if the key is usable for signing
13
- @material.sign(@params[:digest], data)
12
+ validate_signing_key
13
+ material.sign(@params[:digest], data)
14
14
  end
15
15
 
16
16
  def verify(signature, data)
17
- # XXX: should check if the key is usable for verifying
18
- return true if @material.verify(@params[:digest], signature, data)
19
- false
17
+ validate_verify_key
18
+ material.verify(@params[:digest], signature, data)
20
19
  end
21
20
  end
22
21
  end
@@ -11,19 +11,26 @@ module Linzer
11
11
  end
12
12
 
13
13
  def sign(data)
14
- # XXX: should check if the key is usable for signing
15
- @material.sign(@params[:digest], data, signature_options)
14
+ validate_signing_key
15
+ material.sign(@params[:digest], data, signature_options)
16
16
  end
17
17
 
18
18
  def verify(signature, data)
19
- # XXX: should check if the key is usable for verifying
20
- return true if @material.verify(
19
+ validate_verify_key
20
+ material.verify(
21
21
  @params[:digest],
22
22
  signature,
23
23
  data,
24
24
  signature_options
25
25
  )
26
- false
26
+ end
27
+
28
+ def public?
29
+ has_pem_public?
30
+ end
31
+
32
+ def private?
33
+ has_pem_private?
27
34
  end
28
35
 
29
36
  private
@@ -11,9 +11,13 @@ module Linzer
11
11
  end
12
12
 
13
13
  attr_reader :metadata, :value, :parameters, :label
14
- alias_method :components, :metadata
14
+ alias_method :serialized_components, :metadata
15
15
  alias_method :bytes, :value
16
16
 
17
+ def components
18
+ FieldId.deserialize_components(serialized_components)
19
+ end
20
+
17
21
  def created
18
22
  Integer(parameters["created"])
19
23
  rescue
@@ -28,10 +32,13 @@ module Linzer
28
32
 
29
33
  def to_h
30
34
  {
31
- "signature" => Starry.serialize({label => value}),
32
- "signature-input" =>
33
- Starry.serialize({label =>
34
- Starry::InnerList.new(components, parameters)})
35
+ "signature" => Starry.serialize({label => value}),
36
+ "signature-input" => Starry.serialize({
37
+ label => Starry::InnerList.new(
38
+ serialized_components.map { |c| Starry.parse_item(c) },
39
+ parameters
40
+ )
41
+ })
35
42
  }
36
43
  end
37
44
 
@@ -56,7 +63,7 @@ module Linzer
56
63
 
57
64
  fail_due_invalid_components unless input[label].value.respond_to?(:each)
58
65
 
59
- components = input[label].value.map(&:value)
66
+ components = input[label].value.map { |c| Starry.serialize_item(c) }
60
67
  parameters = input[label].parameters
61
68
 
62
69
  new(components, raw_signature, label, parameters)
data/lib/linzer/signer.rb CHANGED
@@ -8,15 +8,16 @@ module Linzer
8
8
  include Common
9
9
 
10
10
  def sign(key, message, components, options = {})
11
- validate key, message, components
11
+ serialized_components = FieldId.serialize_components(Array(components))
12
+ validate key, message, serialized_components
12
13
 
13
14
  parameters = populate_parameters(key, options)
14
- signature_base = signature_base(message, components, parameters)
15
+ signature_base = signature_base(message, serialized_components, parameters)
15
16
 
16
17
  signature = key.sign(signature_base)
17
18
  label = options[:label] || DEFAULT_LABEL
18
19
 
19
- Linzer::Signature.build(serialize(signature, components, parameters, label))
20
+ Linzer::Signature.build(serialize(signature, serialized_components, parameters, label))
20
21
  end
21
22
 
22
23
  def default_label
@@ -55,8 +56,11 @@ module Linzer
55
56
  {
56
57
  "signature" => Starry.serialize({label => signature}),
57
58
  "signature-input" =>
58
- Starry.serialize({label =>
59
- Starry::InnerList.new(components, parameters)})
59
+ Starry.serialize(label =>
60
+ Starry::InnerList.new(
61
+ components.map { |c| Starry.parse_item(c) },
62
+ parameters
63
+ ))
60
64
  }
61
65
  end
62
66
  end
@@ -9,9 +9,9 @@ module Linzer
9
9
  validate message, key, signature, no_older_than: no_older_than
10
10
 
11
11
  parameters = signature.parameters
12
- components = signature.components
12
+ serialized_components = signature.serialized_components
13
13
 
14
- signature_base = signature_base(message, components, parameters)
14
+ signature_base = signature_base(message, serialized_components, parameters)
15
15
 
16
16
  verify_or_fail key, signature.value, signature_base
17
17
  end
@@ -31,7 +31,7 @@ module Linzer
31
31
  raise VerifyError, "Components cannot be null" if signature.components.nil?
32
32
 
33
33
  begin
34
- validate_components message, signature.components
34
+ validate_components message, signature.serialized_components
35
35
  rescue Error => ex
36
36
  raise VerifyError, ex.message, cause: ex
37
37
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Linzer
4
- VERSION = "0.7.3"
4
+ VERSION = "0.7.4"
5
5
  end
data/lib/linzer.rb CHANGED
@@ -14,6 +14,8 @@ require_relative "linzer/options"
14
14
  require_relative "linzer/message"
15
15
  require_relative "linzer/message/adapter"
16
16
  require_relative "linzer/message/wrapper"
17
+ require_relative "linzer/message/field"
18
+ require_relative "linzer/message/field/parser"
17
19
  require_relative "linzer/signature"
18
20
  require_relative "linzer/key"
19
21
  require_relative "linzer/rsa"
@@ -25,7 +27,6 @@ require_relative "linzer/key/helper"
25
27
  require_relative "linzer/signer"
26
28
  require_relative "linzer/verifier"
27
29
  require_relative "linzer/http"
28
- require_relative "rack/auth/signature"
29
30
 
30
31
  module Linzer
31
32
  class Error < StandardError; end
@@ -50,4 +51,8 @@ module Linzer
50
51
  Linzer::Common.signature_base(message, components, parameters)
51
52
  end
52
53
  end
54
+
55
+ FieldId = Message::Field::Identifier
53
56
  end
57
+
58
+ require_relative "rack/auth/signature"
@@ -36,6 +36,11 @@ module Rack
36
36
  end
37
37
 
38
38
  module Configuration
39
+ def default_covered_components
40
+ Linzer::Options::DEFAULT[:covered_components]
41
+ end
42
+ module_function :default_covered_components
43
+
39
44
  DEFAULT_OPTIONS = {
40
45
  signatures: {
41
46
  reject_older_than: 900,
@@ -45,7 +50,9 @@ module Rack
45
50
  tag_required: false,
46
51
  expires_required: false,
47
52
  keyid_required: false,
48
- covered_components: %w[@method @request-target @authority date],
53
+ covered_components:
54
+ Linzer::FieldId
55
+ .serialize_components(default_covered_components),
49
56
  error_response: {body: [], status: 401, headers: {}}
50
57
  },
51
58
  keys: {}
@@ -85,7 +85,7 @@ module Rack
85
85
  end
86
86
 
87
87
  def has_required_components?
88
- components = @signature.components || []
88
+ components = @signature.serialized_components || []
89
89
  covered_components = options[:signatures][:covered_components]
90
90
  warning = "Insufficient coverage by signature. Consult S 7.2.1. in RFC"
91
91
  logger.warn warning if covered_components.empty?
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: linzer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Landaeta
@@ -210,6 +210,8 @@ files:
210
210
  - lib/linzer/message/adapter/rack/common.rb
211
211
  - lib/linzer/message/adapter/rack/request.rb
212
212
  - lib/linzer/message/adapter/rack/response.rb
213
+ - lib/linzer/message/field.rb
214
+ - lib/linzer/message/field/parser.rb
213
215
  - lib/linzer/message/wrapper.rb
214
216
  - lib/linzer/options.rb
215
217
  - lib/linzer/rsa.rb
@@ -241,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
241
243
  - !ruby/object:Gem::Version
242
244
  version: '0'
243
245
  requirements: []
244
- rubygems_version: 3.6.7
246
+ rubygems_version: 3.6.8
245
247
  specification_version: 4
246
248
  summary: An implementation of HTTP Messages Signatures (RFC9421)
247
249
  test_files: []