End-to-End Encryption policies for Prosody
Go to file
phryk 7165594a47 Fixed whitelist iteration 2022-05-18 03:17:47 +02:00
COPYING updated documentation, applied GPLv3 2021-08-15 23:28:36 +02:00
README.markdown updated documentation, applied GPLv3 2021-08-15 23:28:36 +02:00
mod_e2e_policy.lua Fixed whitelist iteration 2022-05-18 03:17:47 +02:00



This module was written to encourage or enforce usage of end-to-end encryption. It will warn senders of messages without acceptable E2EE through a chosen warning mechanism and outright block messages when using the "required" policy.

Policies can be escalated from optional to required per user with a configurable grace period.

Whitelisting of user and MUC JIDs is also supported, so administrators can for example enable users having E2EE issues to contact support contacts or MUCS.


Enable the module as any other:

modules_enabled = {

You can then set some options to configure your desired policy:

Option Default Description
e2e_policy_accepted_schemes {"omemo", "pgp"} List of acceptable E2EE schemes. Possible values: "omemo", "pgp", "pgp_legacy" and "otr".
e2e_policy_direct "optional" Policy for direct messages. Possible values: "none", "optional" and "required".
e2e_policy_group "optional" Policy for group messages. Possible values: "none", "optional" and "required".
e2e_policy_warn_mechanism "message" Mechanism to use to communicate lack of E2EE with. Possible values: "message" and "error".
e2e_policy_whitelist { } Make this module ignore messages sent to and from these JIDs. Can include MUCs.
e2e_policy_message_plain_optional_direct See custom messages.
e2e_policy_message_plain_required_direct See custom messages.
e2e_policy_message_unacceptable_optional_direct See custom messages.
e2e_policy_message_unacceptable_required_direct See custom messages.
e2e_policy_message_plain_optional_group See custom messages.
e2e_policy_message_plain_required_group See custom messages.
e2e_policy_message_unacceptable_optional_group See custom messages.
e2e_policy_message_unacceptable_required_group See custom messages.
e2e_policy_message_graceperiod See custom messages.

Some examples:

e2e_policy_accepted_schemes = {"omemo", "otr", "pgp", "pgp_legacy"}
e2e_policy_direct = "required"
e2e_policy_group = "optional"
e2e_policy_warn_mechanism = "error"
e2e_policy_whitelist = { "admin@example.com", "prosody@conference.prosody.im" }

Recognized E2EE schemes

A word on warning mechanisms

Depending on the value of e2e_policy_warn_mechanism, warnings are sent either as <message> stanzas of type error or as normal messages from the servers' own JID.

Error messages should™ be shown directly in the affected conversations by clients and as such are the superior mechanism the problem is just that some contemporary clients don't honor them. This is why "message" is currently the default.

Custom messages

The e2e_policy_message_* options can be used to set custom messages to be sent to users on policy violations.
The names for these are built like this: e2e_policy_message_<reason>_<policy>_<chat-type>.

The variable parts are as follows:

  • <reason>: Whether this warning is caused by plaintext communication (plain) or an unacceptable E2EE scheme being used.
  • <policy>: What policy this warning is sent for, optional or required.
  • <chat-type>: The type of chat this warning is for, either direct or group.

Unless otherwise configured, the messages for <chat-type> group are inherited from the corresponding messages for direct chats.

Additionally, the following interpolation patterns are available to inject some contextual information:

  • {recipient}: The JID the message was supposed to go to.
  • {scheme}: The E2EE scheme used in the offending message, or "none".
  • {accepted_schemes}: A stringified list of accepted E2EE schemes.
  • {graceperiod_remaining}: A pretty representation of the remaining time until the grace period is over. Only available in e2e_policy_message_graceperiod.

e2e_policy_message_graceperiod is automatically appended to the selected warning message when it applies (i.e. when a grace period is active and not expired).

Default messages

Option Value
e2e_policy_message_plain_optional_direct "Your message to {recipient} was not end-to-end encrypted. For security reasons, using one of the following E2EE schemes is *STRONGLY* recommended: {accepted_schemes} "
e2e_policy_message_plain_required_direct "Your message to {recipient} was not end-to-end encrypted. For security reasons, using one of the following E2EE schemes is *REQUIRED* for conversations on this server: {accepted_schemes} "
e2e_policy_message_unacceptable_optional_direct "Your message to {recipient} was end-to-end encrypted using the {scheme} scheme, but we recommend using one of the following instead: {accepted_schemes} "
e2e_policy_message_unacceptable_required_direct "Your message to {recipient} was end-to-end encrypted using the {scheme} scheme, but this server *REQUIRES* one of these: {accepted_schemes} "
e2e_policy_message_plain_optional_group e2e_policy_message_plain_optional_direct
e2e_policy_message_plain_required_group e2e_policy_message_plain_required_direct
e2e_policy_message_unacceptable_optional_group e2e_policy_message_unacceptable_optional_direct
e2e_policy_message_unacceptable_required_group e2e_policy_message_unacceptable_required_direct
e2e_policy_message_graceperiod "You have {graceperiod_remaining} left before this will be enforced and messages without acceptable E2EE will be discarded."


Version State
trunk Should work
0.11 Works
0.10 Should work
0.9 Should work


This module was initially written by Michel Le Bihan. It was later greatly extended by phryk.