acme-client 0.3.7 → 0.4.0

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
  SHA1:
3
- metadata.gz: caadecc954e9a67dfb321eeb5017112660d24110
4
- data.tar.gz: 7788f6340a7266cfc652583ec1b3f70a8ddb672d
3
+ metadata.gz: 23f849edb70a3c4e33466410c19df3293242ec75
4
+ data.tar.gz: c610d9cabc6d2520b51654f3f140d2d12b8ecabe
5
5
  SHA512:
6
- metadata.gz: bb70e95c5e5acc0faba72c687bc257f03b4ca0411b2ab30d206c79b08ce73974a473c01ca6d48734f6b69eb4bef2efdf314b82b033c36c9465cfbef2a73d1155
7
- data.tar.gz: 971890ea5f70b48d68a29ef5f447d6641e9eab60a51785f6db7c26e52e5dc3f39fd4aa23aa25c8481dd0279a1fb05af9d6f78a44f64775187ec4ab77e5162bf0
6
+ metadata.gz: 4002d98a374002c504d3a6fdf4566b69dcb6eaf7bb298a111562a8911a2ccf3f10ba510795efbf41b03cf51b0a88c51fb900c30b22b914c66fe3c84ef729aff7
7
+ data.tar.gz: 7495152d76edaa3c3248518a14af07b103e8b4d3b5e22ca83ba1ca71aa93c7f6617a7c6925457e0994b1b10ca6c4807bfe3b5253c868bb512a317ab1b19a4e9b
@@ -24,5 +24,4 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency 'webmock', '~> 1.21', '>= 1.21.0'
25
25
 
26
26
  spec.add_runtime_dependency 'faraday', '~> 0.9', '>= 0.9.1'
27
- spec.add_runtime_dependency 'json-jwt', '~> 1.2', '>= 1.2.3'
28
27
  end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'faraday'
2
4
  require 'json'
3
- require 'json/jwt'
4
5
  require 'openssl'
5
6
  require 'digest'
6
7
  require 'forwardable'
8
+ require 'base64'
7
9
 
8
10
  module Acme; end
9
11
  class Acme::Client; end
@@ -6,26 +6,91 @@ class Acme::Client::Crypto
6
6
  end
7
7
 
8
8
  def generate_signed_jws(header:, payload:)
9
- jwt = JSON::JWT.new(payload || {})
10
- jwt.header.merge!(header || {})
11
- jwt.header[:jwk] = jwk
12
- jws = jwt.sign(private_key, :RS256)
13
- jws.to_json(syntax: :flattened)
9
+ header = { typ: 'JWT', alg: jws_alg, jwk: jwk }.merge(header)
10
+
11
+ encoded_header = urlsafe_base64(header.to_json)
12
+ encoded_payload = urlsafe_base64(payload.to_json)
13
+ signature_data = "#{encoded_header}.#{encoded_payload}"
14
+
15
+ signature = private_key.sign digest, signature_data
16
+ encoded_signature = urlsafe_base64(signature)
17
+
18
+ {
19
+ protected: encoded_header,
20
+ payload: encoded_payload,
21
+ signature: encoded_signature
22
+ }.to_json
14
23
  end
15
24
 
16
25
  def thumbprint
17
- jwk.thumbprint
26
+ urlsafe_base64 digest.digest(jwk.to_json)
18
27
  end
19
28
 
20
29
  def digest
21
30
  OpenSSL::Digest::SHA256.new
22
31
  end
23
32
 
33
+ def urlsafe_base64(data)
34
+ Base64.urlsafe_encode64(data).sub(/[\s=]*\z/, '')
35
+ end
36
+
24
37
  private
25
38
 
39
+ def jws_alg
40
+ { 'RSA' => 'RS256', 'EC' => 'ES256' }.fetch(jwk[:kty])
41
+ end
42
+
26
43
  def jwk
27
- @jwk ||= JSON::JWK.new(public_key)
44
+ @jwk ||= case private_key
45
+ when OpenSSL::PKey::RSA
46
+ rsa_jwk
47
+ when OpenSSL::PKey::EC
48
+ ec_jwk
49
+ else
50
+ raise ArgumentError, "Can't handle #{private_key} as private key, only OpenSSL::PKey::RSA and OpenSSL::PKey::EC"
51
+ end
52
+ end
53
+
54
+ def rsa_jwk
55
+ {
56
+ e: urlsafe_base64(public_key.e.to_s(2)),
57
+ kty: 'RSA',
58
+ n: urlsafe_base64(public_key.n.to_s(2))
59
+ }
60
+ end
61
+
62
+ def ec_jwk
63
+ {
64
+ crv: curve_name,
65
+ kty: 'EC',
66
+ x: urlsafe_base64(coordinates[:x].to_s(2)),
67
+ y: urlsafe_base64(coordinates[:y].to_s(2))
68
+ }
69
+ end
70
+
71
+ def curve_name
72
+ {
73
+ 'prime256v1' => 'P-256',
74
+ 'secp384r1' => 'P-384',
75
+ 'secp521r1' => 'P-521'
76
+ }.fetch(private_key.group.curve_name) { raise ArgumentError, 'Unknown EC curve' }
77
+ end
78
+
79
+ # rubocop:disable Metrics/AbcSize
80
+ def coordinates
81
+ @coordinates ||= begin
82
+ hex = public_key.to_bn.to_s(16)
83
+ data_len = hex.length - 2
84
+ hex_x = hex[2, data_len / 2]
85
+ hex_y = hex[2 + data_len / 2, data_len / 2]
86
+
87
+ {
88
+ x: OpenSSL::BN.new([hex_x].pack('H*'), 2),
89
+ y: OpenSSL::BN.new([hex_y].pack('H*'), 2)
90
+ }
91
+ end
28
92
  end
93
+ # rubocop:enable Metrics/AbcSize
29
94
 
30
95
  def public_key
31
96
  @public_key ||= private_key.public_key
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Acme::Client::FaradayMiddleware < Faraday::Middleware
2
4
  attr_reader :env, :response, :client
3
5
 
@@ -50,8 +52,8 @@ class Acme::Client::FaradayMiddleware < Faraday::Middleware
50
52
  end
51
53
 
52
54
  def error_class
53
- if error_name.present? && Acme::Client::Error.const_defined?(error_name)
54
- "Acme::Client::Error::#{error_name}".constantize
55
+ if error_name && !error_name.empty? && Acme::Client::Error.const_defined?(error_name)
56
+ Object.const_get("Acme::Client::Error::#{error_name}")
55
57
  else
56
58
  Acme::Client::Error
57
59
  end
@@ -62,7 +64,7 @@ class Acme::Client::FaradayMiddleware < Faraday::Middleware
62
64
  return unless env.body.is_a?(Hash)
63
65
  return unless env.body.key?('type')
64
66
 
65
- env.body['type'].gsub('urn:acme:error:', '').classify
67
+ env.body['type'].gsub('urn:acme:error:', '').split(/[_-]/).map(&:capitalize).join
66
68
  end
67
69
  end
68
70
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Acme::Client::Resources::Challenges::DNS01 < Acme::Client::Resources::Challenges::Base
2
4
  CHALLENGE_TYPE = 'dns-01'.freeze
3
5
  RECORD_NAME = '_acme-challenge'.freeze
@@ -12,6 +14,6 @@ class Acme::Client::Resources::Challenges::DNS01 < Acme::Client::Resources::Chal
12
14
  end
13
15
 
14
16
  def record_content
15
- Base64.urlsafe_encode64(crypto.digest.digest(authorization_key)).sub(/[\s=]*\z/, '')
17
+ crypto.urlsafe_base64(crypto.digest.digest(authorization_key))
16
18
  end
17
19
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Acme::Client::Resources::Challenges::HTTP01 < Acme::Client::Resources::Challenges::Base
2
4
  CHALLENGE_TYPE = 'http-01'.freeze
3
5
  CONTENT_TYPE = 'text/plain'.freeze
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Acme::Client::Resources::Challenges::TLSSNI01 < Acme::Client::Resources::Challenges::Base
2
4
  CHALLENGE_TYPE = 'tls-sni-01'.freeze
3
5
 
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Acme
2
4
  class Client
3
- VERSION = '0.3.7'.freeze
5
+ VERSION = '0.4.0'.freeze
4
6
  end
5
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acme-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.7
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charles Barbier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-27 00:00:00.000000000 Z
11
+ date: 2016-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -124,26 +124,6 @@ dependencies:
124
124
  - - ">="
125
125
  - !ruby/object:Gem::Version
126
126
  version: 0.9.1
127
- - !ruby/object:Gem::Dependency
128
- name: json-jwt
129
- requirement: !ruby/object:Gem::Requirement
130
- requirements:
131
- - - "~>"
132
- - !ruby/object:Gem::Version
133
- version: '1.2'
134
- - - ">="
135
- - !ruby/object:Gem::Version
136
- version: 1.2.3
137
- type: :runtime
138
- prerelease: false
139
- version_requirements: !ruby/object:Gem::Requirement
140
- requirements:
141
- - - "~>"
142
- - !ruby/object:Gem::Version
143
- version: '1.2'
144
- - - ">="
145
- - !ruby/object:Gem::Version
146
- version: 1.2.3
147
127
  description:
148
128
  email:
149
129
  - unixcharles@gmail.com