Merge 0.10->trunk
authorKim Alvefur <zash@zash.se>
Sun, 27 Dec 2015 11:29:28 +0000 (12:29 +0100)
committerKim Alvefur <zash@zash.se>
Sun, 27 Dec 2015 11:29:28 +0000 (12:29 +0100)
certs/Makefile
man/Makefile [new file with mode: 0644]
man/prosodyctl.man
man/prosodyctl.markdown [new file with mode: 0644]
plugins/mod_register.lua
tests/test.lua
tests/test_util_cache.lua
tests/test_util_throttle.lua [new file with mode: 0644]
util/array.lua
util/cache.lua
util/openssl.lua

index f3854c5f98b9b5143d654d933f4cb8c031d34628..96361748e7c06a44e2ca7318c7ac8d187dccb931 100644 (file)
@@ -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 (file)
index 0000000..79bdd90
--- /dev/null
@@ -0,0 +1,4 @@
+all: prosodyctl.man
+
+%.man: %.markdown
+       pandoc -s -t man -o $@ $^
index 6dcb04cda678feb9d403844d79df32ef346c87bb..b91502a846ae746c5eeb6a2cf0ce254cb5804759 100644 (file)
-.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 (file)
index 0000000..217dfd3
--- /dev/null
@@ -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/>
index e537e9036cb11e38e78b0b683f0e99f8da215e33..1961b27654743b65d4eedb48a10b7cc43663e9cf 100644 (file)
@@ -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 });
index f7fdee91308ad948054eaae0b50f60a7cb1a83f1..1666fcf5199e8de327b05db19cb78162e03e6bff 100644 (file)
@@ -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");
index a174eea757383d5d521074ce86d540197716c528..72cb5a856ed486cf437e05c588edad228fd2bdfb 100644 (file)
@@ -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 (file)
index 0000000..582f499
--- /dev/null
@@ -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
+
index d4ab1771111cb543db105942892005177dbbd612..3ddc97f610172008a3046c75a7a6a0b9aaf6d258 100644 (file)
@@ -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);
index 72b74351a37733e2374abb6b0a5b602043ff3f71..d3639b3f7aebc791bfdf8b57d395af810b03e25e 100644 (file)
@@ -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
 
index 39fe99d6abf3013112259fda1e876e8ed894ee1c..12e49eac2ef5efa8f96c266a758f72ad327ef3f0 100644 (file)
@@ -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;
        });