.. This file is part of PEPSI. Copyright (C) 2026 GNUnet e.V. PEPSI is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. ========================== pepsi-stage-auto-whitelist ========================== *Record the recipients of outgoing mail so they can always reply.* Role ==== ``pepsi-stage-auto-whitelist`` is the write-side counterpart of :doc:`pepsi-stage-check-whitelist`. As an **outgoing** message passes through, it inserts each envelope recipient (``rcpt_to``) into a named whitelist, so that when that person later **replies**, the check stage recognises their ``From:`` header and lets the reply through without payment. Place it on the outbound path (e.g. before a relay stage). It only writes whitelist rows and advances — it never modifies the message or drops, bounces or pauses it. Reference: :manpage:`pepsi-stage-auto-whitelist(1)`. Features ======== * **Shared whitelist table:** writes the same ``pepsi.whitelist`` table the check stage reads, so no schema of its own is needed; the ``WHITELIST_NAME`` option selects the ``whitelist_name`` group to populate. * **All envelope recipients:** every address in ``rcpt_to`` is recorded in a single round-trip, idempotently (``ON CONFLICT (whitelist_name, match_field, whitelist_regex) DO NOTHING``); the rows are written with ``match_field = from``. * **Fully anchored patterns:** each address is lower-cased, regex-escaped and wrapped in ``^``/``$``, so the stored ``whitelist_regex`` matches that address and nothing else. The check stage evaluates it (case-insensitively, with the ``~*`` operator) against the **addr-spec parsed out of** a reply's ``From:`` header, not the raw header value — so ``bob@example.com (Bob)`` still matches the row for ``bob@example.com``, while ``bob@example.com.evil`` and ``(bob@example.com)x@attacker.test`` do not. The anchoring is load-bearing: a *boundary* class enumerating the characters an address may contain would let an attacker find one character outside it and sit on either side of a whitelisted address inside a local part of their own. * **Whose whitelist:** on the outbound path the per-address layers are looked up for the envelope **sender**. The operator may name any whitelist in the INI file, ``pepsi.config_override`` at any scope, or a ``pepsi.settings`` row written with :doc:`pepsi-settings`, a list shared by every local user included. An account owner who may edit the stage by mail (:doc:`pepsi-stage-edit-settings`) may only choose a list in their own ``/...`` namespace, or keep the operator's; anything else would let them fill a shared or foreign list with addresses of their choosing. * **Per-row conditions:** * ``dkim_required`` is set from the **DKIM_REQUIRED** option (default *yes*). * ``signature_required`` is set to *true* iff the message state has ``encrypted: true`` — which :doc:`pepsi-stage-encrypt` sets when a recipient's copy really was encrypted. A correspondent reached under encryption is thereby held to the same standard when they reply. This only works with the stage placed **after** the encrypt stage; it changes no content, so it may sit between encrypt and :doc:`pepsi-stage-dkim-sign`, which is where the setup wizard puts it. Configuration ============= ``[stage-]``: ``PROGRAM = pepsi-stage-auto-whitelist``, ``WHITELIST_NAME`` (required — the single ``whitelist_name`` group to populate, a literal name: placeholders are not expanded and are refused), ``DKIM_REQUIRED`` (boolean, default *yes*) and ``NEXT_STAGE`` *(required — the stage records the recipients and always hands the message on)*. Neither the headers nor the body are loaded. See :manpage:`pepsi-stage-auto-whitelist(1)`. State ===== * **Inputs:** the envelope recipients from the ``rcpt_to`` column, and ``state.encrypted`` — set by :doc:`pepsi-stage-encrypt`, earlier on the same outbound path, when the outgoing message really was encrypted to a recipient key — which sets the stored ``signature_required`` flag, so a correspondent reached under encryption is later held to the same standard. * **Outputs:** none on the message — its ``state`` is untouched; the side effect is one ``pepsi.whitelist`` row per recipient. See also ======== :doc:`pepsi-stage-check-whitelist`, :doc:`pepsi-stage-anti-spam`, :doc:`pepsi-stage-arc`, :doc:`../features`, :manpage:`pepsi-stage-auto-whitelist(1)`.