2021-04-19 01:29:53 +00:00
|
|
|
require 'net/ssh'
|
|
|
|
require 'pathname'
|
|
|
|
require 'json'
|
|
|
|
namespace :create_site do
|
|
|
|
desc "Change Site Cert"
|
2021-12-09 09:59:15 +00:00
|
|
|
task :change_site_cert,[:id,:is_certbot,:id_is_server,:cert_id,:redirect_to_https,:exec_finish] => :environment do |task,args|
|
2021-04-19 01:29:53 +00:00
|
|
|
begin
|
2021-10-08 12:04:38 +00:00
|
|
|
site_server = nil
|
|
|
|
site_constructs = []
|
|
|
|
@is_multithread = false
|
|
|
|
@thread = nil
|
2021-12-09 09:59:15 +00:00
|
|
|
@default_cert = args.cert_id ? SiteCert.find(args.cert_id) : nil
|
2021-10-08 12:04:38 +00:00
|
|
|
if args.id_is_server
|
|
|
|
site_server = SiteServer.find(args.id)
|
|
|
|
site_constructs = site_server.site_constructs.to_a
|
|
|
|
@is_multithread = true
|
2021-12-09 09:59:15 +00:00
|
|
|
Multithread.where(:key=>'batch_install_certs').each{|thread| thread.destroy if (thread.status["status"] == "error" || thread.status["status"] == "finish")}
|
|
|
|
Multithread.where(:key=>'batch_install_certs').destroy
|
|
|
|
@thread = Multithread.where(:key=>'batch_install_certs').first
|
2021-10-08 12:04:38 +00:00
|
|
|
if @thread.nil?
|
2021-12-09 09:59:15 +00:00
|
|
|
@thread = Multithread.create(:key=>'batch_install_certs',:status=>{"infos"=>[],"status"=>"execing"})
|
2021-10-08 12:04:38 +00:00
|
|
|
else
|
2021-12-09 09:59:15 +00:00
|
|
|
return false if @default_cert.nil?
|
2021-10-08 12:04:38 +00:00
|
|
|
end
|
|
|
|
else
|
|
|
|
@site_construct = SiteConstruct.find(args.id)
|
|
|
|
site_server = @site_construct.site_server
|
|
|
|
@site_construct.update(:infos=>[],:status=>"changing")
|
|
|
|
site_constructs << @site_construct
|
|
|
|
end
|
|
|
|
tmp_is_certbot = (args.is_certbot == "true")
|
|
|
|
if !site_server.nil?
|
2021-04-19 01:29:53 +00:00
|
|
|
@password = site_server.password
|
|
|
|
Net::SSH.start(site_server.ip , site_server.account , password: site_server.password) do |ssh|
|
2021-12-09 09:59:15 +00:00
|
|
|
redirect_to_https = args.redirect_to_https ? true : (@site_construct.redirect_to_https rescue false)
|
2021-10-08 12:04:38 +00:00
|
|
|
if tmp_is_certbot || (@site_cert.is_certbot rescue false)
|
|
|
|
domain_names = site_constructs.flat_map{|site_construct| site_construct.domain_name.strip.split(" ")}.select{|d| d.present? && d.match(/^[\d\.]+$/).nil?}
|
2021-11-19 03:21:49 +00:00
|
|
|
domain_names = domain_names.select{|d| `dig #{d} +short`.split("\n").select{|s| s.strip == site_server.ip}.count != 0}
|
2021-10-08 12:04:38 +00:00
|
|
|
if domain_names.count != 0
|
2022-10-16 07:58:59 +00:00
|
|
|
certbot_path = exec_ssh_command_by_sudo_and_see_output(ssh,"bash -l -c 'which certbot certbot-auto'",false,true).strip.split("\n")[0].strip()
|
2021-08-11 08:16:14 +00:00
|
|
|
if certbot_path.present?
|
2021-10-08 12:04:38 +00:00
|
|
|
auto_update_infos("Using certbot to update cert setting...")
|
|
|
|
if site_constructs.count > 1
|
|
|
|
auto_update_infos("Generating single cert for multiple domain names...")
|
2021-08-11 08:16:14 +00:00
|
|
|
end
|
2022-09-17 02:10:58 +00:00
|
|
|
exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' #{certbot_path} --nginx #{domain_names.map{|d| "-d " + d}.join(" ")} -n --#{redirect_to_https ? 'redirect' : 'no-redirect'} --expand",true,false)
|
2021-10-08 12:04:38 +00:00
|
|
|
site_constructs.each do |site_construct|
|
|
|
|
@site_construct = site_construct
|
|
|
|
auto_update_infos("Checking cert for #{site_construct.site_name}...")
|
|
|
|
nginx_file = site_construct.nginx_file
|
|
|
|
nginx_file_content = exec_ssh_command_by_sudo_and_see_output(ssh,"cat #{nginx_file}",false,true)
|
|
|
|
crt_file_path = nginx_file_content.match(/(?<=!#|^)\s*ssl_certificate\s+(.*)/)[1].split(';').first rescue ''
|
|
|
|
private_key_path = nginx_file_content.match(/(?<=!#|^)\s*ssl_certificate_key\s+(.*)/)[1].split(';').first rescue ''
|
|
|
|
site_cert = site_construct.site_cert
|
|
|
|
if crt_file_path.present? && private_key_path.present?
|
|
|
|
if site_cert.nil? || !site_cert.is_certbot
|
|
|
|
site_cert = SiteCert.where(:source_paths=>[crt_file_path,private_key_path]).first
|
|
|
|
site_cert = SiteCert.new if site_cert.nil?
|
|
|
|
end
|
|
|
|
if true #site_cert.source_paths.count == 0
|
|
|
|
site_cert["cert_file"] = File.basename(crt_file_path)
|
|
|
|
cert_file_store_path = site_cert.cert_file.file.file
|
|
|
|
crt_file_content = exec_ssh_command_by_sudo_and_see_output(ssh,"cat #{crt_file_path}",false).select{|s| s.present?}.join("\n").strip.split(/(\r\n|\n)/).select{|s| s.present?}.join("\n")
|
|
|
|
FileUtils.mkdir_p(File.dirname(cert_file_store_path)) unless Dir.exist?(File.dirname(cert_file_store_path))
|
|
|
|
File.open(site_cert.cert_file.file.file,'w+'){|f| f.write(crt_file_content)}
|
|
|
|
site_cert["private_key"] = File.basename(private_key_path)
|
|
|
|
private_key_store_path = site_cert.private_key.file.file
|
|
|
|
private_key_content = exec_ssh_command_by_sudo_and_see_output(ssh,"cat #{private_key_path}",false).select{|s| s.present?}.join("\n").strip.split(/(\r\n|\n)/).select{|s| s.present?}.join("\n")
|
|
|
|
FileUtils.mkdir_p(File.dirname(private_key_store_path)) unless Dir.exist?(File.dirname(private_key_path))
|
|
|
|
File.open(site_cert.private_key.file.file,'w+'){|f| f.write(private_key_content)}
|
|
|
|
site_cert.source_paths = [crt_file_path,private_key_path]
|
|
|
|
site_cert.is_certbot = private_key_path.include?("letsencrypt")
|
|
|
|
site_cert.save
|
|
|
|
site_construct.update(:site_cert=>site_cert)
|
|
|
|
end
|
|
|
|
all_ports = (site_construct.port + ["443"]).uniq
|
2021-12-09 09:59:15 +00:00
|
|
|
site_construct.update(:port=> all_ports, :status=>'finish' )
|
2021-10-08 12:04:38 +00:00
|
|
|
auto_update_infos("Finish installing cert with certbot in #{site_construct.site_name} !")
|
|
|
|
else
|
|
|
|
auto_update_infos("Certbot generate cert failed!")
|
|
|
|
auto_update_infos("Please check your domain dns setting(A record)!")
|
|
|
|
site_construct.update(:status=>"error")
|
2021-08-11 08:16:14 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
else
|
2021-10-08 12:04:38 +00:00
|
|
|
auto_update_infos("Please install certbot first!")
|
2021-08-11 08:16:14 +00:00
|
|
|
end
|
|
|
|
else
|
2021-10-08 12:04:38 +00:00
|
|
|
auto_update_infos("Please set domain name first!")
|
2021-08-11 08:16:14 +00:00
|
|
|
end
|
|
|
|
else
|
2021-10-08 12:04:38 +00:00
|
|
|
site_constructs.each do |site_construct|
|
2021-12-09 09:59:15 +00:00
|
|
|
@site_cert = @default_cert || @site_construct.site_cert
|
2021-10-08 12:04:38 +00:00
|
|
|
next if @site_cert.nil?
|
|
|
|
is_certbot = tmp_is_certbot || (@site_cert.is_certbot rescue false)
|
|
|
|
@site_construct = site_construct
|
|
|
|
@site_cert.change_data
|
|
|
|
if @site_cert.is_valid
|
2021-12-09 09:59:15 +00:00
|
|
|
valid_domain_names = @site_cert.valid_domain_names(@site_construct.domain_name)
|
|
|
|
next if valid_domain_names.count == 0
|
|
|
|
if @default_cert
|
|
|
|
@site_construct.update(:site_cert=>@default_cert,:redirect_to_https=>redirect_to_https)
|
|
|
|
end
|
2021-10-08 12:04:38 +00:00
|
|
|
auto_update_infos("Copying Cert to #{@site_construct.server_type}...")
|
2021-12-09 09:59:15 +00:00
|
|
|
auto_update_infos("Installing Cert on #{valid_domain_names.join(" , ")}")
|
2021-10-08 12:04:38 +00:00
|
|
|
cert_file_content = [(@site_cert.cert_file.file.read.strip rescue ""),(@site_cert.ca_bundle.file.read.strip rescue "")].join("\n").strip
|
|
|
|
private_key_content = @site_cert.private_key.file.read
|
2022-10-16 07:13:12 +00:00
|
|
|
if is_certbot && @site_cert.source_paths.present? && @site_cert.source_paths.count == 2
|
|
|
|
source_paths = @site_cert.source_paths
|
|
|
|
is_exist = exec_command_by_user(ssh, "echo '#{@password}'|sudo -S bash -c 'if [ -e \"#{source_paths[0]}\" ] && [ -e \"#{source_paths[1]}\" ] ; then echo 1; else echo 0; fi'").strip() == "1"
|
|
|
|
else
|
|
|
|
is_exist = false
|
|
|
|
end
|
|
|
|
if is_exist
|
|
|
|
auto_update_infos("Cert already exist.")
|
|
|
|
else
|
|
|
|
cert_file_store_path = @site_construct.cert_file_remote_store_path
|
|
|
|
exec_ssh_command_by_sudo(ssh,"mkdir -p #{File.dirname(cert_file_store_path)}")
|
|
|
|
exec_command_by_user(ssh,"x='#{cert_file_content}'; echo '#{@password}' | sudo -S sh -c \"echo '$x' > #{cert_file_store_path}\"")
|
|
|
|
private_key_store_path = @site_construct.private_key_remote_store_path
|
|
|
|
exec_ssh_command_by_sudo(ssh,"mkdir -p #{File.dirname(private_key_store_path)}")
|
|
|
|
exec_command_by_user(ssh,"x='#{private_key_content}'; echo '#{@password}' | sudo -S sh -c \"echo '$x' > #{private_key_store_path}\"")
|
|
|
|
auto_update_infos("Finish copy.")
|
|
|
|
end
|
2021-10-08 12:04:38 +00:00
|
|
|
auto_update_infos("Setting Cert...")
|
|
|
|
nginx_file_content = exec_command_by_user(ssh,"cat #{@site_construct.nginx_file}")
|
|
|
|
all_ports = (@site_construct.port + ["443"]).uniq
|
2021-12-09 09:59:15 +00:00
|
|
|
@site_construct.update(:port=> all_ports,:status=>'finish' )
|
2021-10-08 12:04:38 +00:00
|
|
|
nginx_file_content = @site_construct.generate_nginx_text(nginx_file_content)
|
2022-09-08 06:48:32 +00:00
|
|
|
cmd = "x='#{nginx_file_content.gsub(/'{1,3}/,"\"\'\"")}'; echo '#{@password}' | sudo -S sh -c \"echo '$x' > #{@site_construct.nginx_file}\""
|
2021-10-08 12:04:38 +00:00
|
|
|
exec_command_by_user(ssh,cmd)
|
|
|
|
end
|
|
|
|
end
|
2021-08-11 08:16:14 +00:00
|
|
|
end
|
2021-04-19 01:29:53 +00:00
|
|
|
exec_ssh_command_by_sudo(ssh,"service nginx restart")
|
2021-12-09 09:59:15 +00:00
|
|
|
if @default_cert.nil? || args.exec_finish
|
|
|
|
auto_update_infos("Finish!")
|
|
|
|
if @is_multithread
|
|
|
|
@thread.update(:status=>@thread.status.merge({"status"=>"finish"}))
|
|
|
|
else
|
|
|
|
@site_construct.update(:status=>"finish")
|
|
|
|
end
|
2021-10-08 12:04:38 +00:00
|
|
|
end
|
2021-04-19 01:29:53 +00:00
|
|
|
end
|
|
|
|
else
|
2021-10-08 12:04:38 +00:00
|
|
|
auto_update_infos("Cert not found!")
|
2021-04-19 01:29:53 +00:00
|
|
|
@site_construct.update(:status=>"error")
|
|
|
|
end
|
|
|
|
rescue => e
|
|
|
|
puts [e,e.backtrace]
|
2021-10-08 12:04:38 +00:00
|
|
|
auto_update_infos(e.to_s)
|
2021-12-09 09:59:15 +00:00
|
|
|
if @is_multithread
|
|
|
|
@thread.update(:status=>@thread.status.merge({"status"=>"error"}))
|
|
|
|
else
|
|
|
|
@site_construct.update(:status=>"error")
|
|
|
|
end
|
2021-04-19 01:29:53 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
def exec_command_by_user(session,command)
|
|
|
|
output = session.exec!(command)
|
|
|
|
return output[0...-1].gsub(/^\n[\n]+/,'')
|
|
|
|
end
|
|
|
|
def exec_ssh_command_by_sudo(session,command)
|
|
|
|
output = session.exec!("echo '#{@password}' | sudo -S #{command}")
|
|
|
|
if output.include?("sudo:") && output.include?("command not found")
|
|
|
|
output = session.exec!(command)
|
|
|
|
end
|
2022-07-21 16:10:04 +00:00
|
|
|
return output.encode!("UTF-8", :invalid => :replace, :undef => :replace, :replace => '')
|
2021-04-19 01:29:53 +00:00
|
|
|
end
|
2021-10-08 12:04:38 +00:00
|
|
|
def auto_update_infos(info)
|
|
|
|
if @is_multithread
|
|
|
|
update_thread_infos(info)
|
|
|
|
if @site_construct
|
|
|
|
update_infos(info)
|
|
|
|
end
|
|
|
|
else
|
|
|
|
update_infos(info)
|
|
|
|
end
|
|
|
|
end
|
2021-04-19 01:29:53 +00:00
|
|
|
end
|