linzer 0.7.9.beta3 → 0.8.0.beta1

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.
data/lib/linzer/signer.rb CHANGED
@@ -68,16 +68,31 @@ module Linzer
68
68
  # tag: "my-app"
69
69
  # )
70
70
  def sign(key, message, components, options = {})
71
- serialized_components = FieldId.serialize_components(Array(components))
72
- validate key, message, serialized_components
71
+ serialized_components, field_ids =
72
+ FieldId.serialize_components_with_field_ids(Array(components))
73
+ validate key, message, serialized_components, field_ids: field_ids
74
+
75
+ # Reuse the already-parsed items from field_ids
76
+ parsed_items = field_ids.map(&:item)
73
77
 
74
78
  parameters = populate_parameters(key, options)
75
- signature_base = signature_base(message, serialized_components, parameters)
79
+ signature_base = signature_base(message, serialized_components, parameters,
80
+ field_ids: field_ids)
76
81
 
77
- signature = key.sign(signature_base)
82
+ raw_signature = key.sign(signature_base)
78
83
  label = options[:label] || DEFAULT_LABEL
79
84
 
80
- Linzer::Signature.build(serialize(signature, serialized_components, parameters, label))
85
+ # Build the signature directly, bypassing the serialize -> parse round-trip
86
+ headers = serialize(raw_signature, serialized_components, parameters, label)
87
+
88
+ Linzer::Signature.from_components(
89
+ components: serialized_components,
90
+ raw_signature: raw_signature,
91
+ label: label,
92
+ parameters: parameters,
93
+ parsed_items: parsed_items,
94
+ headers: headers
95
+ )
81
96
  end
82
97
 
83
98
  # Returns the default signature label.
@@ -91,19 +106,22 @@ module Linzer
91
106
 
92
107
  # Validates signing inputs.
93
108
  # @raise [SigningError] If any input is invalid
94
- def validate(key, message, components)
109
+ def validate(key, message, components, field_ids: nil)
95
110
  msg = "Message cannot be signed with null %s"
96
111
  raise SigningError, msg % "value" if message.nil?
97
112
  raise SigningError, msg % "key" if key.nil?
98
113
  raise SigningError, msg % "component" if components.nil?
99
114
 
100
115
  begin
101
- validate_components message, components
116
+ validate_components message, components, field_ids: field_ids
102
117
  rescue Error => ex
103
118
  raise SigningError, ex.message, cause: ex
104
119
  end
105
120
  end
106
121
 
122
+ RESERVED_OPTIONS = %i[created keyid label].freeze
123
+ private_constant :RESERVED_OPTIONS
124
+
107
125
  # Builds the signature parameters hash from options and key.
108
126
  # @return [Hash] The populated parameters
109
127
  def populate_parameters(key, options)
@@ -114,22 +132,25 @@ module Linzer
114
132
  key_id = options[:keyid] || (key.key_id if key.respond_to?(:key_id))
115
133
  parameters[:keyid] = key_id unless key_id.nil?
116
134
 
117
- (options.keys - %i[created keyid label]).each { |k| parameters[k] = options[k] }
135
+ options.each { |k, v| parameters[k] = v unless RESERVED_OPTIONS.include?(k) }
118
136
 
119
137
  parameters
120
138
  end
121
139
 
122
140
  # Serializes the signature into HTTP header format.
141
+ #
142
+ # Uses direct string building instead of Starry.serialize to avoid
143
+ # the overhead of generic structured field serialization.
144
+ #
123
145
  # @return [Hash] Hash with "signature" and "signature-input" keys
124
146
  def serialize(signature, components, parameters, label)
147
+ sig_b64 = Base64.strict_encode64(signature)
148
+ input_params = HTTP::StructuredField.serialize_parameters(parameters)
149
+ components_str = components.join(" ")
150
+
125
151
  {
126
- "signature" => Starry.serialize({label => signature}),
127
- "signature-input" =>
128
- Starry.serialize(label =>
129
- Starry::InnerList.new(
130
- components.map { |c| Starry.parse_item(c) },
131
- parameters
132
- ))
152
+ "signature" => "#{label}=:#{sig_b64}:",
153
+ "signature-input" => "#{label}=(#{components_str})#{input_params}"
133
154
  }
134
155
  end
135
156
  end
@@ -59,7 +59,12 @@ module Linzer
59
59
  parameters = signature.parameters
60
60
  serialized_components = signature.serialized_components
61
61
 
62
- signature_base = signature_base(message, serialized_components, parameters)
62
+ # Build fresh field_ids for signature_base (validate already
63
+ # consumed its own set, which may have been mutated by adapters).
64
+ field_ids = signature.field_ids
65
+
66
+ signature_base = signature_base(message, serialized_components, parameters,
67
+ field_ids: field_ids)
63
68
 
64
69
  verify_or_fail key, signature.value, signature_base
65
70
  end
@@ -78,10 +83,11 @@ module Linzer
78
83
  end
79
84
 
80
85
  raise VerifyError, "Signature raw value to cannot be null" if signature.value.nil?
81
- raise VerifyError, "Components cannot be null" if signature.components.nil?
86
+ raise VerifyError, "Components cannot be null" if signature.serialized_components.nil?
82
87
 
83
88
  begin
84
- validate_components message, signature.serialized_components
89
+ validate_components message, signature.serialized_components,
90
+ field_ids: signature.field_ids
85
91
  rescue Error => ex
86
92
  raise VerifyError, ex.message, cause: ex
87
93
  end
@@ -3,5 +3,5 @@
3
3
  module Linzer
4
4
  # Current version of the Linzer gem.
5
5
  # @return [String]
6
- VERSION = "0.7.9.beta3"
6
+ VERSION = "0.8.0.beta1"
7
7
  end
data/lib/linzer.rb CHANGED
@@ -2,9 +2,7 @@
2
2
 
3
3
  require "starry"
4
4
  require "openssl"
5
- require "rack"
6
5
  require "uri"
7
- require "stringio"
8
6
  require "net/http"
9
7
 
10
8
  require_relative "linzer/version"
@@ -27,6 +25,7 @@ require_relative "linzer/key/helper"
27
25
  require_relative "linzer/signer"
28
26
  require_relative "linzer/verifier"
29
27
  require_relative "linzer/http"
28
+ require_relative "linzer/http/structured_field"
30
29
 
31
30
  # Linzer is a Ruby library for HTTP Message Signatures as defined in RFC 9421.
32
31
  #
@@ -158,5 +157,3 @@ module Linzer
158
157
  # Used for serializing and deserializing component identifiers.
159
158
  FieldId = Message::Field::Identifier
160
159
  end
161
-
162
- require_relative "rack/auth/signature"
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.9.beta3
4
+ version: 0.8.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Landaeta
@@ -23,26 +23,6 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: '0.2'
26
- - !ruby/object:Gem::Dependency
27
- name: rack
28
- requirement: !ruby/object:Gem::Requirement
29
- requirements:
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: '2.2'
33
- - - "<"
34
- - !ruby/object:Gem::Version
35
- version: '4.0'
36
- type: :runtime
37
- prerelease: false
38
- version_requirements: !ruby/object:Gem::Requirement
39
- requirements:
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- version: '2.2'
43
- - - "<"
44
- - !ruby/object:Gem::Version
45
- version: '4.0'
46
26
  - !ruby/object:Gem::Dependency
47
27
  name: uri
48
28
  requirement: !ruby/object:Gem::Requirement
@@ -63,46 +43,6 @@ dependencies:
63
43
  - - ">="
64
44
  - !ruby/object:Gem::Version
65
45
  version: 1.0.2
66
- - !ruby/object:Gem::Dependency
67
- name: stringio
68
- requirement: !ruby/object:Gem::Requirement
69
- requirements:
70
- - - "~>"
71
- - !ruby/object:Gem::Version
72
- version: '3.1'
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: 3.1.2
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '3.1'
83
- - - ">="
84
- - !ruby/object:Gem::Version
85
- version: 3.1.2
86
- - !ruby/object:Gem::Dependency
87
- name: logger
88
- requirement: !ruby/object:Gem::Requirement
89
- requirements:
90
- - - "~>"
91
- - !ruby/object:Gem::Version
92
- version: '1.7'
93
- - - ">="
94
- - !ruby/object:Gem::Version
95
- version: 1.7.0
96
- type: :runtime
97
- prerelease: false
98
- version_requirements: !ruby/object:Gem::Requirement
99
- requirements:
100
- - - "~>"
101
- - !ruby/object:Gem::Version
102
- version: '1.7'
103
- - - ">="
104
- - !ruby/object:Gem::Version
105
- version: 1.7.0
106
46
  - !ruby/object:Gem::Dependency
107
47
  name: forwardable
108
48
  requirement: !ruby/object:Gem::Requirement
@@ -176,6 +116,10 @@ files:
176
116
  - LICENSE.txt
177
117
  - README.md
178
118
  - Rakefile
119
+ - benchmarks/profile_sign_ed25519.rb
120
+ - benchmarks/profile_verify_ed25519.rb
121
+ - benchmarks/sign.rb
122
+ - benchmarks/verify.rb
179
123
  - examples/sinatra/Gemfile
180
124
  - examples/sinatra/config.ru
181
125
  - examples/sinatra/http-signatures.yml
@@ -195,6 +139,7 @@ files:
195
139
  - lib/linzer/http.rb
196
140
  - lib/linzer/http/bootstrap.rb
197
141
  - lib/linzer/http/signature_feature.rb
142
+ - lib/linzer/http/structured_field.rb
198
143
  - lib/linzer/jws.rb
199
144
  - lib/linzer/key.rb
200
145
  - lib/linzer/key/helper.rb
@@ -217,6 +162,7 @@ files:
217
162
  - lib/linzer/message/field/parser.rb
218
163
  - lib/linzer/message/wrapper.rb
219
164
  - lib/linzer/options.rb
165
+ - lib/linzer/rack.rb
220
166
  - lib/linzer/rsa.rb
221
167
  - lib/linzer/rsa_pss.rb
222
168
  - lib/linzer/signature.rb