diff options
-rw-r--r-- | certs/Makefile | 42 | ||||
-rw-r--r-- | man/Makefile | 4 | ||||
-rw-r--r-- | man/prosodyctl.man | 195 | ||||
-rw-r--r-- | man/prosodyctl.markdown | 127 | ||||
-rw-r--r-- | plugins/mod_register.lua | 52 | ||||
-rw-r--r-- | tests/test.lua | 1 | ||||
-rw-r--r-- | tests/test_util_cache.lua | 55 | ||||
-rw-r--r-- | tests/test_util_throttle.lua | 34 | ||||
-rw-r--r-- | util/array.lua | 26 | ||||
-rw-r--r-- | util/cache.lua | 11 | ||||
-rw-r--r-- | util/openssl.lua | 34 |
11 files changed, 452 insertions, 129 deletions
diff --git a/certs/Makefile b/certs/Makefile index f3854c5f..96361748 100644 --- a/certs/Makefile +++ b/certs/Makefile @@ -15,16 +15,48 @@ keysize=2048 # To request a cert %.csr: %.cnf %.key - openssl req -new -key $(lastword $^) -out $@ -utf8 -config $(firstword $^) + openssl req -new -key $(lastword $^) \ + -sha256 -utf8 -config $(firstword $^) -out $@ + +%.csr: %.cnf + umask 0077 && touch $*.key + openssl req -new -newkey rsa:$(keysize) -nodes -keyout $*.key \ + -sha256 -utf8 -config $^ -out $@ + @chmod 400 $*.key -c + +%.csr: %.key + openssl req -new -key $^ -utf8 -subj /CN=$* -out $@ + +%.csr: + umask 0077 && touch $*.key + openssl req -new -newkey rsa:$(keysize) -nodes -keyout $*.key \ + -utf8 -subj /CN=$* -out $@ + @chmod 400 $*.key -c # Self signed %.crt: %.cnf %.key - openssl req -new -x509 -nodes -key $(lastword $^) -days 365 \ - -sha1 -out $@ -utf8 -config $(firstword $^) + openssl req -new -x509 -key $(lastword $^) -days 365 -sha256 -utf8 \ + -config $(firstword $^) -out $@ + +%.crt: %.cnf + umask 0077 && touch $*.key + openssl req -new -x509 -newkey rsa:$(keysize) -nodes -keyout $*.key \ + -days 365 -sha256 -utf8 -config $(firstword $^) -out $@ + @chmod 400 $*.key -c + +%.crt: %.key + openssl req -new -x509 -key $^ -days 365 -sha256 -utf8 -subj /CN=$* -out $@ + +%.crt: + umask 0077 && touch $*.key + openssl req -new -x509 -newkey rsa:$(keysize) -nodes -keyout $*.key \ + -days 365 -sha256 -out $@ -utf8 -subj /CN=$* + @chmod 400 $*.key -c +# Generate a config from the example %.cnf: sed 's,example\.com,$*,g' openssl.cnf > $@ %.key: - openssl genrsa $(keysize) > $@ - @chmod 400 $@ + umask 0077 && openssl genrsa -out $@ $(keysize) + @chmod 400 $@ -c diff --git a/man/Makefile b/man/Makefile new file mode 100644 index 00000000..79bdd90a --- /dev/null +++ b/man/Makefile @@ -0,0 +1,4 @@ +all: prosodyctl.man + +%.man: %.markdown + pandoc -s -t man -o $@ $^ diff --git a/man/prosodyctl.man b/man/prosodyctl.man index 6dcb04cd..b91502a8 100644 --- a/man/prosodyctl.man +++ b/man/prosodyctl.man @@ -1,83 +1,140 @@ -.TH PROSODYCTL 1 "2009-07-02" - +.\" Automatically generated by Pandoc 1.15.2 +.\" +.hy +.TH "PROSODYCTL" "1" "2015\-12\-23" "" "" .SH NAME +.PP prosodyctl \- Manage a Prosody XMPP server - .SH SYNOPSIS -\fBprosodyctl\fP \fIcommand\fP [\fI--help\fP] - +.IP +.nf +\f[C] +prosodyctl\ command\ [\-\-help] +\f[] +.fi .SH DESCRIPTION -\fBprosodyctl\fP is the control tool for the Prosody XMPP server. It may be -used to control the server daemon and manage users. - -\fBprosodyctl\fP needs to be executed with sufficient privileges to perform -its commands. This typically means executing \fBprosodyctl\fP as the root user. -If a user named "prosody" is found then \fBprosodyctl\fP will change to that +.PP +prosodyctl is the control tool for the Prosody XMPP server. +It may be used to control the server daemon and manage users. +.PP +prosodyctl needs to be executed with sufficient privileges to perform +its commands. +This typically means executing prosodyctl as the root user. +If a user named "prosody" is found then prosodyctl will change to that user before executing its commands. - .SH COMMANDS .SS User Management -In the following commands users are identified by a Jabber ID, \fIjid\fP, of the -usual form: user@domain. - -.IP "\fBadduser\fP \fIjid\fP" -Adds a user with Jabber ID, \fIjid\fP, to the server. You will be -prompted to enter the user's password. - -.IP "\fBpasswd\fP \fIjid\fP" -Changes the password of an existing user with Jabber ID, \fIjid\fP. You will be -prompted to enter the user's new password. - -.IP "\fBdeluser\fP \fIjid\fP" -Deletes an existing user with Jabber ID, \fIjid\fP, from the server. - +.PP +In the following commands users are identified by a Jabber ID, jid, of +the usual form: user\@domain. +.TP +.B adduser jid +Adds a user with Jabber ID, jid, to the server. +You will be prompted to enter the user\[aq]s password. +.RS +.RE +.TP +.B passwd jid +Changes the password of an existing user with Jabber ID, jid. +You will be prompted to enter the user\[aq]s new password. +.RS +.RE +.TP +.B deluser jid +Deletes an existing user with Jabber ID, jid, from the server. +.RS +.RE .SS Daemon Management -Although \fBprosodyctl\fP has commands to manage the \fBprosody\fP daemon it is -recommended that you utilize your distributions daemon management features if -you attained Prosody through a package. - -To perform daemon control commands \fBprosodyctl\fP needs a \fIpidfile\fP value -specified in \fI/etc/prosody/prosody.cfg.lua\fP. Failure to do so will cause -\fBprosodyctl\fP to complain. - -.IP \fBstart\fP -Starts the \fBprosody\fP server daemon. If run as root \fBprosodyctl\fP will -attempt to change to a user named "prosody" before executing. This operation -will block for up to five seconds to wait for the server to execute. - -.IP \fBstop\fP -Stops the \fBprosody\fP server daemon. This operation will block for up to five -seconds to wait for the server to stop executing. - -.IP \fBrestart\fP -Restarts the \fBprosody\fP server daemon. Equivalent to running \fBprosodyctl -stop\fP followed by \fBprosodyctl start\fP. - -.IP \fBstatus\fP -Prints the current execution status of the \fBprosody\fP server daemon. - +.PP +Although prosodyctl has commands to manage the prosody daemon it is +recommended that you utilize your distributions daemon management +features if you attained Prosody through a package. +.PP +To perform daemon control commands prosodyctl needs a pidfile value +specified in \f[C]/etc/prosody/prosody.cfg.lua\f[]. +Failure to do so will cause prosodyctl to complain. +.TP +.B start +Starts the prosody server daemon. +If run as root prosodyctl will attempt to change to a user named +"prosody" before executing. +This operation will block for up to five seconds to wait for the server +to execute. +.RS +.RE +.TP +.B stop +Stops the prosody server daemon. +This operation will block for up to five seconds to wait for the server +to stop executing. +.RS +.RE +.TP +.B restart +Restarts the prosody server daemon. +Equivalent to running prosodyctl stop followed by prosodyctl start. +.RS +.RE +.TP +.B reload +Signals the prosody server daemon to reload configuration and reopen log +files. +.RS +.RE +.TP +.B status +Prints the current execution status of the prosody server daemon. +.RS +.RE +.SS Debugging +.PP +prosodyctl can also show some information about the environment, +dependencies and such to aid in debugging. +.TP +.B about +Shows environment, various paths used by Prosody and installed +dependencies. +.RS +.RE +.TP +.B check [what] +Performs various sanity checks on the configuration, DNS setup and +configured TLS certificates. +\f[C]what\f[] can be one of \f[C]config\f[], \f[C]dns\f[] and +\f[C]certs\f[] to run only that check. +.RS +.RE .SS Ejabberd Compatibility -\fBejabberd\fP is another XMPP server which provides a comparable control tool, -\fBejabberdctl\fP, to control its server's operations. \fBprosodyctl\fP -implements some commands which are compatible with \fBejabberdctl\fP. For -details of how these commands work you should see -.BR ejabberdctl (8). - -.IP "\fBregister\fP \fIuser server password\fP" -.IP "\fBunregister\fP \fIuser server\fP" - +.PP +ejabberd is another XMPP server which provides a comparable control +tool, ejabberdctl, to control its server\[aq]s operations. +prosodyctl implements some commands which are compatible with +ejabberdctl. +For details of how these commands work you should see ejabberdctl(8). +.IP +.nf +\f[C] +register\ user\ server\ password + +unregister\ user\ server +\f[] +.fi .SH OPTIONS -.IP \fI--help\fP +.TP +.B \f[C]\-\-help\f[] Display help text for the specified command. - +.RS +.RE .SH FILES -.IP \fI/etc/prosody/prosody.cfg.lua\fP -The main \fBprosody\fP configuration file. \fBprosodyctl\fP reads this to -determine the process ID file of the \fBprosody\fP server daemon and to -determine if a host has been configured. - +.TP +.B \f[C]/etc/prosody/prosody.cfg.lua\f[] +The main prosody configuration file. +prosodyctl reads this to determine the process ID file of the prosody +server daemon and to determine if a host has been configured. +.RS +.RE .SH ONLINE -More information may be found online at: \fIhttp://prosody.im/\fP - +.PP +More information may be found online at: <https://prosody.im/> .SH AUTHORS -Dwayne Bent <dbb.1@liqd.org> +Dwayne Bent <dbb.1@liqd.org>; Kim Alvefur. diff --git a/man/prosodyctl.markdown b/man/prosodyctl.markdown new file mode 100644 index 00000000..217dfd3d --- /dev/null +++ b/man/prosodyctl.markdown @@ -0,0 +1,127 @@ +--- +author: +- 'Dwayne Bent <dbb.1@liqd.org>' +- Kim Alvefur +date: '2015-12-23' +section: 1 +title: PROSODYCTL +... + +NAME +==== + +prosodyctl - Manage a Prosody XMPP server + +SYNOPSIS +======== + + prosodyctl command [--help] + +DESCRIPTION +=========== + +prosodyctl is the control tool for the Prosody XMPP server. It may be +used to control the server daemon and manage users. + +prosodyctl needs to be executed with sufficient privileges to perform +its commands. This typically means executing prosodyctl as the root +user. If a user named "prosody" is found then prosodyctl will change to +that user before executing its commands. + +COMMANDS +======== + +User Management +--------------- + +In the following commands users are identified by a Jabber ID, jid, of +the usual form: user@domain. + +adduser jid +: Adds a user with Jabber ID, jid, to the server. You will be prompted + to enter the user's password. + +passwd jid +: Changes the password of an existing user with Jabber ID, jid. You + will be prompted to enter the user's new password. + +deluser jid +: Deletes an existing user with Jabber ID, jid, from the server. + +Daemon Management +----------------- + +Although prosodyctl has commands to manage the prosody daemon it is +recommended that you utilize your distributions daemon management +features if you attained Prosody through a package. + +To perform daemon control commands prosodyctl needs a pidfile value +specified in `/etc/prosody/prosody.cfg.lua`. Failure to do so will cause +prosodyctl to complain. + +start +: Starts the prosody server daemon. If run as root prosodyctl will + attempt to change to a user named "prosody" before executing. This + operation will block for up to five seconds to wait for the server + to execute. + +stop +: Stops the prosody server daemon. This operation will block for up to + five seconds to wait for the server to stop executing. + +restart +: Restarts the prosody server daemon. Equivalent to running prosodyctl + stop followed by prosodyctl start. + +reload +: Signals the prosody server daemon to reload configuration and reopen + log files. + +status +: Prints the current execution status of the prosody server daemon. + +Debugging +--------- + +prosodyctl can also show some information about the environment, +dependencies and such to aid in debugging. + +about +: Shows environment, various paths used by Prosody and + installed dependencies. + +check \[what\] +: Performs various sanity checks on the configuration, DNS setup and + configured TLS certificates. `what` can be one of `config`, `dns` + and `certs` to run only that check. + +Ejabberd Compatibility +---------------------- + +ejabberd is another XMPP server which provides a comparable control +tool, ejabberdctl, to control its server's operations. prosodyctl +implements some commands which are compatible with ejabberdctl. For +details of how these commands work you should see ejabberdctl(8). + + register user server password + + unregister user server + +OPTIONS +======= + +`--help` +: Display help text for the specified command. + +FILES +===== + +`/etc/prosody/prosody.cfg.lua` +: The main prosody configuration file. prosodyctl reads this to + determine the process ID file of the prosody server daemon and to + determine if a host has been configured. + +ONLINE +====== + +More information may be found online at: <https://prosody.im/> diff --git a/plugins/mod_register.lua b/plugins/mod_register.lua index e537e903..1961b276 100644 --- a/plugins/mod_register.lua +++ b/plugins/mod_register.lua @@ -13,9 +13,10 @@ local usermanager_user_exists = require "core.usermanager".user_exists; local usermanager_create_user = require "core.usermanager".create_user; local usermanager_set_password = require "core.usermanager".set_password; local usermanager_delete_user = require "core.usermanager".delete_user; -local os_time = os.time; local nodeprep = require "util.encodings".stringprep.nodeprep; local jid_bare = require "util.jid".bare; +local create_throttle = require "util.throttle".create; +local new_cache = require "util.cache".new; local compat = module:get_option_boolean("registration_compat", true); local allow_registration = module:get_option_boolean("allow_registration", false); @@ -84,6 +85,7 @@ end); local function handle_registration_stanza(event) local session, stanza = event.origin, event.stanza; + local log = session.log or module._log; local query = stanza.tags[1]; if stanza.attr.type == "get" then @@ -97,6 +99,7 @@ local function handle_registration_stanza(event) if query.tags[1] and query.tags[1].name == "remove" then local username, host = session.username, session.host; + -- This one weird trick sends a reply to this stanza before the user is deleted local old_session_close = session.close; session.close = function(session, ...) session.send(st.reply(stanza)); @@ -106,13 +109,13 @@ local function handle_registration_stanza(event) local ok, err = usermanager_delete_user(username, host); if not ok then - module:log("debug", "Removing user account %s@%s failed: %s", username, host, err); + log("debug", "Removing user account %s@%s failed: %s", username, host, err); session.close = old_session_close; session.send(st.error_reply(stanza, "cancel", "service-unavailable", err)); return true; end - module:log("info", "User removed their account: %s@%s", username, host); + log("info", "User removed their account: %s@%s", username, host); module:fire_event("user-deregistered", { username = username, host = host, source = "mod_register", session = session }); else local username = nodeprep(query:get_child_text("username")); @@ -169,14 +172,36 @@ local function parse_response(query) end end -local recent_ips = {}; local min_seconds_between_registrations = module:get_option_number("min_seconds_between_registrations"); local whitelist_only = module:get_option_boolean("whitelist_registration_only"); local whitelisted_ips = module:get_option_set("registration_whitelist", { "127.0.0.1" })._items; local blacklisted_ips = module:get_option_set("registration_blacklist", {})._items; +local throttle_max = module:get_option_number("registration_throttle_max", min_seconds_between_registrations and 1); +local throttle_period = module:get_option_number("registration_throttle_period", min_seconds_between_registrations); +local throttle_cache_size = module:get_option_number("registration_throttle_cache_size", 100); +local blacklist_overflow = module_get_option_boolean("blacklist_on_registration_throttle_overload", false); + +local throttle_cache = new_cache(throttle_cache_size, blacklist_overflow and function (ip, throttle) + if not throttle:peek() then + module:log("info", "Adding ip %s to registration blacklist", ip); + blacklisted_ips[ip] = true; + end +end); + +local function check_throttle(ip) + if not throttle_max then return true end + local throttle = throttle_cache:get(ip); + if not throttle then + throttle = create_throttle(throttle_max, throttle_period); + end + throttle_cache:set(ip, throttle); + return throttle:poll(1); +end + module:hook("stanza/iq/jabber:iq:register:query", function(event) local session, stanza = event.origin, event.stanza; + local log = session.log or module._log; if not(allow_registration) or session.type ~= "c2s_unauthed" then session.send(st.error_reply(stanza, "cancel", "service-unavailable")); @@ -196,23 +221,14 @@ module:hook("stanza/iq/jabber:iq:register:query", function(event) else -- Check that the user is not blacklisted or registering too often if not session.ip then - module:log("debug", "User's IP not known; can't apply blacklist/whitelist"); + log("debug", "User's IP not known; can't apply blacklist/whitelist"); elseif blacklisted_ips[session.ip] or (whitelist_only and not whitelisted_ips[session.ip]) then session.send(st.error_reply(stanza, "cancel", "not-acceptable", "You are not allowed to register an account.")); return true; elseif min_seconds_between_registrations and not whitelisted_ips[session.ip] then - if not recent_ips[session.ip] then - recent_ips[session.ip] = { time = os_time(), count = 1 }; - else - local ip = recent_ips[session.ip]; - ip.count = ip.count + 1; - - if os_time() - ip.time < min_seconds_between_registrations then - ip.time = os_time(); - session.send(st.error_reply(stanza, "wait", "not-acceptable")); - return true; - end - ip.time = os_time(); + if check_throttle(session.ip) then + session.send(st.error_reply(stanza, "wait", "not-acceptable")); + return true; end end local username, password = nodeprep(data.username), data.password; @@ -238,7 +254,7 @@ module:hook("stanza/iq/jabber:iq:register:query", function(event) return true; end session.send(st.reply(stanza)); -- user created! - module:log("info", "User account created: %s@%s", username, host); + log("info", "User account created: %s@%s", username, host); module:fire_event("user-registered", { username = username, host = host, source = "mod_register", session = session }); diff --git a/tests/test.lua b/tests/test.lua index f7fdee91..1666fcf5 100644 --- a/tests/test.lua +++ b/tests/test.lua @@ -21,6 +21,7 @@ function run_all_tests() dotest "util.stanza" dotest "util.sasl.scram" dotest "util.cache" + dotest "util.throttle" dosingletest("test_sasl.lua", "latin1toutf8"); dosingletest("test_utf8.lua", "valid"); diff --git a/tests/test_util_cache.lua b/tests/test_util_cache.lua index a174eea7..72cb5a85 100644 --- a/tests/test_util_cache.lua +++ b/tests/test_util_cache.lua @@ -170,5 +170,60 @@ function new(new) end assert_equal(i, 4); + local evicted_key, evicted_value; + local c = new(3, function (_key, _value) + evicted_key, evicted_value = _key, _value; + end); + local function set(k, v, should_evict_key, should_evict_value) + evicted_key, evicted_value = nil, nil; + c:set(k, v); + assert_equal(evicted_key, should_evict_key); + assert_equal(evicted_value, should_evict_value); + end + set("a", 1) + set("a", 1) + set("a", 1) + set("a", 1) + set("a", 1) + + set("b", 2) + set("c", 3) + set("b", 2) + set("d", 4, "a", 1) + set("e", 5, "c", 3) + + + local evicted_key, evicted_value; + local c3 = new(1, function (_key, _value, c3) + evicted_key, evicted_value = _key, _value; + if _key == "a" then + -- Put it back in... + -- Check that the newest key/value was set before on_evict was called + assert_equal(c3:get("b"), 2); + -- Sanity check for what we're evicting + assert_equal(_key, "a"); + assert_equal(_value, 1); + -- Re-insert the evicted key (causes this evict function to run again with "b",2) + c3:set(_key, _value) + assert_equal(c3:get(_key), _value) + end + end); + local function set(k, v, should_evict_key, should_evict_value) + evicted_key, evicted_value = nil, nil; + c3:set(k, v); + assert_equal(evicted_key, should_evict_key); + assert_equal(evicted_value, should_evict_value); + end + set("a", 1) + set("a", 1) + set("a", 1) + set("a", 1) + set("a", 1) + -- The evict handler re-inserts "a"->1, so "b" gets evicted: + set("b", 2, "b", 2) + -- Check the final state is what we expect + assert_equal(c3:get("a"), 1); + assert_equal(c3:get("b"), nil); + assert_equal(c3:count(), 1); end diff --git a/tests/test_util_throttle.lua b/tests/test_util_throttle.lua new file mode 100644 index 00000000..582f499d --- /dev/null +++ b/tests/test_util_throttle.lua @@ -0,0 +1,34 @@ + +local now = 0; -- wibbly-wobbly... timey-wimey... stuff +local function predictable_gettime() + return now; +end +local function later(n) + now = now + n; -- time passes at a different rate +end + +local function override_gettime(throttle) + local i = 0; + repeat + i = i + 1; + local name = debug.getupvalue(throttle.update, i); + if name then + debug.setupvalue(throttle.update, i, predictable_gettime); + return throttle; + end + until not name; +end + +function create(create) + local a = override_gettime( create(3, 10) ); + + assert_equal(a:poll(1), true); -- 3 -> 2 + assert_equal(a:poll(1), true); -- 2 -> 1 + assert_equal(a:poll(1), true); -- 1 -> 0 + assert_equal(a:poll(1), false); -- MEEP, out of credits! + later(1); -- ... what about + assert_equal(a:poll(1), false); -- now? - Still no! + later(9); -- Later that day + assert_equal(a:poll(1), true); -- Should be back at 3 credits ... 2 +end + diff --git a/util/array.lua b/util/array.lua index d4ab1771..3ddc97f6 100644 --- a/util/array.lua +++ b/util/array.lua @@ -37,7 +37,7 @@ setmetatable(array, { __call = new_array }); -- Read-only methods function array_methods:random() - return self[math_random(1,#self)]; + return self[math_random(1, #self)]; end -- These methods can be called two ways: @@ -45,7 +45,7 @@ end -- existing_array:method([params, ...]) -- Transform existing array into result -- function array_base.map(outa, ina, func) - for k,v in ipairs(ina) do + for k, v in ipairs(ina) do outa[k] = func(v); end return outa; @@ -54,7 +54,7 @@ end function array_base.filter(outa, ina, func) local inplace, start_length = ina == outa, #ina; local write = 1; - for read=1,start_length do + for read = 1, start_length do local v = ina[read]; if func(v) then outa[write] = v; @@ -63,7 +63,7 @@ function array_base.filter(outa, ina, func) end if inplace and write <= start_length then - for i=write,start_length do + for i = write, start_length do outa[i] = nil; end end @@ -80,7 +80,7 @@ function array_base.sort(outa, ina, ...) end function array_base.pluck(outa, ina, key) - for i=1,#ina do + for i = 1, #ina do outa[i] = ina[i][key]; end return outa; @@ -108,16 +108,16 @@ end --- These methods only mutate the array function array_methods:shuffle(outa, ina) local len = #self; - for i=1,#self do - local r = math_random(i,len); + for i = 1, #self do + local r = math_random(i, len); self[i], self[r] = self[r], self[i]; end return self; end function array_methods:append(array) - local len,len2 = #self, #array; - for i=1,len2 do + local len, len2 = #self, #array; + for i = 1, len2 do self[len+i] = array[i]; end return self; @@ -128,11 +128,7 @@ function array_methods:push(x) return self; end -function array_methods:pop(x) - local v = self[x]; - t_remove(self, x); - return v; -end +array_methods.pop = t_remove; function array_methods:concat(sep) return t_concat(array.map(self, tostring), sep); @@ -147,7 +143,7 @@ function array.collect(f, s, var) local t = {}; while true do var = f(s, var); - if var == nil then break; end + if var == nil then break; end t_insert(t, var); end return setmetatable(t, array_mt); diff --git a/util/cache.lua b/util/cache.lua index 72b74351..d3639b3f 100644 --- a/util/cache.lua +++ b/util/cache.lua @@ -51,19 +51,20 @@ function cache_methods:set(k, v) return true; end -- Check whether we need to remove oldest k/v + local on_evict, evicted_key, evicted_value; if self._count == self.size then local tail = self._tail; - local on_evict = self._on_evict; - if on_evict then - on_evict(tail.key, tail.value); - end + on_evict, evicted_key, evicted_value = self._on_evict, tail.key, tail.value; _remove(self, tail); - self._data[tail.key] = nil; + self._data[evicted_key] = nil; end m = { key = k, value = v, prev = nil, next = nil }; self._data[k] = m; _insert(self, m); + if on_evict and evicted_key then + on_evict(evicted_key, evicted_value, self); + end return true; end diff --git a/util/openssl.lua b/util/openssl.lua index 39fe99d6..12e49eac 100644 --- a/util/openssl.lua +++ b/util/openssl.lua @@ -12,7 +12,7 @@ local config = {}; _M.config = config; local ssl_config = {}; -local ssl_config_mt = {__index=ssl_config}; +local ssl_config_mt = { __index = ssl_config }; function config.new() return setmetatable({ @@ -65,12 +65,12 @@ function ssl_config:serialize() s = s .. ("[%s]\n"):format(k); if k == "subject_alternative_name" then for san, n in pairs(t) do - for i = 1,#n do + for i = 1, #n do s = s .. s_format("%s.%d = %s\n", san, i -1, n[i]); end end elseif k == "distinguished_name" then - for i=1,#DN_order do + for i=1, #DN_order do local k = DN_order[i] local v = t[k]; if v then @@ -107,7 +107,7 @@ end function ssl_config:add_sRVName(host, service) t_insert(self.subject_alternative_name.otherName, - s_format("%s;%s", oid_dnssrv, ia5string("_" .. service .."." .. idna_to_ascii(host)))); + s_format("%s;%s", oid_dnssrv, ia5string("_" .. service .. "." .. idna_to_ascii(host)))); end function ssl_config:add_xmppAddr(host) @@ -118,10 +118,10 @@ end function ssl_config:from_prosody(hosts, config, certhosts) -- TODO Decide if this should go elsewhere local found_matching_hosts = false; - for i = 1,#certhosts do + for i = 1, #certhosts do local certhost = certhosts[i]; for name in pairs(hosts) do - if name == certhost or name:sub(-1-#certhost) == "."..certhost then + if name == certhost or name:sub(-1-#certhost) == "." .. certhost then found_matching_hosts = true; self:add_dNSName(name); --print(name .. "#component_module: " .. (config.get(name, "component_module") or "nil")); @@ -144,30 +144,30 @@ end do -- Lua to shell calls. local function shell_escape(s) - return s:gsub("'",[['\'']]); + return "'" .. tostring(s):gsub("'",[['\'']]) .. "'"; end - local function serialize(f,o) - local r = {"openssl", f}; - for k,v in pairs(o) do + local function serialize(command, args) + local commandline = { "openssl", command }; + for k, v in pairs(args) do if type(k) == "string" then - t_insert(r, ("-%s"):format(k)); + t_insert(commandline, ("-%s"):format(k)); if v ~= true then - t_insert(r, ("'%s'"):format(shell_escape(tostring(v)))); + t_insert(commandline, shell_escape(v)); end end end - for _,v in ipairs(o) do - t_insert(r, ("'%s'"):format(shell_escape(tostring(v)))); + for _, v in ipairs(args) do + t_insert(commandline, shell_escape(v)); end - return t_concat(r, " "); + return t_concat(commandline, " "); end local os_execute = os.execute; setmetatable(_M, { - __index=function(_,f) + __index = function(_, command) return function(opts) - return 0 == os_execute(serialize(f, type(opts) == "table" and opts or {})); + return 0 == os_execute(serialize(command, type(opts) == "table" and opts or {})); end; end; }); |