mirror of
https://github.com/neocities/neocities.git
synced 2025-04-25 01:32:36 +02:00
checkin of initial letsencrypt code
This commit is contained in:
parent
6a8aaacd20
commit
8473b99d56
11 changed files with 117 additions and 0 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -21,3 +21,6 @@ files/sslsites.zip
|
||||||
public/banned_sites
|
public/banned_sites
|
||||||
public/deleted_sites
|
public/deleted_sites
|
||||||
files/disposable_email_blacklist.conf
|
files/disposable_email_blacklist.conf
|
||||||
|
files/letsencrypt.key
|
||||||
|
files/tor.txt
|
||||||
|
.bundle
|
||||||
|
|
1
Gemfile
1
Gemfile
|
@ -39,6 +39,7 @@ gem 'simpleidn'
|
||||||
gem 'gandi'
|
gem 'gandi'
|
||||||
gem 'hoe', '3.14.2', require: nil
|
gem 'hoe', '3.14.2', require: nil
|
||||||
gem 'msgpack'
|
gem 'msgpack'
|
||||||
|
gem 'acme-client'
|
||||||
|
|
||||||
platform :mri, :rbx do
|
platform :mri, :rbx do
|
||||||
gem 'magic' # sudo apt-get install file, For OSX: brew install libmagic
|
gem 'magic' # sudo apt-get install file, For OSX: brew install libmagic
|
||||||
|
|
16
Gemfile.lock
16
Gemfile.lock
|
@ -1,6 +1,9 @@
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
|
acme-client (0.3.1)
|
||||||
|
faraday (~> 0.9, >= 0.9.1)
|
||||||
|
json-jwt (~> 1.2, >= 1.2.3)
|
||||||
activesupport (4.2.6)
|
activesupport (4.2.6)
|
||||||
i18n (~> 0.7)
|
i18n (~> 0.7)
|
||||||
json (~> 1.7, >= 1.7.7)
|
json (~> 1.7, >= 1.7.7)
|
||||||
|
@ -14,6 +17,7 @@ GEM
|
||||||
ansi (1.5.0)
|
ansi (1.5.0)
|
||||||
base32 (0.3.2)
|
base32 (0.3.2)
|
||||||
bcrypt (3.1.11)
|
bcrypt (3.1.11)
|
||||||
|
bindata (2.3.0)
|
||||||
blankslate (3.1.3)
|
blankslate (3.1.3)
|
||||||
builder (3.2.2)
|
builder (3.2.2)
|
||||||
byebug (8.2.4)
|
byebug (8.2.4)
|
||||||
|
@ -58,6 +62,8 @@ GEM
|
||||||
fabrication (2.15.0)
|
fabrication (2.15.0)
|
||||||
faker (1.6.3)
|
faker (1.6.3)
|
||||||
i18n (~> 0.5)
|
i18n (~> 0.5)
|
||||||
|
faraday (0.9.2)
|
||||||
|
multipart-post (>= 1.2, < 3)
|
||||||
ffi (1.9.10)
|
ffi (1.9.10)
|
||||||
ffi-compiler (0.1.3)
|
ffi-compiler (0.1.3)
|
||||||
ffi (>= 1.0.0)
|
ffi (>= 1.0.0)
|
||||||
|
@ -82,6 +88,12 @@ GEM
|
||||||
rack (~> 1.4)
|
rack (~> 1.4)
|
||||||
rest-client (~> 1.0)
|
rest-client (~> 1.0)
|
||||||
json (1.8.3)
|
json (1.8.3)
|
||||||
|
json-jwt (1.5.2)
|
||||||
|
activesupport
|
||||||
|
bindata
|
||||||
|
multi_json (>= 1.3)
|
||||||
|
securecompare
|
||||||
|
url_safe_base64
|
||||||
m (1.4.2)
|
m (1.4.2)
|
||||||
method_source (>= 0.6.7)
|
method_source (>= 0.6.7)
|
||||||
rake (>= 0.9.2.2)
|
rake (>= 0.9.2.2)
|
||||||
|
@ -104,6 +116,7 @@ GEM
|
||||||
mock_redis (0.16.1)
|
mock_redis (0.16.1)
|
||||||
msgpack (0.7.5)
|
msgpack (0.7.5)
|
||||||
multi_json (1.11.2)
|
multi_json (1.11.2)
|
||||||
|
multipart-post (2.0.0)
|
||||||
net-scp (1.2.1)
|
net-scp (1.2.1)
|
||||||
net-ssh (>= 2.6.5)
|
net-ssh (>= 2.6.5)
|
||||||
net-ssh (3.1.1)
|
net-ssh (3.1.1)
|
||||||
|
@ -166,6 +179,7 @@ GEM
|
||||||
scrypt (2.1.1)
|
scrypt (2.1.1)
|
||||||
ffi-compiler (>= 0.0.2)
|
ffi-compiler (>= 0.0.2)
|
||||||
rake
|
rake
|
||||||
|
securecompare (1.0.0)
|
||||||
sequel (4.8.0)
|
sequel (4.8.0)
|
||||||
sequel_pg (1.6.16)
|
sequel_pg (1.6.16)
|
||||||
pg (>= 0.8.0)
|
pg (>= 0.8.0)
|
||||||
|
@ -216,6 +230,7 @@ GEM
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
unf_ext (0.0.7.2)
|
unf_ext (0.0.7.2)
|
||||||
|
url_safe_base64 (0.2.2)
|
||||||
uuidtools (2.1.5)
|
uuidtools (2.1.5)
|
||||||
webmock (1.24.2)
|
webmock (1.24.2)
|
||||||
addressable (>= 2.3.6)
|
addressable (>= 2.3.6)
|
||||||
|
@ -233,6 +248,7 @@ PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
|
acme-client
|
||||||
addressable
|
addressable
|
||||||
ago
|
ago
|
||||||
base32
|
base32
|
||||||
|
|
|
@ -66,6 +66,7 @@ post '/settings/:username/profile' do
|
||||||
redirect "/settings/#{@site.username}#profile"
|
redirect "/settings/#{@site.username}#profile"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
post '/settings/:username/ssl' do
|
post '/settings/:username/ssl' do
|
||||||
require_login
|
require_login
|
||||||
require_ownership_for_settings
|
require_ownership_for_settings
|
||||||
|
@ -167,6 +168,7 @@ post '/settings/:username/ssl' do
|
||||||
flash[:success] = 'Updated SSL key/certificate.'
|
flash[:success] = 'Updated SSL key/certificate.'
|
||||||
redirect "/settings/#{@site.username}#custom_domain"
|
redirect "/settings/#{@site.username}#custom_domain"
|
||||||
end
|
end
|
||||||
|
=end
|
||||||
|
|
||||||
post '/settings/:username/change_name' do
|
post '/settings/:username/change_name' do
|
||||||
require_login
|
require_login
|
||||||
|
@ -241,6 +243,7 @@ post '/settings/:username/custom_domain' do
|
||||||
|
|
||||||
if @site.valid?
|
if @site.valid?
|
||||||
@site.save_changes
|
@site.save_changes
|
||||||
|
RequestSSLAuthWorker.perform_async @site.id
|
||||||
flash[:success] = 'The domain has been successfully updated.'
|
flash[:success] = 'The domain has been successfully updated.'
|
||||||
redirect "/settings/#{@site.username}#custom_domain"
|
redirect "/settings/#{@site.username}#custom_domain"
|
||||||
else
|
else
|
||||||
|
|
|
@ -15,6 +15,8 @@ development:
|
||||||
paypal_api_username: derp
|
paypal_api_username: derp
|
||||||
paypal_api_password: ing
|
paypal_api_password: ing
|
||||||
paypal_api_signature: tonz
|
paypal_api_signature: tonz
|
||||||
|
letsencrypt_key: ./tests/files/letsencrypt.key
|
||||||
|
letsencrypt_endpoint: https://acme-staging.api.letsencrypt.org/
|
||||||
test:
|
test:
|
||||||
database: 'postgres://neocities@localhost/neocities_test'
|
database: 'postgres://neocities@localhost/neocities_test'
|
||||||
database_pool: 1
|
database_pool: 1
|
||||||
|
@ -31,3 +33,5 @@ test:
|
||||||
paypal_api_username: derp
|
paypal_api_username: derp
|
||||||
paypal_api_password: ing
|
paypal_api_password: ing
|
||||||
paypal_api_signature: tonz
|
paypal_api_signature: tonz
|
||||||
|
letsencrypt_key: ./tests/files/letsencrypt.key
|
||||||
|
letsencrypt_endpoint: https://acme-staging.api.letsencrypt.org/
|
|
@ -11,3 +11,5 @@ paypal_api_username: derp
|
||||||
paypal_api_password: ing
|
paypal_api_password: ing
|
||||||
paypal_api_signature: tonz
|
paypal_api_signature: tonz
|
||||||
logs_path: "/tmp/neocitiestestlogs"
|
logs_path: "/tmp/neocitiestestlogs"
|
||||||
|
letsencrypt_key: ./tests/files/letsencrypt.key
|
||||||
|
letsencrypt_endpoint: https://acme-staging.api.letsencrypt.org/
|
|
@ -152,3 +152,10 @@ end
|
||||||
gandi_opts = {}
|
gandi_opts = {}
|
||||||
gandi_opts[:env] = :test unless ENV['RACK_ENV'] == 'production'
|
gandi_opts[:env] = :test unless ENV['RACK_ENV'] == 'production'
|
||||||
$gandi = Gandi::Session.new $config['gandi_api_key'], gandi_opts
|
$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']
|
||||||
|
)
|
|
@ -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(' ')
|
sanitized.gsub(/(http|https):\/\//, '').gsub(/[^\w\s]/, '').downcase.split.uniq.select{|v| v.length < SiteFile::CLASSIFIER_WORD_LIMIT}.join(' ')
|
||||||
end
|
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.
|
# array of hashes: filename, tempfile, opts.
|
||||||
def store_files(files, opts={})
|
def store_files(files, opts={})
|
||||||
results = []
|
results = []
|
||||||
|
|
27
tests/files/letsencrypt.key
Normal file
27
tests/files/letsencrypt.key
Normal 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-----
|
17
workers/create_ssl_cert_worker.rb
Normal file
17
workers/create_ssl_cert_worker.rb
Normal 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
|
15
workers/request_ssl_auth_worker.rb
Normal file
15
workers/request_ssl_auth_worker.rb
Normal 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
|
Loading…
Add table
Reference in a new issue