linzer 0.6.0 → 0.6.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: c09a63a7eae654921b40e0462b463b3e70867522fcedaf42f03373dd72ef55a5
4
- data.tar.gz: b5fea79104954db4289fbf7e4df9f8e589827943cb62eb2836bd0b970611263a
3
+ metadata.gz: db6a27eef77de787dbb8e481a845c44b2df6c284d98adc01d872fc10bb9f6061
4
+ data.tar.gz: c500a2ee97f3b9b9ec7717fc9162c9f26d979301dfdcd8aad50298126e9943a3
5
5
  SHA512:
6
- metadata.gz: 89572382dde42b597eeafecceca1572222cff5d20bba50345b0e3849f47d510cdbcfbc0988295e16b783aa9d28235a95e56b49302a53577e744dc8575253a419
7
- data.tar.gz: bc8c2850994c211b4549dcd07d64ddb14fd54d948a05153d8011042eb4cd2b4adca4d8f80ab983a8c8c71deefc2473994fa479ec8b7ec00063dfa86ead7be7a4
6
+ metadata.gz: 828eabfdd8bb62382eb97b05b9ad7e75a8c8a71bdf082594d73abbf964735bf60fe8e31dcbfcd16e157bf14f369747e71631f54d7b896c7be3a8dfb336a1977f
7
+ data.tar.gz: 65d6be87fe00af2685a7bed82990d3ffa3fd92f4bd5375d00b34cb7d4756e9dca4beee0871c410b62918236cf4fdfd23f0304f5f51294cd855f9774fe104b1d0
data/.standard.yml CHANGED
@@ -7,3 +7,4 @@ ignore:
7
7
  - Layout/ExtraSpacing
8
8
  - Layout/HashAlignment
9
9
  - Layout/ArgumentAlignment
10
+ - Style/EmptyCaseCondition
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.6.2] - 2024-12-10
4
+
5
+ - Remove dependency on ed25519 gem. Pull request
6
+ [#5](https://github.com/nomadium/linzer/pull/5) by
7
+ [oneiros](https://github.com/oneiros).
8
+
9
+ - Run unit tests against Ruby 3.4.
10
+
11
+ ## [0.6.1] - 2024-12-02
12
+
13
+ - Add more validation checks on HTTP field component identifiers and parameters.
14
+
15
+ - Relax rack version requirements. Pull request
16
+ [#4](https://github.com/nomadium/linzer/pull/4) by
17
+ [oneiros](https://github.com/oneiros).
18
+
19
+ - Update uri dependency to the latest version. Pull request
20
+ [#3](https://github.com/nomadium/linzer/pull/3) by
21
+ [oneiros](https://github.com/oneiros).
22
+
3
23
  ## [0.6.0] - 2024-04-06
4
24
 
5
25
  - Support parameters on HTTP field component identifiers.
data/README.md CHANGED
@@ -97,13 +97,10 @@ response = http.post("/some_uri", "data", headers.merge(signature.to_h))
97
97
  ### To verify a valid signature:
98
98
 
99
99
  ```ruby
100
- test_ed25519_key_pub = Base64.strict_encode64(key.material.verify_key.to_bytes)
101
- # => "EUra7KsJ8B/lSZJVhDaopMycmZ6T7KtJqKVNJTHKIw0="
100
+ test_ed25519_key_pub = key.material.public_to_pem
101
+ # => "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAK1ZrC4JqC356pRsUiLVJdFZ3dAjo909VfWs1li33MCQ=\n-----END PUBLIC KEY-----\n"
102
102
 
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")
103
+ pubkey = Linzer.new_ed25519_public_key(test_ed25519_key_pub, "some-key-ed25519")
107
104
  # => #<Linzer::Ed25519::Key:0x00000fe19b9384b0
108
105
 
109
106
  # if you have to, there is a helper method to build a request object on the server side
data/lib/linzer/common.rb CHANGED
@@ -18,10 +18,29 @@ module Linzer
18
18
  if components.include?("@signature-params")
19
19
  raise Error.new "Invalid component in signature input"
20
20
  end
21
+
21
22
  msg = "Cannot verify signature. Missing component in message: %s"
22
- components.each { |c| raise Error.new msg % "\"#{c}\"" unless message.field?(c) }
23
+ components.each do |c|
24
+ raise Error.new msg % "\"#{c}\"" unless message.field?(c)
25
+ end
26
+
27
+ validate_uniqueness components
28
+ end
29
+
30
+ def validate_uniqueness(components)
23
31
  msg = "Invalid signature. Duplicated component in signature input."
24
- raise Error.new msg if components.size != components.uniq.size
32
+
33
+ uniq_components =
34
+ components
35
+ .partition { |c| c.start_with?("@") }
36
+ .flat_map
37
+ .with_index do |group, idx|
38
+ group
39
+ .map { |comp| Starry.parse_item(idx.zero? ? comp[1..] : comp) }
40
+ .uniq { |comp| [comp.value, comp.parameters] }
41
+ end
42
+
43
+ raise Error.new msg if components.count != uniq_components.count
25
44
  end
26
45
  end
27
46
  end
@@ -1,19 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "ed25519"
4
-
5
3
  module Linzer
6
4
  module Ed25519
7
5
  class Key < Linzer::Key
8
6
  def sign(data)
9
- material.sign(data)
7
+ material.sign(nil, data)
10
8
  end
11
9
 
12
10
  def verify(signature, data)
13
- verify_key = material.is_a?(::Ed25519::SigningKey) ? material.verify_key : material
14
- verify_key.verify(signature, data)
15
- rescue ::Ed25519::VerifyError
16
- false
11
+ material.verify(nil, signature, data)
17
12
  end
18
13
  end
19
14
  end
@@ -33,18 +33,17 @@ module Linzer
33
33
  end
34
34
 
35
35
  def generate_ed25519_key(key_id = nil)
36
- material = ::Ed25519::SigningKey.generate
36
+ material = OpenSSL::PKey.generate_key("ed25519")
37
37
  Linzer::Ed25519::Key.new(material, id: key_id)
38
38
  end
39
39
 
40
40
  def new_ed25519_key(material, key_id = nil)
41
- key = ::Ed25519::SigningKey.new(material)
41
+ key = OpenSSL::PKey.read(material)
42
42
  Linzer::Ed25519::Key.new(key, id: key_id)
43
43
  end
44
44
 
45
45
  def new_ed25519_public_key(material, key_id = nil)
46
- key = ::Ed25519::VerifyKey.new(material)
47
- Linzer::Ed25519::Key.new(key, id: key_id)
46
+ new_ed25519_key(material, key_id)
48
47
  end
49
48
 
50
49
  # https://www.rfc-editor.org/rfc/rfc4492.html#appendix-A
@@ -47,7 +47,6 @@ module Linzer
47
47
  return nil if name.nil?
48
48
 
49
49
  if field_name.start_with?("@")
50
- return nil if name.parameters["tr"]
51
50
  retrieve(name, :derived)
52
51
  else
53
52
  retrieve(name, :field)
@@ -79,13 +78,48 @@ module Linzer
79
78
  nil
80
79
  end
81
80
 
81
+ def validate_parameters(name, method)
82
+ has_unknown = name.parameters.any? { |p, _| !KNOWN_PARAMETERS.include?(p) }
83
+ return nil if has_unknown
84
+
85
+ has_name = name.parameters["name"]
86
+ has_req = name.parameters["req"]
87
+ has_sf = name.parameters["sf"] || name.parameters.key?("key")
88
+ has_bs = name.parameters["bs"]
89
+ value = name.value
90
+
91
+ # Section 2.2.8 of RFC 9421
92
+ return nil if has_name && value != :"query-param"
93
+
94
+ # No derived values come from trailers section
95
+ return nil if method == :derived && name.parameters["tr"]
96
+
97
+ # From: 2.1. HTTP Fields:
98
+ # The bs parameter, which requires the raw bytes of the field values
99
+ # from the message, is not compatible with the use of the sf or key
100
+ # parameters, which require the parsed data structures of the field
101
+ # values after combination
102
+ return nil if has_sf && has_bs
103
+
104
+ # req param only makes sense on responses with an associated request
105
+ return nil if has_req && (!response? || !attached_request?)
106
+
107
+ name
108
+ end
109
+
110
+ KNOWN_PARAMETERS = %w[sf key bs req tr name]
111
+ private_constant :KNOWN_PARAMETERS
112
+
82
113
  def retrieve(name, method)
114
+ if !name.parameters.empty?
115
+ valid_params = validate_parameters(name, method)
116
+ return nil if !valid_params
117
+ end
118
+
83
119
  has_req = name.parameters["req"]
84
120
  has_sf = name.parameters["sf"] || name.parameters.key?("key")
85
121
  has_bs = name.parameters["bs"]
86
122
 
87
- return nil if has_req && (!response? || !attached_request?)
88
-
89
123
  if has_req
90
124
  name.parameters.delete("req")
91
125
  return req(name, method)
@@ -93,10 +127,13 @@ module Linzer
93
127
 
94
128
  value = send(method, name)
95
129
 
96
- key = name.parameters["key"]
97
- value = sf(value, key) if has_sf
98
- value = bs(value) if has_bs
99
- value
130
+ case
131
+ when has_sf
132
+ key = name.parameters["key"]
133
+ sf(value, key)
134
+ when has_bs then bs(value)
135
+ else value
136
+ end
100
137
  end
101
138
 
102
139
  def derived(name)
@@ -128,7 +165,8 @@ module Linzer
128
165
  def derive(operation, method)
129
166
  return nil unless operation.respond_to?(method)
130
167
  value = operation.public_send(method)
131
- return "?" + value if method == :query_string
168
+ return "?" + value if method == :query_string
169
+ return value.downcase if %i[authority scheme].include?(method)
132
170
  value
133
171
  end
134
172
 
@@ -144,10 +182,12 @@ module Linzer
144
182
  def sf(value, key = nil)
145
183
  dict = Starry.parse_dictionary(value)
146
184
 
147
- obj = dict[key] if key
148
- return Starry.serialize(obj.is_a?(Starry::InnerList) ? [obj] : obj) if key
149
-
150
- Starry.serialize(dict)
185
+ if key
186
+ obj = dict[key]
187
+ Starry.serialize(obj.is_a?(Starry::InnerList) ? [obj] : obj)
188
+ else
189
+ Starry.serialize(dict)
190
+ end
151
191
  end
152
192
 
153
193
  def bs(value)
@@ -11,7 +11,8 @@ module Linzer
11
11
  request_method = Rack.const_get(verb.upcase)
12
12
  args = {
13
13
  "REQUEST_METHOD" => request_method,
14
- "PATH_INFO" => uri.to_str
14
+ "PATH_INFO" => uri.to_str,
15
+ "rack.input" => StringIO.new
15
16
  }
16
17
 
17
18
  Rack::Request.new(build_rack_env(headers).merge(args))
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Linzer
4
- VERSION = "0.6.0"
5
-
6
- def self.ruby_dev?
7
- RUBY_ENGINE == "ruby" && RUBY_PATCHLEVEL == -1 && /\Aruby 3.[0-9].0dev/ =~ RUBY_DESCRIPTION
8
- end
4
+ VERSION = "0.6.2"
9
5
  end
data/lib/linzer.rb CHANGED
@@ -4,6 +4,7 @@ require "starry"
4
4
  require "openssl"
5
5
  require "rack"
6
6
  require "uri"
7
+ require "stringio"
7
8
 
8
9
  require_relative "linzer/version"
9
10
  require_relative "linzer/common"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: linzer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.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-04-06 00:00:00.000000000 Z
11
+ date: 2024-12-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: openssl
@@ -31,73 +31,79 @@ dependencies:
31
31
  - !ruby/object:Gem::Version
32
32
  version: 3.0.0
33
33
  - !ruby/object:Gem::Dependency
34
- name: ed25519
34
+ name: starry
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '1.3'
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- version: 1.3.0
39
+ version: '0.2'
43
40
  type: :runtime
44
41
  prerelease: false
45
42
  version_requirements: !ruby/object:Gem::Requirement
46
43
  requirements:
47
44
  - - "~>"
48
45
  - !ruby/object:Gem::Version
49
- version: '1.3'
50
- - - ">="
51
- - !ruby/object:Gem::Version
52
- version: 1.3.0
46
+ version: '0.2'
53
47
  - !ruby/object:Gem::Dependency
54
- name: starry
48
+ name: rack
55
49
  requirement: !ruby/object:Gem::Requirement
56
50
  requirements:
57
- - - "~>"
51
+ - - ">="
58
52
  - !ruby/object:Gem::Version
59
- version: '0.1'
53
+ version: '2.2'
54
+ - - "<"
55
+ - !ruby/object:Gem::Version
56
+ version: '4.0'
60
57
  type: :runtime
61
58
  prerelease: false
62
59
  version_requirements: !ruby/object:Gem::Requirement
63
60
  requirements:
64
- - - "~>"
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '2.2'
64
+ - - "<"
65
65
  - !ruby/object:Gem::Version
66
- version: '0.1'
66
+ version: '4.0'
67
67
  - !ruby/object:Gem::Dependency
68
- name: rack
68
+ name: uri
69
69
  requirement: !ruby/object:Gem::Requirement
70
70
  requirements:
71
71
  - - "~>"
72
72
  - !ruby/object:Gem::Version
73
- version: '3.0'
73
+ version: '1.0'
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: 1.0.2
74
77
  type: :runtime
75
78
  prerelease: false
76
79
  version_requirements: !ruby/object:Gem::Requirement
77
80
  requirements:
78
81
  - - "~>"
79
82
  - !ruby/object:Gem::Version
80
- version: '3.0'
83
+ version: '1.0'
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: 1.0.2
81
87
  - !ruby/object:Gem::Dependency
82
- name: uri
88
+ name: stringio
83
89
  requirement: !ruby/object:Gem::Requirement
84
90
  requirements:
85
91
  - - "~>"
86
92
  - !ruby/object:Gem::Version
87
- version: '0.12'
93
+ version: '3.1'
88
94
  - - ">="
89
95
  - !ruby/object:Gem::Version
90
- version: 0.12.0
96
+ version: 3.1.2
91
97
  type: :runtime
92
98
  prerelease: false
93
99
  version_requirements: !ruby/object:Gem::Requirement
94
100
  requirements:
95
101
  - - "~>"
96
102
  - !ruby/object:Gem::Version
97
- version: '0.12'
103
+ version: '3.1'
98
104
  - - ">="
99
105
  - !ruby/object:Gem::Version
100
- version: 0.12.0
106
+ version: 3.1.2
101
107
  description:
102
108
  email:
103
109
  - miguel@miguel.cc
@@ -127,7 +133,6 @@ files:
127
133
  - lib/linzer/signer.rb
128
134
  - lib/linzer/verifier.rb
129
135
  - lib/linzer/version.rb
130
- - linzer.gemspec
131
136
  homepage: https://github.com/nomadium/linzer
132
137
  licenses:
133
138
  - MIT
data/linzer.gemspec DELETED
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "lib/linzer/version"
4
-
5
- Gem::Specification.new do |spec|
6
- spec.name = "linzer"
7
- spec.version = Linzer::VERSION
8
- spec.authors = ["Miguel Landaeta"]
9
- spec.email = %w[miguel@miguel.cc]
10
-
11
- spec.summary = "An implementation of HTTP Messages Signatures (RFC9421)"
12
- spec.homepage = "https://github.com/nomadium/linzer"
13
- spec.license = "MIT"
14
- spec.required_ruby_version = ">= 2.6.0"
15
-
16
- spec.metadata["homepage_uri"] = spec.homepage
17
- spec.metadata["source_code_uri"] = spec.homepage
18
- spec.metadata["changelog_uri"] = spec.homepage + "/blob/master/CHANGELOG.md"
19
-
20
- # Specify which files should be added to the gem when it is released.
21
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
- spec.files = Dir.chdir(__dir__) do
23
- `git ls-files -z`.split("\x0").reject do |f|
24
- (File.expand_path(f) == __FILE__) ||
25
- f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
26
- end
27
- end
28
- spec.bindir = "exe"
29
- spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
- spec.require_paths = ["lib"]
31
-
32
- spec.add_runtime_dependency "openssl", "~> 3.0", ">= 3.0.0"
33
- spec.add_runtime_dependency "ed25519", "~> 1.3", ">= 1.3.0"
34
- spec.add_runtime_dependency "starry", "~> 0.1" unless Linzer.ruby_dev?
35
- spec.add_runtime_dependency "rack", "~> 3.0"
36
- spec.add_runtime_dependency "uri", "~> 0.12", ">= 0.12.0"
37
- end