Mercurial Hosting > luan
changeset 2057:634a44d10c96 acme-tiny tip
https.luan cleanup and add test
| author | Franklin Schmidt <fschmidt@gmail.com> |
|---|---|
| date | Wed, 12 Nov 2025 23:18:04 -0700 |
| parents | 75cd3c7bda02 |
| children | |
| files | host/test/test_https.luan src/luan/host/https.luan |
| diffstat | 2 files changed, 66 insertions(+), 54 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/host/test/test_https.luan Wed Nov 12 23:18:04 2025 -0700 @@ -0,0 +1,21 @@ +local Luan = require "luan:Luan.luan" +local error = Luan.error +local do_file = Luan.do_file or error() +local Io = require "luan:Io.luan" +local uri = Io.uri or error() +local Hosted = require "luan:host/Hosted.luan" +local Logging = require "luan:logging/Logging.luan" +local logger = Logging.logger "test_https" + + +do_file "classpath:luan/host/https.luan" + +local is_https = true +local domain = "https.s3.luan.software" +local site_dir = uri("file:local") +local luanhost_dir = uri("file:..") +local dry_run = true + +site_dir.mkdir() + +Hosted.do_set_https(is_https,domain,site_dir,luanhost_dir,dry_run)
--- a/src/luan/host/https.luan Tue Nov 11 22:07:12 2025 -0800 +++ b/src/luan/host/https.luan Wed Nov 12 23:18:04 2025 -0700 @@ -9,6 +9,8 @@ local uri = Io.uri or error() local String = require "luan:String.luan" local starts_with = String.starts_with or error() +local Thread = require "luan:Thread.luan" +local try_synchronized = Thread.try_synchronized or error() local Http = require "luan:http/Http.luan" local Hosted = require "luan:host/Hosted.luan" local Logging = require "luan:logging/Logging.luan" @@ -16,33 +18,16 @@ logger.info("Hello test") -function Hosted.set_https(is_https) - if Http.did_init() then - logger.error(new_error("set_https called outside of init.luan")) - return - end - local domain = Http.domain - local site_dir = uri("site:").parent() +local function do_set_https(is_https,domain,site_dir,luanhost_dir,dry_run) local nginx_file = site_dir.child("nginx.ssl.conf") local key_file = site_dir.child(domain..".key") - local key_file_str = key_file.canonical().to_string() local csr_file = site_dir.child(domain..".csr") - local csr_file_str = csr_file.canonical().to_string() local local_cer_file = site_dir.child("fullchain.cer") - local local_cer_file_str = local_cer_file.canonical().to_string() local local_ca_file = site_dir.child("ca.cer") -- luan/host - local luanhost_dir = uri("file:.").canonical().to_string() + local luanhost_file = "file:"..luanhost_dir.to_string().."/" + local luanhost_dir_str = luanhost_dir.canonical().to_string() local changed = false - -- use for testing, so as to not hit rate limits - -- on the real letsencrypt servers - local dry_run = false - local dry_run_dir_url = "https://acme-staging-v02.api.letsencrypt.org/directory" - - -- declare these so they are visible in the catch and finally blocks - local guard_file = "/tmp/acme_setup_locks/"..domain..".lock" - local guard_uri = uri("file:"..guard_file) - local temp_dir_string = "/tmp/acme_setup/"..domain if is_https then -- https if not key_file.exists() then @@ -60,37 +45,21 @@ else -- set up a temporary barebones nginx conf -- to serve acme challenges on the domain + local temp_dir = uri("file:/tmp/acme_setup/"..domain) try - - -- recursion guard, must have this to prevent - -- the http request from invoking this code - -- and causing an infinite recursion. - local cmd = "mkdir -p /tmp/acme_setup_locks/" - local s = uri("bash:"..cmd).read_text() - if guard_uri.exists() then - logger.info("set_https already running for "..domain..", skipping") - return - end - -- Clean out old temp files - local cmd = "rm -rf "..temp_dir_string - local s = uri("bash:"..cmd).read_text() + temp_dir.delete() -- create all needed dirs at once by using -- mkdir -p on the deepest nested dir (acme-challenge) - local webroot = temp_dir_string.."/webroot" + local webroot = temp_dir.to_string().."/webroot" local acme_challenges = webroot.."/.well-known/acme-challenge" - local cmd = "mkdir -p "..acme_challenges - local s = uri("bash:"..cmd).read_text() - - guard_uri.write("this is a recursion guard, see https.luan") - + uri("file:"..acme_challenges).mkdir() -- Create the nginx config from the template - local temp_dir = uri("file:"..temp_dir_string) -- The *output* file, where the generated config is stored local acme_nginx_file = temp_dir.child("nginx.acme_setup.conf") - local conf = load_file "file:startup/nginx/nginx.acme_setup.conf.luan" + local conf = load_file(luanhost_file.."startup/nginx/nginx.acme_setup.conf.luan") local acme_nginx = ` conf(webroot,domain) ` acme_nginx_file.write(acme_nginx) @@ -104,32 +73,36 @@ -- glob include confs in /tmp/acme_setup/*/nginx.acme_setup.conf -- so we just need to reload it so it can find the one we just made local cmd = [[ - sudo $(which nginx) -t -c "]]..luanhost_dir..[[/local/nginx.conf" && \ - sudo $(which nginx) -s reload -c "]]..luanhost_dir..[[/local/nginx.conf"; + sudo $(which nginx) -t -c "]]..luanhost_dir_str..[[/local/nginx.conf" && \ + sudo $(which nginx) -s reload -c "]]..luanhost_dir_str..[[/local/nginx.conf"; ]] local s = uri("bash:"..cmd).read_text() logger.info("reload_nginx "..s) -- We've set up nginx to serve from our temp root, now we need to -- create a *domain key*, which we then use to sign our cert. + local key_file_str = key_file.canonical().to_string() local cmd = "openssl genrsa 4096 > "..key_file_str local s = uri("bash:"..cmd).read_text() logger.info("create domain key\n"..s) -- create the cert, signed with the key we just made + local csr_file_str = csr_file.canonical().to_string() local cmd = 'openssl req -new -sha256 -key '..key_file_str..' -subj "/CN='..domain..'" > '..csr_file_str local s = uri("bash:"..cmd).read_text() logger.info("create cert\n"..s) -- Finally, get our cert signed by letsencrypt. local cmd = [[ - ./acme_tiny --account-key ./local/tiny_account.key \ + ]]..luanhost_dir_str..[[/acme_tiny --account-key ./local/tiny_account.key \ --csr ]]..csr_file_str..[[ \ --acme-dir ]]..acme_challenges..[[ \ ]] - if dry_run == true then + if dry_run then + local dry_run_dir_url = "https://acme-staging-v02.api.letsencrypt.org/directory" cmd = cmd.." --directory-url "..dry_run_dir_url end + local local_cer_file_str = local_cer_file.canonical().to_string() cmd = cmd.."> "..local_cer_file_str local s = uri("bash:"..cmd).read_text() @@ -141,11 +114,7 @@ catch e logger.error("Error setting up ACME: "..e) finally - if guard_uri and guard_uri.exists() then - guard_uri.delete() - end - local cmd = "rm -rf "..temp_dir_string - local s = uri("bash:"..cmd).read_text() + temp_dir.delete() end_try end @@ -158,8 +127,8 @@ changed = true -- the nginx config only requires 2 files: -- fullchain.cer and DOMAIN.key - local conf = load_file "file:startup/nginx/nginx.ssl.conf.luan" - local nginx = ` conf(luanhost_dir,domain) ` + local conf = load_file(luanhost_file.."startup/nginx/nginx.ssl.conf.luan") + local nginx = ` conf(luanhost_dir_str,domain) ` nginx_file.write(nginx) end end @@ -179,12 +148,34 @@ end if changed then local cmd = [[ -sudo $(which nginx) -t -c "]]..luanhost_dir..[[/local/nginx.conf" && \ -sudo $(which nginx) -s reload -c "]]..luanhost_dir..[[/local/nginx.conf"; +sudo $(which nginx) -t -c "]]..luanhost_dir_str..[[/local/nginx.conf" && \ +sudo $(which nginx) -s reload -c "]]..luanhost_dir_str..[[/local/nginx.conf"; ]] local s = uri("bash:"..cmd).read_text() logger.info("reload_nginx "..s) end --logger.info "done" end +Hosted.do_set_https = do_set_https -- for testing + +function Hosted.set_https(is_https) + if Http.did_init() then + logger.error(new_error("set_https called outside of init.luan")) + return + end + local domain = Http.domain + local site_dir = uri("site:").parent() + local luanhost_dir = uri("file:.") + + -- use for testing, so as to not hit rate limits + -- on the real letsencrypt servers + local dry_run = false + + if not try_synchronized( function() + do_set_https(is_https,domain,site_dir,luanhost_dir,dry_run) + end, domain..".lock", 0 )() then + logger.info("set_https already running for "..domain..", skipping") + end +end + Hosted.set_https = Boot.no_security(Hosted.set_https)
