mod_external_services API

mod_external_services allows other modules to add items via the items API, as well as events.

Items API

Services added via the items API are subject to the same processing as those added via config file. Fields with the wrong type are ignored and time based credentials can be generated from a supplied secret.

Credentials, if required, can be supplied in several ways:

  • Static password
  • Generated from a shared secret
  • Generated by a credentials_cb() function
  • Generated in external_service/credentials event (can be async)
module:add_item("external_service", {
    type = "ftp",
    transport = "tcp",
    host = "ftp.example.net",
    port = 21,

    ttl = 300,

    -- static credentials:
    username = "jdoe",
    password = "changeme",

    -- shared secret
    secret = "secr3t",
    algorithm = "turn",

    -- callback
    credentials_cb = function (srv)
        srv.username = random_username(),
        srv.password = random_password(),
    end
})

Obs! Only use one of the above credentials methods.

Shared secret algorithms

Currently only one algorithm is available:

turn
Time based algorithm from REST API for TURN services

Other processing

For time-limited credentials, a ttl field may be set to the number of seconds that the credentials remain valid. It later gets translated into an expires timestamp.

Event API

Two kinds of events are fired, corresponding to the two commands described in XEP-0215.

external_service/services
Request for list of services, possibly filtered by type.
external_service/credentials
Request for credentials for a specific service.

Service record method

This method includes access to the origin session like other events, and thus arbitrary access control can be performed, or credentials could be based on the senders JID etc.

module:hook_event("external_service/services", function(event)
    if event.requested_type == "ftp" then
        event.services:push({
            type = "ftp",
            transport = "tcp",
            host = "ftp.example.net",
            port = 21,
            username = event.origin.username,
            password = generate_temporary_password(event.origin.username),
            restricted = true,
            ttl = 300
        });
    end
end);

Stanza format

Finally, the raw reply stanza can be manipulated in arbitrary ways.

local dt = require "util.datetime";

module:hook_event("external_service/services", function(event)
    if event.requested_type == "ftp" then
        event.reply:tag("service", {
                type = "ftp",
                transport = "tcp",
                host = "ftp.example.com,
                port = "21", -- Obs! string
                username = event.origin.username,
                password = generate_temporary_password(),
                expires = dt.datetime(os.time() + 300),
                restricted = "1",
            }):up();
    end
end);