letscert 0.2.2 → 0.2.3

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: 7794f56c134e1437cbb2d89cf9bcf3b2da6f5bc1
4
- data.tar.gz: 735bb555113c95eb110500c3fcd43b435c7e41aa
3
+ metadata.gz: 13246f0cc94eb264f9dcc01fb55a2e55250d5e63
4
+ data.tar.gz: d543f27b0a2d55a1e0fc17950bb662bbfbb3a932
5
5
  SHA512:
6
- metadata.gz: 8d1369f91acfe830d02461a442eeac66d14995944996dac69c1d6120c42077566701eb0aca6bdc34ec9a0a17e82d2765a315086ba5ad0d97b7c58772701e0102
7
- data.tar.gz: 5cc07fe0b35bab4b652ac29a1807ae39b62cae562fcbb73dd8fc9320f2bbef3be338471094baca01bdc41c9309fb6c8b375080b01013c91538467ecaddbae05b
6
+ metadata.gz: ebbdc254cd7cfea90f1b23308673a839baeaa564450dc18fa5340ed30a8fa5e93e84180fdbe66360f70db449671bd276352c3a2081a5aa8b76b58604f341df7e
7
+ data.tar.gz: 4ae2cdc6a2fa18eb7e9606c909e6260cee6878000ab5c601ce0482352e15333e8bd048a8b33d2614459d0c9ba36dc7c72d753936e21489a584fafb9894457720
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Gem Version](https://badge.fury.io/rb/letscert.svg)](https://badge.fury.io/rb/letscert)
2
+
1
3
  # letscert
2
4
  A simple `Let's Encrypt` client in ruby.
3
5
 
@@ -7,12 +9,17 @@ in Ruby.
7
9
 
8
10
  # Usage
9
11
 
10
- Generate a key pair and get signed certificate
12
+ Generate a key pair and get signed certificate:
13
+ ```bash
14
+ letscert -d example.com:/var/www/example.com/html -f account_key.json -f key.pem -f cert.pem -f fullchain.pem
15
+ ```
16
+
17
+ Generate a key pair and get a signed certificate for multi-domains:
11
18
  ```bash
12
- letscert -d example.com:/var/www/example.com/html -f key.pem -f cert.pem -f fullchain.pem
19
+ letscert -d example.com -d www.example.com --default_root /var/www/html -f account_key.json -f key.pem -f cert.pem -f fullchain.pem
13
20
  ```
14
21
 
15
- The command is the same for certificate renewal.
22
+ Commands are the sames for certificate renewal.
16
23
 
17
24
  # What `letscert` do
18
25
 
@@ -30,4 +37,4 @@ The command is the same for certificate renewal.
30
37
  * 2 in case of errors.
31
38
 
32
39
  # Todo
33
- Add support to revocation.
40
+ Add support to revocation.
@@ -54,15 +54,17 @@ module LetsCert
54
54
  key = data[:key]
55
55
  else
56
56
  logger.info { 'Generate new private key' }
57
- key = OpenSSL::PKey::RSA.generate(@options[:cert_key_size])
57
+ key = OpenSSL::PKey::RSA.generate(options[:cert_key_size])
58
58
  end
59
59
 
60
- csr = Acme::Client::CertificateRequest.new(names: roots.keys, private_key: key)
60
+ csr = Acme::Client::CertificateRequest.new(names: roots.keys,
61
+ private_key: key)
61
62
  cert = client.new_certificate(csr)
62
63
 
63
- IOPlugin.registered.each do |name, plugin|
64
- plugin.save( account_key: client.private_key, key: key, cert: cert.x509,
65
- chain: cert.x509_chain)
64
+ options[:files].each do |plugname|
65
+ IOPlugin.registered[plugname].save(account_key: client.private_key,
66
+ key: key, cert: cert.x509,
67
+ chain: cert.x509_chain)
66
68
  end
67
69
  end
68
70
 
@@ -19,8 +19,7 @@
19
19
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
- require 'json'
23
- require 'base64'
22
+ require 'json/jwt'
24
23
  require_relative 'loggable'
25
24
 
26
25
  module LetsCert
@@ -145,43 +144,14 @@ module LetsCert
145
144
  def load_jwk(data)
146
145
  return nil if data.empty?
147
146
 
148
- hsh = JSON.parse(data)
149
-
150
- key = OpenSSL::PKey::RSA.new
151
- key.n = OpenSSL::BN.new(Base64.strict_decode64(hsh['n']))
152
- key.e = OpenSSL::BN.new(Base64.strict_decode64(hsh['e']))
153
- key.d = OpenSSL::BN.new(Base64.strict_decode64(hsh['e']))
154
- key.p = OpenSSL::BN.new(Base64.strict_decode64(hsh['p']))
155
- key.q = OpenSSL::BN.new(Base64.strict_decode64(hsh['q']))
156
- key.dmp1 = OpenSSL::BN.new(Base64.strict_decode64(hsh['dp']))
157
- key.dmq1 = OpenSSL::BN.new(Base64.strict_decode64(hsh['dq']))
158
- key.iqmp = OpenSSL::BN.new(Base64.strict_decode64(hsh['qi']))
159
-
160
- key
147
+ JSON::JWK.new(JSON.parse(data)).to_key
161
148
  end
162
149
 
163
150
  # Dump crypto data (key) to a JSON-encoded string
164
- # @param [OpenSSL::PKey] jwk
151
+ # @param [OpenSSL::PKey] key
165
152
  # @return [String]
166
- def dump_jwk(jwk)
167
- hsh = jwk.params
168
-
169
- # Add and rename some fields to be compatible with simp_le
170
- hsh['kty'] = 'RSA'
171
- hsh['qi'] = hsh['iqmp'].dup
172
- hsh['dp'] = hsh['dmp1'].dup
173
- hsh['dq'] = hsh['dmq1'].dup
174
- hsh.delete('iqmp')
175
- hsh.delete('dmpl')
176
- hsh.delete('dmql')
177
- hsh.rehash
178
-
179
- hsh.each_key do |key|
180
- if hsh[key].is_a?(OpenSSL::BN)
181
- hsh[key] = Base64.strict_encode64(hsh[key].to_s)
182
- end
183
- end
184
- hsh.to_json
153
+ def dump_jwk(key)
154
+ key.to_jwk.to_json
185
155
  end
186
156
  end
187
157
 
data/lib/letscert.rb CHANGED
@@ -24,7 +24,7 @@
24
24
  module LetsCert
25
25
 
26
26
  # Letscert version number
27
- VERSION = '0.2.2'
27
+ VERSION = '0.2.3'
28
28
 
29
29
 
30
30
  # Base error class
@@ -0,0 +1 @@
1
+ {"kty":"RSA","e":"AQAB","n":"ugv1o2Fg5N-RBScXrLpRRoPgDjFgHcM_BD2fHZYzXJ4k1AnspAgS-soaWuoN0WK4mwRsSGwF7cemLEA1zZiCpc6Q3WUxLDsM8oF8P_S0euAEhe8FQPON3vtNqYth2yPqAQ4-me43mZyXS94yzTrCVjowlnZsdaA54uUW0AxOD_0","d":"Qo-6zzwspVXTFYvZ7YMvRtIxnAJQR_Wtmv_M6JHvSEiQFoiCcGEvISijazlnvizarSNU9kgnit2t9xD17tuMidbqdPC0x0mkJ6BszB7lau6Nzfz6ACSqtH8eKmkGDBJTnRqzg45Z6-3-gQ9vlmvc3T029Gv7xfA-XOt_cNgFnGE","p":"7nhrSRbf6FZ6LA2FKzcdFOTSI7UlgEwWsrSC_7pyzYyXJC44crlWUDxxJJXNeC9OyOEJOXlgn-0hShAWkl9-CQ","q":"x7kFmj6GYbh0SaLeg9CFhnY-y_UMO9wFxu0NLi2JgL31gvIDrKGJYiSZ3xESi6FwpmHX_vbtFXpZXBbvMy0_VQ"}
@@ -0,0 +1,104 @@
1
+ require_relative 'spec_helper'
2
+ require 'fileutils'
3
+
4
+ module LetsCert
5
+
6
+ describe IOPlugin do
7
+
8
+ it '.empty_data always returns the same hash' do
9
+ hsh = IOPlugin.empty_data
10
+
11
+ expect(hsh.keys.size).to eq(4)
12
+ [:account_key, :key, :cert, :chain].each do |key|
13
+ expect(hsh.keys).to include(key)
14
+ expect(hsh[key]).to be_nil
15
+ end
16
+ end
17
+
18
+ it '.register registers known subclasses' do
19
+ names = %w(account_key.json key.pem key.der chain.pem fullchain.pem)
20
+ names += %w(cert.pem cert.der)
21
+
22
+ expect(IOPlugin.registered.size).to eq(names.size)
23
+
24
+ names.each do |name|
25
+ expect(IOPlugin.registered.keys).to include(name)
26
+ end
27
+ end
28
+
29
+ it '.register may register new classes' do
30
+ class NewIO < IOPlugin;end
31
+ IOPlugin.register(NewIO, 'newio')
32
+
33
+ expect(IOPlugin.registered.keys).to include('newio')
34
+ expect(IOPlugin.registered['newio']).to be_a(NewIO)
35
+ end
36
+
37
+ end
38
+
39
+ describe JWKIOPluginMixin do
40
+
41
+ class Test; include JWKIOPluginMixin; end
42
+
43
+ let(:test) { Test.new }
44
+
45
+ it "#load_jwk loads a RSA key from a JSON Web Key raw string" do
46
+ jwk = File.read(File.join(File.dirname(__FILE__), 'test.json'))
47
+ key = test.load_jwk(jwk)
48
+
49
+ expect(key).to be_a(OpenSSL::PKey::PKey)
50
+ end
51
+
52
+ it "#dump_jwk dumps a RSA key to a JSON Web Key raw string" do
53
+ jwk = File.read(File.join(File.dirname(__FILE__), 'test.json'))
54
+ key = test.load_jwk(jwk)
55
+
56
+ jwk2 = test.dump_jwk(key)
57
+ expect(jwk2).to eq(jwk)
58
+ end
59
+ end
60
+
61
+ describe AccountKey do
62
+
63
+ before(:all) { IOPlugin.logger = Logger.new('/dev/null') }
64
+
65
+ let(:ak) { IOPlugin.registered['account_key.json'] }
66
+
67
+ it 'persist account_key' do
68
+ persisted = ak.persisted
69
+ expect(persisted[:account_key]).to be(true)
70
+ end
71
+
72
+ it "#load account key from account_key.json file" do
73
+ expect(ak).to be_a(AccountKey)
74
+
75
+ pwd = FileUtils.pwd
76
+ FileUtils.cd File.dirname(__FILE__)
77
+
78
+ begin
79
+ content = ak.load
80
+ expect(content).to be_a(Hash)
81
+ expect(content.keys.size).to eq(1)
82
+ expect(content[:account_key]).to be_a(OpenSSL::PKey::PKey)
83
+ rescue Exception
84
+ raise
85
+ ensure
86
+ FileUtils.cd pwd
87
+ end
88
+ end
89
+
90
+ it "#save account key to account_key.json file" do
91
+ data = { account_key: OpenSSL::PKey::RSA.new(1024) }
92
+ ak.save(data)
93
+ begin
94
+ expect(File.exist?('account_key.json')).to be_truthy
95
+ rescue Exception
96
+ raise
97
+ ensure
98
+ File.unlink('account_key.json')
99
+ end
100
+ end
101
+
102
+ end
103
+
104
+ end
@@ -0,0 +1,16 @@
1
+ require_relative 'spec_helper'
2
+
3
+ module LetsCert
4
+
5
+ describe IOPlugin do
6
+
7
+ it '.empty_data always returns the same hash' do
8
+ hsh = IOPlugin.empty_data
9
+
10
+ expect(hsh.keys.size).to eq(4)
11
+ expect(hsh.keys).to include(:account_key)
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,32 @@
1
+ require_relative 'spec_helper'
2
+
3
+ module LetsCert
4
+
5
+ describe Loggable do
6
+
7
+ it 'extend a class to add loggability' do
8
+ class TestA; include Loggable; end
9
+
10
+ expect(TestA.methods).to include(:logger=)
11
+
12
+ my_logger = Logger.new(STDERR)
13
+ TestA.logger = my_logger
14
+ expect(TestA.new.logger).to eq(my_logger)
15
+ end
16
+
17
+ it 'extend a class and its subclasses to add loggability' do
18
+ class TestA; include Loggable; end
19
+ class TestB < TestA; end
20
+
21
+ expect(TestA.methods).to include(:logger=)
22
+ expect(TestB.methods).to include(:logger=)
23
+
24
+ my_logger = Logger.new(STDERR)
25
+ TestA.logger = my_logger
26
+ expect(TestA.new.logger).to eq(my_logger)
27
+ expect(TestB.new.logger).to eq(my_logger)
28
+ end
29
+
30
+ end
31
+
32
+ end
@@ -0,0 +1 @@
1
+ require_relative 'spec_helper'
@@ -0,0 +1,2 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'letscert'
@@ -0,0 +1 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
data/spec/test.json ADDED
@@ -0,0 +1 @@
1
+ {"kty":"RSA","e":"AQAB","n":"ugv1o2Fg5N-RBScXrLpRRoPgDjFgHcM_BD2fHZYzXJ4k1AnspAgS-soaWuoN0WK4mwRsSGwF7cemLEA1zZiCpc6Q3WUxLDsM8oF8P_S0euAEhe8FQPON3vtNqYth2yPqAQ4-me43mZyXS94yzTrCVjowlnZsdaA54uUW0AxOD_0","d":"Qo-6zzwspVXTFYvZ7YMvRtIxnAJQR_Wtmv_M6JHvSEiQFoiCcGEvISijazlnvizarSNU9kgnit2t9xD17tuMidbqdPC0x0mkJ6BszB7lau6Nzfz6ACSqtH8eKmkGDBJTnRqzg45Z6-3-gQ9vlmvc3T029Gv7xfA-XOt_cNgFnGE","p":"7nhrSRbf6FZ6LA2FKzcdFOTSI7UlgEwWsrSC_7pyzYyXJC44crlWUDxxJJXNeC9OyOEJOXlgn-0hShAWkl9-CQ","q":"x7kFmj6GYbh0SaLeg9CFhnY-y_UMO9wFxu0NLi2JgL31gvIDrKGJYiSZ3xESi6FwpmHX_vbtFXpZXBbvMy0_VQ"}
data/tasks/gem.rake CHANGED
@@ -22,6 +22,7 @@ EOF
22
22
  s.executables = ['letscert']
23
23
 
24
24
  s.add_dependency 'acme-client', '~>0.3.0'
25
+ s.add_dependency 'json-jwt', '~>1.5'
25
26
  s.add_dependency 'yard', '~>0.8'
26
27
 
27
28
  #s.add_development_dependency 'rspec', '~>3.4'
data/tasks/spec.rake ADDED
@@ -0,0 +1,3 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: letscert
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sylvain Daubert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-05 00:00:00.000000000 Z
11
+ date: 2016-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: acme-client
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.3.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: json-jwt
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.5'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: yard
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -55,13 +69,20 @@ files:
55
69
  - lib/letscert.rb
56
70
  - lib/letscert.rb~
57
71
  - lib/letscert/certificate.rb
58
- - lib/letscert/certificate.rb~
59
72
  - lib/letscert/io_plugin.rb
60
73
  - lib/letscert/loggable.rb
61
- - lib/letscert/loggable.rb~
62
74
  - lib/letscert/runner.rb
75
+ - spec/account_key.json
76
+ - spec/io_plugin_spec.rb
77
+ - spec/io_plugin_spec.rb~
78
+ - spec/loggable_spec.rb
79
+ - spec/loggable_spec.rb~
80
+ - spec/spec_helper.rb
81
+ - spec/spec_helper.rb~
82
+ - spec/test.json
63
83
  - tasks/gem.rake
64
84
  - tasks/gem.rake~
85
+ - tasks/spec.rake
65
86
  - tasks/yard.rake
66
87
  homepage: https://github.com/sdaubert/letscert
67
88
  licenses:
@@ -83,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
104
  version: '0'
84
105
  requirements: []
85
106
  rubyforge_project:
86
- rubygems_version: 2.2.2
107
+ rubygems_version: 2.4.5.1
87
108
  signing_key:
88
109
  specification_version: 4
89
110
  summary: letscert, a simple Let's Encrypt client
@@ -1,8 +0,0 @@
1
-
2
- module LetsCert
3
-
4
- # Class to handle ACME operations on certificates
5
- class Certificate
6
- end
7
-
8
- end
@@ -1,24 +0,0 @@
1
- module LetsCert
2
-
3
- module Loggable
4
-
5
- module ClassMethods
6
-
7
- # Set logger
8
- # @param [Logger] logger
9
- def self.logger=(logger)
10
- @@logger = logger
11
- end
12
-
13
- end
14
-
15
-
16
- # Get logger instance
17
- # @return [Logger]
18
- def logger
19
- @logger ||= self.class.class_variable_get(:@@logger)
20
- end
21
-
22
- end
23
-
24
- end