checkin of initial letsencrypt code

This commit is contained in:
Kyle Drake 2016-06-16 01:42:16 -07:00
parent 6a8aaacd20
commit 8473b99d56
11 changed files with 117 additions and 0 deletions

3
.gitignore vendored
View file

@ -21,3 +21,6 @@ files/sslsites.zip
public/banned_sites
public/deleted_sites
files/disposable_email_blacklist.conf
files/letsencrypt.key
files/tor.txt
.bundle

View file

@ -39,6 +39,7 @@ gem 'simpleidn'
gem 'gandi'
gem 'hoe', '3.14.2', require: nil
gem 'msgpack'
gem 'acme-client'
platform :mri, :rbx do
gem 'magic' # sudo apt-get install file, For OSX: brew install libmagic

View file

@ -1,6 +1,9 @@
GEM
remote: https://rubygems.org/
specs:
acme-client (0.3.1)
faraday (~> 0.9, >= 0.9.1)
json-jwt (~> 1.2, >= 1.2.3)
activesupport (4.2.6)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
@ -14,6 +17,7 @@ GEM
ansi (1.5.0)
base32 (0.3.2)
bcrypt (3.1.11)
bindata (2.3.0)
blankslate (3.1.3)
builder (3.2.2)
byebug (8.2.4)
@ -58,6 +62,8 @@ GEM
fabrication (2.15.0)
faker (1.6.3)
i18n (~> 0.5)
faraday (0.9.2)
multipart-post (>= 1.2, < 3)
ffi (1.9.10)
ffi-compiler (0.1.3)
ffi (>= 1.0.0)
@ -82,6 +88,12 @@ GEM
rack (~> 1.4)
rest-client (~> 1.0)
json (1.8.3)
json-jwt (1.5.2)
activesupport
bindata
multi_json (>= 1.3)
securecompare
url_safe_base64
m (1.4.2)
method_source (>= 0.6.7)
rake (>= 0.9.2.2)
@ -104,6 +116,7 @@ GEM
mock_redis (0.16.1)
msgpack (0.7.5)
multi_json (1.11.2)
multipart-post (2.0.0)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
net-ssh (3.1.1)
@ -166,6 +179,7 @@ GEM
scrypt (2.1.1)
ffi-compiler (>= 0.0.2)
rake
securecompare (1.0.0)
sequel (4.8.0)
sequel_pg (1.6.16)
pg (>= 0.8.0)
@ -216,6 +230,7 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.7.2)
url_safe_base64 (0.2.2)
uuidtools (2.1.5)
webmock (1.24.2)
addressable (>= 2.3.6)
@ -233,6 +248,7 @@ PLATFORMS
ruby
DEPENDENCIES
acme-client
addressable
ago
base32

View file

@ -66,6 +66,7 @@ post '/settings/:username/profile' do
redirect "/settings/#{@site.username}#profile"
end
=begin
post '/settings/:username/ssl' do
require_login
require_ownership_for_settings
@ -167,6 +168,7 @@ post '/settings/:username/ssl' do
flash[:success] = 'Updated SSL key/certificate.'
redirect "/settings/#{@site.username}#custom_domain"
end
=end
post '/settings/:username/change_name' do
require_login
@ -241,6 +243,7 @@ post '/settings/:username/custom_domain' do
if @site.valid?
@site.save_changes
RequestSSLAuthWorker.perform_async @site.id
flash[:success] = 'The domain has been successfully updated.'
redirect "/settings/#{@site.username}#custom_domain"
else

View file

@ -15,6 +15,8 @@ development:
paypal_api_username: derp
paypal_api_password: ing
paypal_api_signature: tonz
letsencrypt_key: ./tests/files/letsencrypt.key
letsencrypt_endpoint: https://acme-staging.api.letsencrypt.org/
test:
database: 'postgres://neocities@localhost/neocities_test'
database_pool: 1
@ -31,3 +33,5 @@ test:
paypal_api_username: derp
paypal_api_password: ing
paypal_api_signature: tonz
letsencrypt_key: ./tests/files/letsencrypt.key
letsencrypt_endpoint: https://acme-staging.api.letsencrypt.org/

View file

@ -11,3 +11,5 @@ paypal_api_username: derp
paypal_api_password: ing
paypal_api_signature: tonz
logs_path: "/tmp/neocitiestestlogs"
letsencrypt_key: ./tests/files/letsencrypt.key
letsencrypt_endpoint: https://acme-staging.api.letsencrypt.org/

View file

@ -152,3 +152,10 @@ end
gandi_opts = {}
gandi_opts[:env] = :test unless ENV['RACK_ENV'] == 'production'
$gandi = Gandi::Session.new $config['gandi_api_key'], gandi_opts
# Let's Encrypt
$letsencrypt = Acme::Client.new(
private_key: OpenSSL::PKey::RSA.new(File.read($config['letsencrypt_key'])),
endpoint: $config['letsencrypt_endpoint']
)

View file

@ -1330,6 +1330,28 @@ class Site < Sequel::Model
sanitized.gsub(/(http|https):\/\//, '').gsub(/[^\w\s]/, '').downcase.split.uniq.select{|v| v.length < SiteFile::CLASSIFIER_WORD_LIMIT}.join(' ')
end
def request_ssl_authorization
auth = $letsencrypt.authorize domain: domain
challenge = auth.http01
FileUtils.mkdir_p File.join(base_files_path, File.dirname(challenge.filename))
File.write File.join(base_files_path, challenge.filename), challenge.file_content
challenge.request_verification
challenge
end
# request_ssl_authorization must be run first!
def obtain_ssl_certificate
csr = Acme::Client::CertificateRequest.new names: [domain, "www.#{domain}"]
certificate = $letsencrypt.new_certificate csr
self.ssl_key = certificate.request.private_key.to_pem
self.ssl_cert = certificate.fullchain_to_pem
save_changes
FileUtils.rm_rf File.join(base_files_path, '.well-known')
end
# array of hashes: filename, tempfile, opts.
def store_files(files, opts={})
results = []

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAwsY6rlj09XsfnxbzatQKEqjN9Kqynjp+o7jaHBaWMjRSOSqC
xj0ThnxghxsXnUZEP+Wc/e38JQ15Ob8LRe5AnigP65ArvC3Fk9p19uV9JkX+gBtr
LSzQqSD0As+4SQc8iE7zoAH8Oz2t1WXGOJnhw/D3DZBoEis4TBXctc9FMYYWtCSH
2wfqUMTVUru6vOG9dv1w/7lQr4+YIHJGGai9p+XEqLGmkH/JkHwQ11XJZcBjKQtQ
1jTfryzMtCGtdRBvF9Au2JCWz3zrVdh4Pz6pj8NTQ87izf97u3RvmnnZIT9RSPWF
LVfkFSLNExguMqreWi8NzI79rfP08bMAhIcEFQIDAQABAoIBAEABJAdm9Bg2/Y0p
3ZOdWjIHhqZ/8XJNhpAGjqXsRi75QovGjHLYXzIybQX4wSnNjV/x9ET9j34dj1iK
jwnL4TAXuiOOnNCZufN8NoeLojSRi7BNUkrmDyuEyKqj18sntZyVVTmfbWOKQTV+
3ER9TNM2u/iZG5nc2gMmrACSvAopktYvBYRPHAmCR8ZLkE6ZjPeOKcJbr6F5D9Ie
X5+QKsoG0by7Gu8eHkOh0WtufeOM38OfSStDpPW5eu5JOFrtgEQPolaMi0Mw2h4D
aaNLUQbmk1I9JMS17yVJFnTrrKTSeHFiC16rwKWJvG0S4DUfsyMW9u0oog4sYrAT
5j0+oAECgYEA8ZD2QRbuZD52F6SPB6tV0LokUijKLLzUW1+d8R54sW7ATurCSspU
J9CRSmyi9cfFn9ReP776dRBgtfYmf6IV5Ju6fH86+B2+WI/2YLqbMkpcAILnRF80
IlfJK4mDy0ljxvubUNaEUcZj/bpINx5PwddU7Xl6POWuYxXzBn4TZNUCgYEAzmmH
t+Qv9l+LxxaNDIdZYtWhkYUWGzupiLKWHjrnprqmFLODDCbfA95Y1jxK3tBxZ3Yp
TRD9XJ/0+PrLK992OUDvlPxX4XSMZPMtsqLSAwlnAvUzzZQimhyhC8rx2eogbDSx
Wf0pKqMRVJdk6zFEMKNx+Lcgvpv5rCWoIJ7twkECgYAJdFf/AivAZqVulXU3oqAQ
NEjZolkPWTCihuKCnmOw5hnGvO9vx+11RXd6Rzg1kGUOtVwe+JWK4WI3nPOyySA8
O1AYMU6YiWl6w9+rt4H9fOWO65Crn2JF+dOYzaAH485w6kYQ6uRw4ufk9VaAOcJ7
XrcnODrtiTvDCwfg+CxAJQKBgFHlCNXrESR9ECYzSk8YPFy8SdhEp1qytzbnNCxW
TqaWE2LPPkVJ/t24ECMf1MzGgtf7x7Mt9HgVdsp6JrYHeQ6KNwQzgmKPLUy4Nv9T
HmPaDSbdRmpgRcJDbZoSMRa2j5qe5WbAzN5/yFZ5oq6140ow7v0xGyrFE7A7WJNo
uwiBAoGAMyptWRsi0vFMXy/0b26whVj2LGFLRDS03bT3XhyQmCnp+f+03GHbuggM
/IAf3RMj8oub1RrPoFqzd78n0CnZLwk+A6w8EMkKDFCY1sLESy7dVtPdS91deIxk
H07fMxqzLYQO6XplcmqsD06PuTLmWYDjA9e8hSSMQo1n+rSw4ko=
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,17 @@
class CreateSSLCertWorker
include Sidekiq::Worker
sidekiq_options queue: :create_ssl_auth_worker, retry: 100, backtrace: true
sidekiq_retry_in do |count|
180
end
def perform(site_id, challenge)
site = Site[site_id]
challenge = $letsencrypt.challenge_from_hash JSON.parse(challenge)
if challenge.verify_status == 'valid'
site.obtain_ssl_certificate
end
end
end

View file

@ -0,0 +1,15 @@
class RequestSSLAuthWorker
include Sidekiq::Worker
sidekiq_options queue: :request_ssl_auth_worker, retry: 100, backtrace: true
sidekiq_retry_in do |count|
180
end
def perform(site_id)
site = Site[site_id]
challenge = site.request_ssl_authorization
CreateSSLCertWorker.perform_in 5.seconds, site_id, challenge.to_h.to_json
end
end