| 0 | 1 local Luan = require "luan:Luan.luan" | 
|  | 2 local error = Luan.error | 
|  | 3 local ipairs = Luan.ipairs or error() | 
|  | 4 local pairs = Luan.pairs or error() | 
|  | 5 local type = Luan.type or error() | 
|  | 6 local set_metatable = Luan.set_metatable or error() | 
|  | 7 local stringify = Luan.stringify or error() | 
|  | 8 local parse = Luan.parse or error() | 
|  | 9 local range = Luan.range or error() | 
|  | 10 local String = require "luan:String.luan" | 
|  | 11 local split = String.split or error() | 
|  | 12 local trim = String.trim or error() | 
|  | 13 local sub_string = String.sub or error() | 
|  | 14 local Table = require "luan:Table.luan" | 
|  | 15 local concat = Table.concat or error() | 
|  | 16 local Math = require "luan:Math.luan" | 
|  | 17 local random = Math.random or error() | 
|  | 18 local Binary = require "luan:Binary.luan" | 
|  | 19 local binary_base64_decode = Binary.base64_decode or error() | 
|  | 20 local binary_to_string = Binary.to_string or error() | 
|  | 21 local Io = require "luan:Io.luan" | 
|  | 22 local uri = Io.uri or error() | 
|  | 23 local Http = require "luan:http/Http.luan" | 
|  | 24 local Logging = require "luan:logging/Logging.luan" | 
|  | 25 local logger = Logging.logger "Shared" | 
|  | 26 | 
|  | 27 | 
|  | 28 local Shared = {} | 
|  | 29 | 
|  | 30 function Shared.head() | 
|  | 31 %> | 
|  | 32 		<meta name="viewport" content="width=device-width, initial-scale=1"> | 
|  | 33 		<style> | 
|  | 34 			@import "/site.css"; | 
|  | 35 		</style> | 
|  | 36 <% | 
|  | 37 end | 
|  | 38 | 
|  | 39 local function header(crumbs) | 
|  | 40 %> | 
|  | 41 		<div header> | 
|  | 42 			<a href="/">Mercurial Hosting</a> | 
|  | 43 <%	for _, crumb in ipairs(crumbs or {}) do %> | 
|  | 44 			/ <%=crumb%> | 
|  | 45 <%	end %> | 
|  | 46 		</div> | 
|  | 47 <% | 
|  | 48 end | 
|  | 49 Shared.header = header | 
|  | 50 | 
|  | 51 function Shared.admin_header() | 
|  | 52 	header{ | 
|  | 53 		[[<a href="/admin/">Your Repositories</a>]] | 
|  | 54 	} | 
|  | 55 end | 
|  | 56 | 
|  | 57 function Shared.private_header() | 
|  | 58 	header{ | 
|  | 59 		[[<a href="/private/">private</a>]] | 
|  | 60 		[[<a href="/private/tools/">tools</a>]] | 
|  | 61 	} | 
|  | 62 end | 
|  | 63 | 
|  | 64 Shared.admin_return = [[<p>Return to <a href="/admin/">Your Repositories</a></p>]] | 
|  | 65 | 
|  | 66 local function base64_decode(s) | 
|  | 67 	return binary_to_string(binary_base64_decode(s)) | 
|  | 68 end | 
|  | 69 | 
|  | 70 function Shared.get_user() | 
|  | 71 	local s = Http.request.headers["Authorization"] or error "not authorized" | 
|  | 72 	local tp, auth = split(s," ") | 
|  | 73 	tp=="Basic" or error("invalid auth type: "..tp) | 
|  | 74 	s = base64_decode(auth) | 
|  | 75 	s = split(s,":") | 
|  | 76 	return s | 
|  | 77 end | 
|  | 78 | 
|  | 79 local function deep_copy(tbl) | 
|  | 80 	local t = {} | 
|  | 81 	for k,v in pairs(tbl) do | 
|  | 82 		if type(v)=="table" then | 
|  | 83 			v = deep_copy(v) | 
|  | 84 		end | 
|  | 85 		t[k] = v | 
|  | 86 	end | 
|  | 87 	return t | 
|  | 88 end | 
|  | 89 | 
|  | 90 local set_mt = {} | 
|  | 91 function set_mt.__index(table,key) | 
|  | 92 	return false | 
|  | 93 end | 
|  | 94 | 
|  | 95 local function list_to_set(list) | 
|  | 96 	local set = {} | 
|  | 97 	for _, v in ipairs(list) do | 
|  | 98 		set[v] = true | 
|  | 99 	end | 
|  | 100 	set_metatable(set,set_mt) | 
|  | 101 	return set | 
|  | 102 end | 
|  | 103 Shared.list_to_set = list_to_set | 
|  | 104 | 
|  | 105 function Shared.text_to_list(text) | 
|  | 106 	local list = {} | 
|  | 107 	for line in Io.schemes.string(text).read_lines() do | 
|  | 108 		line = trim(line) | 
|  | 109 		if line ~= "" then | 
|  | 110 			list[#list+1] = line | 
|  | 111 		end | 
|  | 112 	end | 
|  | 113 	return list | 
|  | 114 end | 
|  | 115 | 
|  | 116 local password_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" | 
|  | 117 do | 
|  | 118 	local t = {} | 
|  | 119 	for i in range(1,#password_chars) do | 
|  | 120 		t[#t+1] = sub_string(password_chars,i,i) | 
|  | 121 	end | 
|  | 122 	password_chars = t | 
|  | 123 end | 
|  | 124 | 
|  | 125 function Shared.new_password() | 
|  | 126 	local n = #password_chars | 
|  | 127 	local t = {} | 
|  | 128 	for _ in range(1,10) do | 
|  | 129 		t[#t+1] = password_chars[random(n)] | 
|  | 130 	end | 
|  | 131 	return concat(t) | 
|  | 132 end | 
|  | 133 | 
|  | 134 local raw_config = parse( uri("file:config/config.luano").read_text() ) | 
|  | 135 local config = deep_copy(raw_config) | 
|  | 136 for name, repo in pairs(config.repos) do | 
|  | 137 	repo.name = name | 
|  | 138 	repo.users = list_to_set(repo.users) | 
|  | 139 	repo.admins = list_to_set(repo.admins) | 
|  | 140 end | 
|  | 141 config.private = config.private and list_to_set(config.private) | 
|  | 142 Shared.config = config | 
|  | 143 | 
| 4 | 144 local user_repos = {} | 
|  | 145 for _, repo in pairs(config.repos) do | 
|  | 146 	for user in pairs(repo.users) do | 
|  | 147 		local repos = user_repos[user] | 
|  | 148 		if repos == nil then | 
|  | 149 			repos = {} | 
|  | 150 			user_repos[user] = repos | 
|  | 151 		end | 
|  | 152 		repos[#repos+1] = repo | 
|  | 153 	end | 
|  | 154 end | 
|  | 155 Shared.user_repos = user_repos | 
|  | 156 | 
| 0 | 157 function Shared.get_raw_config() | 
|  | 158 	return deep_copy(raw_config) | 
|  | 159 end | 
|  | 160 | 
|  | 161 local function reload_nginx() | 
|  | 162 	local cmd = [[sudo $(which nginx) -s reload]] | 
|  | 163 	local s = uri("bash:"..cmd).read_text() | 
|  | 164 	logger.info("reload_nginx "..s) | 
|  | 165 end | 
|  | 166 | 
|  | 167 function Shared.save_raw_config(raw_config) | 
|  | 168 	local config_file = uri("file:config/config.luano") | 
|  | 169 	local config_old = uri("file:config/config.luano.old") | 
|  | 170 	config_old.delete() | 
|  | 171 	config_file.move_to(config_old) | 
|  | 172 	config_file.write_text(stringify(raw_config).."\n") | 
|  | 173 	Http.reset_luan() | 
|  | 174 	Luan.do_file "update_repositories.luan" | 
|  | 175 	reload_nginx() | 
|  | 176 end | 
|  | 177 | 
|  | 178 return Shared |