acme-client 0.3.7 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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