linzer 0.7.9 → 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/key.rb CHANGED
@@ -38,6 +38,8 @@ module Linzer
38
38
  @material = material
39
39
  @params = Hash(params).clone.freeze
40
40
  validate
41
+ @is_private = compute_private?
42
+ @is_public = compute_public?
41
43
  freeze
42
44
  end
43
45
 
@@ -84,14 +86,14 @@ module Linzer
84
86
  #
85
87
  # @return [Boolean] true if the key contains public key material
86
88
  def public?
87
- material.public?
89
+ @is_public
88
90
  end
89
91
 
90
92
  # Checks if this key can be used for signing.
91
93
  #
92
94
  # @return [Boolean] true if the key contains private key material
93
95
  def private?
94
- material.private?
96
+ @is_private
95
97
  end
96
98
 
97
99
  private
@@ -102,6 +104,22 @@ module Linzer
102
104
  !material.nil? or raise Error.new "Invalid key. No key material provided."
103
105
  end
104
106
 
107
+ # Computes whether the key contains private key material.
108
+ # Override in subclasses where the OpenSSL key object does not
109
+ # respond to +private?+ (e.g. Ed25519, RSA-PSS).
110
+ # @return [Boolean]
111
+ def compute_private?
112
+ material.respond_to?(:private?) ? material.private? : false
113
+ end
114
+
115
+ # Computes whether the key contains public key material.
116
+ # Override in subclasses where the OpenSSL key object does not
117
+ # respond to +public?+ (e.g. Ed25519, RSA-PSS).
118
+ # @return [Boolean]
119
+ def compute_public?
120
+ material.respond_to?(:public?) ? material.public? : false
121
+ end
122
+
105
123
  # Validates that a digest algorithm is configured.
106
124
  # @raise [Error] If no digest algorithm is set
107
125
  def validate_digest
@@ -70,7 +70,7 @@ module Linzer
70
70
  # @example With structured field parameter
71
71
  # adapter['"example-dict";key="a"'] # => "1"
72
72
  def [](field)
73
- field_id = field.is_a?(FieldId) ? field : parse_field_name(field)
73
+ field_id = (field.is_a?(FieldId) || field.is_a?(Field::FastIdentifier)) ? field : parse_field_name(field)
74
74
  return nil if field_id.nil? || field_id.item.nil?
75
75
  retrieve(field_id.item, field_id.derived? ? :derived : :field)
76
76
  end
@@ -190,10 +190,11 @@ module Linzer
190
190
  # @param method [Symbol] +:derived+ or +:field+
191
191
  # @return [String, Integer, nil] the component value
192
192
  def retrieve(name, method)
193
- if !name.parameters.empty?
194
- valid_params = validate_parameters(name, method)
195
- return nil if !valid_params
196
- end
193
+ # Fast path: no parameters means no special handling needed
194
+ return send(method, name) if name.parameters.empty?
195
+
196
+ valid_params = validate_parameters(name, method)
197
+ return nil if !valid_params
197
198
 
198
199
  has_req = name.parameters["req"]
199
200
  has_sf = name.parameters["sf"] || name.parameters.key?("key")
@@ -3,9 +3,6 @@
3
3
  require_relative "adapter/abstract"
4
4
  require_relative "adapter/generic/request"
5
5
  require_relative "adapter/generic/response"
6
- require_relative "adapter/rack/common"
7
- require_relative "adapter/rack/request"
8
- require_relative "adapter/rack/response"
9
6
  require_relative "adapter/net_http/request"
10
7
  require_relative "adapter/net_http/response"
11
8
 
@@ -34,7 +34,7 @@ module Linzer
34
34
  # @raise [Error] If the component identifier is invalid
35
35
  def serialize
36
36
  raise Error, "Invalid component identifier: '#{field_name}'!" unless item
37
- Starry.serialize(@item)
37
+ @serialized || Starry.serialize(@item)
38
38
  end
39
39
  end
40
40
 
@@ -54,6 +54,29 @@ module Linzer
54
54
 
55
55
  Identifier.include Message::Field::IdentifierMethods
56
56
 
57
+ # Lightweight FieldId for simple components (no parameters).
58
+ # Bypasses Starry parsing entirely. Duck-types with Identifier
59
+ # for use in the adapter's [] method.
60
+ # @api private
61
+ class FastIdentifier
62
+ def initialize(serialized, item)
63
+ @field_name = serialized
64
+ @item = item
65
+ @serialized = serialized
66
+ freeze
67
+ end
68
+
69
+ attr_reader :field_name, :item
70
+
71
+ def derived?
72
+ @item.value.start_with?("@")
73
+ end
74
+
75
+ def serialize
76
+ @serialized
77
+ end
78
+ end
79
+
57
80
  class Identifier
58
81
  class << self
59
82
  # Serializes a single component identifier.
@@ -70,6 +93,35 @@ module Linzer
70
93
  components.map(&method(:serialize))
71
94
  end
72
95
 
96
+ # Serializes an array of component identifiers, returning both
97
+ # the serialized strings and the FieldId objects for reuse.
98
+ # @param components [Array<String>] Component names
99
+ # @return [Array(Array<String>, Array<Identifier>)] Serialized strings and FieldId objects
100
+ def serialize_components_with_field_ids(components)
101
+ serialized = Array.new(components.size)
102
+ field_ids = Array.new(components.size)
103
+
104
+ components.each_with_index do |c, i|
105
+ if c.include?(";") || c.include?('"')
106
+ # Complex component with parameters or already serialized:
107
+ # fall back to full Starry parsing
108
+ fid = new(field_name: c)
109
+ field_ids[i] = fid
110
+ serialized[i] = fid.serialize
111
+ else
112
+ # Simple component (e.g. "@method", "content-type"):
113
+ # build the Item and serialized string directly,
114
+ # bypassing Starry.parse_item + Starry.serialize
115
+ quoted = "\"#{c}\""
116
+ item = Starry::Item.new(c, {})
117
+ field_ids[i] = FastIdentifier.new(quoted, item)
118
+ serialized[i] = quoted
119
+ end
120
+ end
121
+
122
+ [serialized, field_ids]
123
+ end
124
+
73
125
  # Deserializes component identifiers back to names.
74
126
  # @param components [Array<String>] Serialized identifiers
75
127
  # @return [Array<String>] Component names
@@ -12,8 +12,6 @@ module Linzer
12
12
  module Wrapper
13
13
  # Default adapter mappings for built-in HTTP library support.
14
14
  @adapters = {
15
- Rack::Request => Linzer::Message::Adapter::Rack::Request,
16
- Rack::Response => Linzer::Message::Adapter::Rack::Response,
17
15
  Net::HTTPRequest => Linzer::Message::Adapter::NetHTTP::Request,
18
16
  Net::HTTPResponse => Linzer::Message::Adapter::NetHTTP::Response
19
17
  }
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Rack integration for Linzer.
4
+ #
5
+ # Require this file to enable Rack support. It loads the Rack adapter
6
+ # classes and registers them so that {Rack::Request} and {Rack::Response}
7
+ # objects can be used directly with the Linzer signing and verification API.
8
+ #
9
+ # @example
10
+ # require "linzer/rack"
11
+ #
12
+ # use Rack::Auth::Signature,
13
+ # except: "/login",
14
+ # default: :my_key
15
+
16
+ require "rack"
17
+ require "linzer"
18
+ require "rack/auth/signature"
19
+ require "linzer/message/adapter/rack/common"
20
+ require "linzer/message/adapter/rack/request"
21
+ require "linzer/message/adapter/rack/response"
22
+
23
+ Linzer::Message.register_adapter(Rack::Request, Linzer::Message::Adapter::Rack::Request)
24
+ Linzer::Message.register_adapter(Rack::Response, Linzer::Message::Adapter::Rack::Response)
@@ -65,18 +65,18 @@ module Linzer
65
65
  )
66
66
  end
67
67
 
68
+ private
69
+
68
70
  # @return [Boolean] true if this key contains public key material
69
- def public?
71
+ def compute_public?
70
72
  has_pem_public?
71
73
  end
72
74
 
73
75
  # @return [Boolean] true if this key contains private key material
74
- def private?
76
+ def compute_private?
75
77
  has_pem_private?
76
78
  end
77
79
 
78
- private
79
-
80
80
  # Returns OpenSSL options for PSS signature operations.
81
81
  # @return [Hash] OpenSSL signature options
82
82
  def signature_options
@@ -26,12 +26,14 @@ module Linzer
26
26
  # @see https://www.rfc-editor.org/rfc/rfc9421.html#section-4 RFC 9421 Section 4
27
27
  class Signature
28
28
  # @api private
29
- # Use {.build} to create Signature instances.
30
- def initialize(metadata, value, label, parameters = {})
31
- @metadata = metadata.clone.freeze
32
- @value = value.clone.freeze
33
- @parameters = parameters.clone.freeze
34
- @label = label.clone.freeze
29
+ # Use {.build} or {.from_components} to create Signature instances.
30
+ def initialize(metadata, value, label, parameters = {}, parsed_items: nil, headers: nil)
31
+ @metadata = metadata.clone.freeze
32
+ @value = value.clone.freeze
33
+ @parameters = parameters.clone.freeze
34
+ @label = label.clone.freeze
35
+ @parsed_items = parsed_items&.freeze
36
+ @headers = headers&.freeze
35
37
  freeze
36
38
  end
37
39
 
@@ -74,6 +76,20 @@ module Linzer
74
76
  FieldId.deserialize_components(serialized_components)
75
77
  end
76
78
 
79
+ # Builds FieldId objects for each covered component.
80
+ #
81
+ # Uses {parsed_items} when available to create {FastIdentifier} objects
82
+ # that bypass Starry re-parsing. Falls back to constructing full
83
+ # {FieldId} objects from the serialized strings.
84
+ #
85
+ # Returns a fresh array each time because some adapter methods may
86
+ # mutate item parameters during field lookup (e.g., deleting "req").
87
+ #
88
+ # @return [Array<FastIdentifier, FieldId>] FieldId objects for each component
89
+ def field_ids
90
+ build_field_ids
91
+ end
92
+
77
93
  # Returns the signature creation timestamp.
78
94
  #
79
95
  # @return [Integer, nil] Unix timestamp when the signature was created,
@@ -132,20 +148,60 @@ module Linzer
132
148
  # @example Attaching to a Net::HTTP request
133
149
  # signature.to_h.each { |name, value| request[name] = value }
134
150
  def to_h
151
+ return @headers if @headers
152
+
153
+ items = @parsed_items || serialized_components.map { |c| Starry.parse_item(c) }
135
154
  {
136
155
  "signature" => Starry.serialize({label => value}),
137
156
  "signature-input" => Starry.serialize({
138
- label => Starry::InnerList.new(
139
- serialized_components.map { |c| Starry.parse_item(c) },
140
- parameters
141
- )
157
+ label => Starry::InnerList.new(items, parameters)
142
158
  })
143
159
  }
144
160
  end
145
161
 
162
+ private
163
+
164
+ def build_field_ids
165
+ if @parsed_items && @parsed_items.size == @metadata.size
166
+ @metadata.each_with_index.map do |serialized, i|
167
+ item = @parsed_items[i]
168
+ # Clone items that have parameters since the adapter's retrieve
169
+ # method may mutate parameters (e.g., deleting "req").
170
+ unless item.parameters.empty?
171
+ item = Starry::Item.new(item.value, item.parameters.dup)
172
+ end
173
+ Message::Field::FastIdentifier.new(serialized, item)
174
+ end
175
+ else
176
+ @metadata.map { |c| FieldId.new(field_name: c) }
177
+ end
178
+ end
179
+
146
180
  class << self
147
181
  private :new
148
182
 
183
+ # Creates a Signature directly from its constituent parts.
184
+ #
185
+ # This avoids the serialize-then-parse round-trip when the caller
186
+ # (e.g. {Signer.sign}) already has all the data.
187
+ #
188
+ # @api private
189
+ # @param components [Array<String>] Serialized component identifiers
190
+ # @param raw_signature [String] The raw signature bytes
191
+ # @param label [String] The signature label
192
+ # @param parameters [Hash] Signature parameters (symbol keys)
193
+ # @param parsed_items [Array<Starry::Item>] Pre-parsed component items
194
+ # @param headers [Hash] Pre-serialized header strings
195
+ # @return [Signature] The constructed signature
196
+ def from_components(components:, raw_signature:, label:, parameters:, parsed_items:, headers:)
197
+ # Signature stores parameters with string keys (as produced by Starry
198
+ # parsing). Convert symbol keys from Signer to match.
199
+ string_params = {}
200
+ parameters.each { |k, v| string_params[k.to_s] = v }
201
+ new(components, raw_signature, label, string_params,
202
+ parsed_items: parsed_items, headers: headers)
203
+ end
204
+
149
205
  # Builds a Signature from HTTP headers.
150
206
  #
151
207
  # Parses the `signature` and `signature-input` headers according to
@@ -184,19 +240,15 @@ module Linzer
184
240
  reject_multiple_signatures if input.size > 1 && options[:label].nil?
185
241
  label = options[:label] || input.keys.first
186
242
 
187
- signature = parse_structured_field(headers, "signature")
188
- fail_with_signature_not_found label unless signature.key?(label)
189
-
190
- raw_signature =
191
- signature[label].value
192
- .force_encoding(Encoding::ASCII_8BIT)
243
+ raw_signature = extract_raw_signature(headers["signature"], label)
193
244
 
194
245
  fail_due_invalid_components unless input[label].value.respond_to?(:each)
195
246
 
196
- components = input[label].value.map { |c| Starry.serialize_item(c) }
247
+ parsed_items = input[label].value
248
+ components = serialize_parsed_items(parsed_items)
197
249
  parameters = input[label].parameters
198
250
 
199
- new(components, raw_signature, label, parameters)
251
+ new(components, raw_signature, label, parameters, parsed_items: parsed_items)
200
252
  end
201
253
 
202
254
  private
@@ -223,6 +275,79 @@ module Linzer
223
275
  raise Error.new "Unexpected value for covered components."
224
276
  end
225
277
 
278
+ # Extracts the raw signature bytes for a given label from the
279
+ # signature header without a full Starry dictionary parse.
280
+ #
281
+ # The signature header format is: label=:base64data:
282
+ # For multiple signatures: label1=:b64:, label2=:b64:
283
+ #
284
+ # Falls back to full Starry parsing for non-trivial cases.
285
+ #
286
+ # @param header_value [String] the raw signature header
287
+ # @param label [String] the signature label to extract
288
+ # @return [String] the decoded signature bytes (ASCII-8BIT)
289
+ # @raise [Error] if the label is not found or decoding fails
290
+ def extract_raw_signature(header_value, label)
291
+ value = header_value.is_a?(String) ? header_value : header_value.to_s
292
+ prefix = "#{label}=:"
293
+
294
+ # Fast path: single signature (most common case)
295
+ if value.start_with?(prefix)
296
+ end_idx = value.index(":", prefix.length)
297
+ if end_idx
298
+ encoded = value[prefix.length...end_idx]
299
+ return Base64.strict_decode64(encoded)
300
+ .force_encoding(Encoding::ASCII_8BIT)
301
+ end
302
+ end
303
+
304
+ # Multi-signature or unusual format: find the right entry
305
+ # Split on comma-separated dictionary members
306
+ value.split(",").each do |entry|
307
+ entry = entry.strip
308
+ if entry.start_with?(prefix)
309
+ end_idx = entry.index(":", prefix.length)
310
+ if end_idx
311
+ encoded = entry[prefix.length...end_idx]
312
+ return Base64.strict_decode64(encoded)
313
+ .force_encoding(Encoding::ASCII_8BIT)
314
+ end
315
+ end
316
+ end
317
+
318
+ # Label not found via fast path — fall back to Starry
319
+ signature = parse_structured_dictionary(
320
+ value.encode(Encoding::US_ASCII), "signature"
321
+ )
322
+ fail_with_signature_not_found label unless signature.key?(label)
323
+ signature[label].value.force_encoding(Encoding::ASCII_8BIT)
324
+ rescue ArgumentError
325
+ # Base64 decode failed — fall back to Starry
326
+ signature = parse_structured_dictionary(
327
+ value.encode(Encoding::US_ASCII), "signature"
328
+ )
329
+ fail_with_signature_not_found label unless signature.key?(label)
330
+ signature[label].value.force_encoding(Encoding::ASCII_8BIT)
331
+ end
332
+
333
+ # Serializes parsed Starry items to their string representations
334
+ # without going through the generic Starry.serialize_item path.
335
+ #
336
+ # For simple items (no parameters): builds '"value"' directly.
337
+ # For items with parameters: falls back to Starry.serialize_item.
338
+ #
339
+ # @param items [Array<Starry::Item>] parsed items from signature-input
340
+ # @return [Array<String>] serialized component identifiers
341
+ def serialize_parsed_items(items)
342
+ items.map do |item|
343
+ if item.parameters.empty?
344
+ "\"#{item.value}\""
345
+ else
346
+ Starry.serialize_item(item)
347
+ end
348
+ end
349
+ end
350
+
226
351
  def parse_structured_dictionary(str, field_name = nil)
227
352
  Starry.parse_dictionary(str)
228
353
  rescue Starry::ParseError => _
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"
6
+ VERSION = "0.8.0.beta1"
7
7
  end
data/lib/linzer.rb CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "starry"
4
4
  require "openssl"
5
- require "rack"
6
5
  require "uri"
7
6
  require "net/http"
8
7
 
@@ -26,6 +25,7 @@ require_relative "linzer/key/helper"
26
25
  require_relative "linzer/signer"
27
26
  require_relative "linzer/verifier"
28
27
  require_relative "linzer/http"
28
+ require_relative "linzer/http/structured_field"
29
29
 
30
30
  # Linzer is a Ruby library for HTTP Message Signatures as defined in RFC 9421.
31
31
  #
@@ -157,5 +157,3 @@ module Linzer
157
157
  # Used for serializing and deserializing component identifiers.
158
158
  FieldId = Message::Field::Identifier
159
159
  end
160
-
161
- 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
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,26 +43,6 @@ dependencies:
63
43
  - - ">="
64
44
  - !ruby/object:Gem::Version
65
45
  version: 1.0.2
66
- - !ruby/object:Gem::Dependency
67
- name: logger
68
- requirement: !ruby/object:Gem::Requirement
69
- requirements:
70
- - - "~>"
71
- - !ruby/object:Gem::Version
72
- version: '1.7'
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: 1.7.0
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '1.7'
83
- - - ">="
84
- - !ruby/object:Gem::Version
85
- version: 1.7.0
86
46
  - !ruby/object:Gem::Dependency
87
47
  name: forwardable
88
48
  requirement: !ruby/object:Gem::Requirement
@@ -156,6 +116,10 @@ files:
156
116
  - LICENSE.txt
157
117
  - README.md
158
118
  - Rakefile
119
+ - benchmarks/profile_sign_ed25519.rb
120
+ - benchmarks/profile_verify_ed25519.rb
121
+ - benchmarks/sign.rb
122
+ - benchmarks/verify.rb
159
123
  - examples/sinatra/Gemfile
160
124
  - examples/sinatra/config.ru
161
125
  - examples/sinatra/http-signatures.yml
@@ -175,6 +139,7 @@ files:
175
139
  - lib/linzer/http.rb
176
140
  - lib/linzer/http/bootstrap.rb
177
141
  - lib/linzer/http/signature_feature.rb
142
+ - lib/linzer/http/structured_field.rb
178
143
  - lib/linzer/jws.rb
179
144
  - lib/linzer/key.rb
180
145
  - lib/linzer/key/helper.rb
@@ -197,6 +162,7 @@ files:
197
162
  - lib/linzer/message/field/parser.rb
198
163
  - lib/linzer/message/wrapper.rb
199
164
  - lib/linzer/options.rb
165
+ - lib/linzer/rack.rb
200
166
  - lib/linzer/rsa.rb
201
167
  - lib/linzer/rsa_pss.rb
202
168
  - lib/linzer/signature.rb