view update_repositories.luan @ 16:50a1fe272c10

more security
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 01 Oct 2023 21:36:34 -0600
parents c560b4e2f056
children
line wrap: on
line source

local Luan = require "luan:Luan.luan"
local error = Luan.error
local pairs = Luan.pairs or error()
local ipairs = Luan.ipairs or error()
local parse = Luan.parse or error()
local stringify = Luan.stringify or error()
local Io = require "luan:Io.luan"
local uri = Io.uri or error()
local output_of = Io.output_of or error()
local print_to = Io.print_to or error()
local String = require "luan:String.luan"
local trim = String.trim or error()
local Logging = require "luan:logging/Logging.luan"
local logger = Logging.logger "update_repositories"

uri("file:repos").mkdir()
uri("file:logs").mkdir()
uri("file:config").mkdir()

local config
local config_file = uri "file:config/config.luano"
if config_file.exists() then
	config = parse( config_file.read_text() )
else
	config = { users={}, repos={} }
	config_file.write_text( stringify(config).."\n" )
end
local repos = config.repos
for name, repo in pairs(repos) do
	repo.name = name
end

local ROOTPWD = uri("file:.").canonical().to_string()
local repohome = uri("file:repos").canonical().to_string()
local logsdir = uri("file:logs").canonical().to_string()
local nginxauthdir = uri("file:config/nginx").canonical().to_string()

-- init new repositories
for repo in pairs(repos) do
	if not uri("file:repos/"..repo).exists() then
		logger.info("creating repo "..repo)
		uri("bash:/usr/local/bin/hg init repos/"..repo).read_text()
	end
end
-- delete unused repos
for _, child in ipairs( uri("file:repos").children() ) do
	local name = child.name()
	if repos[name] == nil then
		logger.info("deleting repo "..name)
		child.delete()
	end
end

-- update hg config
uri("file:config/web.config").write_text( output_of( function() %>
[web]
allow_push = *
push_ssl = false
staticurl = /hg/static
[paths]
/repo/ = <%=repohome%>/*
<% end_function ) )

-- update nginx config
uri("file:config/nginx.conf").write_text( output_of( function() %>
	location /hg/static/ {
		alias <%=ROOTPWD%>/templates/static/;
	}

	location /admin/ {
		auth_basic_user_file <%=nginxauthdir%>/_all.pass;
		auth_basic "Restricted";
		proxy_pass http://127.0.0.1:8080;
	}

	location /private/ {
		auth_basic_user_file <%=nginxauthdir%>/_private.pass;
		auth_basic "Restricted";
		proxy_pass http://127.0.0.1:8080;
	}

<% for _, repo in pairs(repos) do %>
	location /repo/<%=repo.name%>/
	{
		set $auth "off";
		auth_basic_user_file <%=nginxauthdir%>/<%=repo.name%>.pass;
		if ($request_method = POST ) {
			set $auth "Restricted";
		}
		access_log  <%=logsdir%>/repos/<%=repo.name%>_access_log;
		error_log   <%=logsdir%>/repos/<%=repo.name%>_error_log;
<%	if repo.mode=="private" then %>
		if ($request_method = GET ) {
			set $auth "Restricted";
		}
<%	end %>
		auth_basic           $auth;
		proxy_pass http://127.0.0.1:8090;
	}
<% end
end_function ) )

-- passwords
local nginx_dir = uri("file:config/nginx")
nginx_dir.delete()
nginx_dir.mkdir()
local htpasswds = {}
do
	local writer = nginx_dir.child("_all.pass").text_writer()
	for user, password in pairs(config.users) do
		local htpasswd = uri("bash:htpasswd -nb '"..user.."' '"..password.."'").read_text()
		htpasswd = trim(htpasswd)
		print_to( writer, htpasswd )
		htpasswds[user] = htpasswd
	end
	writer.close()
end
for _, repo in pairs(repos) do
	local writer = nginx_dir.child(repo.name..".pass").text_writer()
	for _, user_name in ipairs(repo.users) do
		local htpasswd = htpasswds[user_name] or error(user_name)
		print_to( writer, htpasswd )
	end
	writer.close()
end
local private = config.private
if private == nil then
	local all = nginx_dir.child("_all.pass")
	local private = nginx_dir.child("_private.pass")
	all.copy_to(private)
else
	local writer = nginx_dir.child("_private.pass").text_writer()
	for _, user_name in ipairs(private) do
		local htpasswd = htpasswds[user_name] or error(user_name)
		print_to( writer, htpasswd )
	end
	writer.close()
end

-- private
uri("file:src/private").mkdir()
do
	local private_logs = uri "file:src/private/logs"
	if not private_logs.exists() then
		local logs = uri("file:logs").canonical()
		logs.symlink_from(private_logs)
		logger.info "linked to logs"
	end
end
do
	local private_config = uri "file:src/private/config"
	if not private_config.exists() then
		local config = uri("file:config").canonical()
		config.symlink_from(private_config)
		logger.info "linked to config"
	end
end