From a04960c1c661cfe7958fd5abc0760c4191208bba Mon Sep 17 00:00:00 2001 From: Ben Grande Date: Fri, 26 Jan 2024 22:46:36 +0100 Subject: [PATCH] feat: initial split-mail setup Split-mail allows to separate the receving, reading/composing and sending of mails to separate qubes, while having the reading/composing qube offline and a manual step necessary to authorize mails to be sent form the sender qube. --- salt/dev/install.sls | 5 + salt/dotfiles | 2 +- salt/kicksecure-minimal/clone.sls | 2 +- salt/mail/README.md | 262 ++++++++++++++++++ salt/{mutt => mail}/appmenus.sls | 2 +- salt/{mutt => mail}/appmenus.top | 2 +- salt/mail/clone.sls | 10 + salt/{mutt => mail}/clone.top | 2 +- salt/mail/configure-fetcher.sls | 31 +++ .../init.top => mail/configure-fetcher.top} | 8 +- .../configure-reader.sls} | 9 + .../configure-reader.top} | 4 +- salt/mail/configure-sender.sls | 30 ++ .../clone.sls => mail/configure-sender.top} | 6 +- salt/mail/create.sls | 179 ++++++++++++ salt/{mutt => mail}/create.top | 2 +- salt/mail/files/admin/policy/default.policy | 11 + salt/mail/files/fetcher/bin/qusal-send-inbox | 25 ++ salt/mail/files/fetcher/fdm.conf.example | 17 ++ salt/mail/files/fetcher/mpoprc.example | 20 ++ salt/mail/files/fetcher/systemd/fdm.service | 12 + salt/mail/files/fetcher/systemd/fdm.timer | 14 + salt/mail/files/fetcher/systemd/mpop.service | 12 + salt/mail/files/fetcher/systemd/mpop.timer | 14 + salt/mail/files/reader/bin/qusal-send-mail | 33 +++ salt/mail/files/reader/mailcap | 22 ++ salt/mail/files/reader/rpc/qusal.MailFetch | 15 + salt/mail/files/sender/msmtprc.example | 20 ++ salt/mail/files/sender/rpc/qusal.MailEnqueue | 15 + salt/mail/init.top | 22 ++ salt/mail/install-fetcher.sls | 64 +++++ salt/mail/install-fetcher.top | 9 + salt/mail/install-reader.sls | 71 +++++ .../install.top => mail/install-reader.top} | 4 +- .../install.sls => mail/install-sender.sls} | 36 +-- salt/mail/install-sender.top | 9 + salt/mutt/README.md | 64 ----- salt/mutt/create.sls | 51 ---- salt/utils/macros/clone-template.sls | 7 +- 39 files changed, 962 insertions(+), 161 deletions(-) create mode 100644 salt/mail/README.md rename salt/{mutt => mail}/appmenus.sls (79%) rename salt/{mutt => mail}/appmenus.top (89%) create mode 100644 salt/mail/clone.sls rename salt/{mutt => mail}/clone.top (90%) create mode 100644 salt/mail/configure-fetcher.sls rename salt/{mutt/init.top => mail/configure-fetcher.top} (62%) rename salt/{mutt/configure.sls => mail/configure-reader.sls} (55%) rename salt/{mutt/configure.top => mail/configure-reader.top} (77%) create mode 100644 salt/mail/configure-sender.sls rename salt/{mutt/clone.sls => mail/configure-sender.top} (52%) create mode 100644 salt/mail/create.sls rename salt/{mutt => mail}/create.top (90%) create mode 100644 salt/mail/files/admin/policy/default.policy create mode 100755 salt/mail/files/fetcher/bin/qusal-send-inbox create mode 100644 salt/mail/files/fetcher/fdm.conf.example create mode 100644 salt/mail/files/fetcher/mpoprc.example create mode 100644 salt/mail/files/fetcher/systemd/fdm.service create mode 100644 salt/mail/files/fetcher/systemd/fdm.timer create mode 100644 salt/mail/files/fetcher/systemd/mpop.service create mode 100644 salt/mail/files/fetcher/systemd/mpop.timer create mode 100755 salt/mail/files/reader/bin/qusal-send-mail create mode 100644 salt/mail/files/reader/mailcap create mode 100755 salt/mail/files/reader/rpc/qusal.MailFetch create mode 100644 salt/mail/files/sender/msmtprc.example create mode 100755 salt/mail/files/sender/rpc/qusal.MailEnqueue create mode 100644 salt/mail/init.top create mode 100644 salt/mail/install-fetcher.sls create mode 100644 salt/mail/install-fetcher.top create mode 100644 salt/mail/install-reader.sls rename salt/{mutt/install.top => mail/install-reader.top} (73%) rename salt/{mutt/install.sls => mail/install-sender.sls} (58%) create mode 100644 salt/mail/install-sender.top delete mode 100644 salt/mutt/README.md delete mode 100644 salt/mutt/create.sls diff --git a/salt/dev/install.sls b/salt/dev/install.sls index 0d849f9..b7a7030 100644 --- a/salt/dev/install.sls +++ b/salt/dev/install.sls @@ -55,6 +55,11 @@ include: - gitlint - pylint - yamllint + # git-send-email + - git-email + - libemail-valid-perl + - libmailtools-perl + - libauthen-sasl-perl {% set pkg = { 'Debian': { diff --git a/salt/dotfiles b/salt/dotfiles index 87499f7..c198724 160000 --- a/salt/dotfiles +++ b/salt/dotfiles @@ -1 +1 @@ -Subproject commit 87499f76ad5b0ffba59fa19cbdbe13cdfa5cdcd6 +Subproject commit c1987240bcaaef22a2f61b52bb399d951b8f3fc3 diff --git a/salt/kicksecure-minimal/clone.sls b/salt/kicksecure-minimal/clone.sls index f87331d..26a9205 100644 --- a/salt/kicksecure-minimal/clone.sls +++ b/salt/kicksecure-minimal/clone.sls @@ -7,4 +7,4 @@ SPDX-License-Identifier: AGPL-3.0-or-later {%- import slsdotpath ~ "/template.jinja" as template -%} {% from 'utils/macros/clone-template.sls' import clone_template -%} -{{ clone_template('debian-minimal', template.template, 'noprefix') }} +{{ clone_template('debian-minimal', template.template, prefix='') }} diff --git a/salt/mail/README.md b/salt/mail/README.md new file mode 100644 index 0000000..ee045fe --- /dev/null +++ b/salt/mail/README.md @@ -0,0 +1,262 @@ +# mail + +Mail operations in Qubes OS. + +## Table of Contents + +* [Description](#description) +* [Security](#security) +* [Installation](#installation) +* [Usage](#usage) + * [Fetcher](#fetcher) + * [fdm Configuration](#fdm-configuration) + * [mpop Configuration](#mpop-configuration) + * [OfflineIMAP Configuration](#offlineimap-configuration) + * [Send Inbox to Reader Qube](#send-inbox-to-reader-qube) + * [Reader](#reader) + * [Mutt Configuration](#mutt-configuration) + * [Send Queue to Sender Qube](#send-queue-to-sender-qube) + * [Sender](#sender) + * [msmtp Configuration](#msmtp-configuration) + * [Send emails to SMTP server](#send-emails-to-smtp-server) +* [Credits](#credits) + +## Description + +Create a mail fetcher qube named "mail-fetcher", a mail reader qube names +"mail-reader" and a mail sender qube named "mail-sender". + +The online "mail-fetcher" qube will fetch messages with POP3. After being +fetched, you can copy them to the offline "mail-reader" qube, where you will +be reading emails. After composing a message, the "mail-reader" qube will +save the messages to a queue, which can be forwarded to the online +"mail-sender" qube. You can review messages to be sent from the "mail-sender" +qube and them send them via SMTP. + +By default, the protocols used required SSL, POP3 on port 995, IMAP on port +995 and SMTP on port 587. You can always override any configuration via +included files. + +This formula is based on Unman's SplitMutt guide, using POP3 and/or IMAP to +get mail, not considering SSH access to the mail server. We are using +qfile-agent and not Rsync to synchronize mails between qubes to avoid a higher +attack surface, but Rsync may be considered in the future in case qfile-agent +causes problems. + +## Security + +Mail is insecure per nature and users depend on archaic Unix tools that +[receive little to no maintenance](https://xkcd.com/2347/). + +The qubes connected to the internet `mail-fetcher` and `mail-sender` hold the +account password to connect to the remote servers. If any of those are +compromised, your mail account can also be. Network firewall can help, to +some extent, if you consider the attacker doesn't have an account on the same +mail server you have, or sends a message from you mail account to an attacker +controlled mail and then delete from your sent messages. + +The reader qube `mail-reader` also has a high attack surface. Although +offline, it can access PGP keys via split-gpg2 and also read all your mails, +in case an especially crafted message exploits the parsing of the message. We +are using `Mutt`, but if you know how to choose local folders in `Mozilla +Thunderbird`, you can adapt the formula. Neither MUA have great security +records, but `Mutt` has less and is more minimal. The reader should be a +secure mail client, but there are none. `Mutt` will open `text/html` and +`text/plain` files, while every other type of file is opened in a disposable +qube. See [reader](../reader/README.md) for offline disposables that can open +some kinds of files. + +If you want to read the mail in the sender qube `mail-sender`, you may want to +do this before sending to the mail server, you should open the file in a +disposable to avoid a parsing bug in the editor to extract information such as +the password from the sender qube. This method doesn't prevent all kinds of +exploitation, as `msmtp` still needs to parse the mail to be sent. + +## Installation + +- Top +```sh +qubesctl top.enable mail reader +qubesctl --targets=tpl-mail-fetcher,tpl-mail-reader,tpl-mail-sender,dvm-mail-fetcher,mail-reader,dvm-mail-sender,tpl-reader state.apply +qubesctl top.disable mail reader +qubesctl state.apply mail.appmenus,reader.appmenus +``` + +- State + +```sh +qubesctl state.apply mail.create +qubesctl --skip-dom0 --targets=tpl-reader state.apply reader.install +qubesctl --skip-dom0 --targets=tpl-mail-fetcher state.apply mail.install-fetcher +qubesctl --skip-dom0 --targets=tpl-mail-reader state.apply mail.install-reader +qubesctl --skip-dom0 --targets=tpl-mail-sender state.apply mail.install-sender +qubesctl --skip-dom0 --targets=dvm-mail-fetcher state.apply mail.configure-fetcher +qubesctl --skip-dom0 --targets=mail-reader state.apply mail.configure-reader +qubesctl --skip-dom0 --targets=dvm-mail-sender state.apply mail.configure-sender +qubesctl state.apply mail.appmenus,reader.appmenus +``` + + +## Usage + +You will use local files to override the ones provided by this package. Few +options must be set. Do not change the directories in the configuration +files, they need to stay the same. + +You should firewall the `mail-fetcher` and `mail-sender` to the `POP3` server +or/and `IMAP` server and `SMTP` server, respectively. + +Steps overview: + +1. Receive mail via the `mail-fetcher` and transfer mail to `mail-reader`. +2. Read and compose mail from `mail-reader` and transfer to `mail-sender`. +3. Send queued mails from `mail-sender` to remote mail server. + +### Fetcher + +The fetcher fetches e-mails with `fdm` or `mpop` via the POP3 protocol or even +`offlineimap` via the IMAP protocol, you only need to choose one program for +this task, depending on your needs. + +The configuration must be done in `dvm-mail-fetcher`, while the fetching of +mails will be done in `disp-mail-fetcher`. + +#### fdm Configuration + +Copy example configuration file to where the program can read automatically: +```sh +cp ~/.fdm.conf.example ~/.fdm.conf +``` + +Edit the configuration according to your needs: +```sh +editor ~/.fdm.conf +``` + +Check the connection is working: +```sh +fdm -kv poll +``` + +Fetch mail: +```sh +fdm -kv fetch +``` + +If the fetch was successful, enable the fetch scheduler: +```sh +systemctl --user enable fdm.timer +systemctl --user start fdm.timer +``` + +#### mpop Configuration + +Copy `~/.mpoprc.example` to `~/.mpoprc` and edit the configuration +according to your needs. + +Copy example configuration file to where the program can read automatically: +```sh +cp ~/.mporc.example ~/.mpoprc +``` + +Edit the configuration according to your needs: +```sh +editor ~/.mpoprc +``` + +Check the connection is working: +```sh +mpop --debug --auth-only +``` + +Fetch mail: +```sh +mpop +``` + +If the fetch was successful, enable the fetch scheduler: +```sh +systemctl --user enable mpop.timer +systemctl --user start mpop.timer +``` + +#### OfflineIMAP Configuration + +TODO: difficult to exemplify as the folders are user and provider specific. + +#### Send Inbox to Reader Qube + +Send the inbox to the reader: +```sh +qusal-send-inbox +``` + +### Reader + +The reader renders e-mails with `mutt`. + +The configuration as well as the reading and composing of mails are done in +`mail-reader`. + +#### Mutt Configuration + +You must place your credentials in `~/.muttrc-credentials.local`, definitions +in this file will be used by scripts sourced at a later time. + +You should define aliases only in `~/.muttrc-aliases.local`, as the aliases +file can be edited by Mutt. + +You can define extra options in `~/.muttrc.local`, as this is the last file to +be sourced, it can override previous options. + +If you want to have your e-mail signature (not PGP) at the end of every mail +you send, place it in `~/.signature`. + +Samples for the aforementioned files can be found at `~/.config/mutt/sample`. + +#### Send Queue to Sender Qube + +Send the queued mail to the sender: +```sh +qusal-send-mail +``` + +### Sender + +The sender sends e-mails with `msmtp` via the SMTP protocol. + +The configuration must be done in `dvm-mail-sender`, while the sending of +mails are done in `disp-mail-sender`. + +#### msmtp Configuration + +Copy example configuration file to where the program can read automatically: +```sh +cp ~/.msmtprc.example ~/.msmtprc +``` + +Edit the configuration according to your needs: +```sh +editor ~/.msmtprc +``` + +Test the connection to the SMTP server: +```sh +msmtp --serverinfo +``` + +#### Send emails to SMTP server + +List the queued mails: +```sh +msmtp-queue -d +``` + +Send selected mails from the queue to the SMTP server: +```sh +msmtp-queue -R +``` + +## Credits + +- [Unman](https://github.com/unman/notes/blob/master/SplitMutt.md) diff --git a/salt/mutt/appmenus.sls b/salt/mail/appmenus.sls similarity index 79% rename from salt/mutt/appmenus.sls rename to salt/mail/appmenus.sls index a84a247..3f4d80d 100644 --- a/salt/mutt/appmenus.sls +++ b/salt/mail/appmenus.sls @@ -5,4 +5,4 @@ SPDX-License-Identifier: AGPL-3.0-or-later #} {% from 'utils/macros/sync-appmenus.sls' import sync_appmenus -%} -{{ sync_appmenus('tpl-' ~ sls_path) }} +{{ sync_appmenus('tpl-' ~ sls_path ~ '-reader') }} diff --git a/salt/mutt/appmenus.top b/salt/mail/appmenus.top similarity index 89% rename from salt/mutt/appmenus.top rename to salt/mail/appmenus.top index 68d5d94..1d9ab1f 100644 --- a/salt/mutt/appmenus.top +++ b/salt/mail/appmenus.top @@ -7,4 +7,4 @@ SPDX-License-Identifier: AGPL-3.0-or-later base: 'dom0': - match: nodegroup - - mutt.appmenus + - mail.appmenus diff --git a/salt/mail/clone.sls b/salt/mail/clone.sls new file mode 100644 index 0000000..562db2a --- /dev/null +++ b/salt/mail/clone.sls @@ -0,0 +1,10 @@ +{# +SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +{% from 'utils/macros/clone-template.sls' import clone_template -%} +{{ clone_template('debian-minimal', sls_path ~ '-fetcher') }} +{{ clone_template('debian-minimal', sls_path ~ '-reader', include_create=False) }} +{{ clone_template('debian-minimal', sls_path ~ '-sender', include_create=False) }} diff --git a/salt/mutt/clone.top b/salt/mail/clone.top similarity index 90% rename from salt/mutt/clone.top rename to salt/mail/clone.top index e6a88fa..9c06090 100644 --- a/salt/mutt/clone.top +++ b/salt/mail/clone.top @@ -7,4 +7,4 @@ SPDX-License-Identifier: AGPL-3.0-or-later base: 'dom0': - match: nodegroup - - mutt.clone + - mail.clone diff --git a/salt/mail/configure-fetcher.sls b/salt/mail/configure-fetcher.sls new file mode 100644 index 0000000..c31c629 --- /dev/null +++ b/salt/mail/configure-fetcher.sls @@ -0,0 +1,31 @@ +{# +SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +{% if grains['nodename'] != 'dom0' %} + +include: + - dotfiles.copy-x11 + - dotfiles.copy-sh + +"{{ slsdotpath }}-fetcher-fdm.conf.example": + file.managed: + - name: /home/user/.fdm.conf.example + - source: salt://{{ slsdotpath }}/files/fetcher/fdm.conf.example + - mode: "0600" + - user: user + - group: user + - makedirs: True + +"{{ slsdotpath }}-fetcher-mpoprc.example": + file.managed: + - name: /home/user/.mpoprc.example + - source: salt://{{ slsdotpath }}/files/fetcher/mpoprc.example + - mode: "0600" + - user: user + - group: user + - makedirs: True + +{% endif -%} diff --git a/salt/mutt/init.top b/salt/mail/configure-fetcher.top similarity index 62% rename from salt/mutt/init.top rename to salt/mail/configure-fetcher.top index 1beae33..9f65e53 100644 --- a/salt/mutt/init.top +++ b/salt/mail/configure-fetcher.top @@ -5,10 +5,6 @@ SPDX-License-Identifier: AGPL-3.0-or-later #} base: - 'dom0': + 'dvm-mail-fetcher': - match: nodegroup - - mutt.create - 'tpl-mutt': - - mutt.install - 'mutt': - - mutt.configure + - mail.configure-fetcher diff --git a/salt/mutt/configure.sls b/salt/mail/configure-reader.sls similarity index 55% rename from salt/mutt/configure.sls rename to salt/mail/configure-reader.sls index 5ae8983..f0737f7 100644 --- a/salt/mutt/configure.sls +++ b/salt/mail/configure-reader.sls @@ -12,4 +12,13 @@ include: - dotfiles.copy-net - dotfiles.copy-mutt +"{{ slsdotpath }}-reader-mailcap": + file.managed: + - name: /home/user/.mailcap + - source: salt://{{ slsdotpath }}/files/reader/mailcap + - mode: "0644" + - user: user + - group: user + - makedirs: True + {% endif -%} diff --git a/salt/mutt/configure.top b/salt/mail/configure-reader.top similarity index 77% rename from salt/mutt/configure.top rename to salt/mail/configure-reader.top index 85c787e..562c239 100644 --- a/salt/mutt/configure.top +++ b/salt/mail/configure-reader.top @@ -5,6 +5,6 @@ SPDX-License-Identifier: AGPL-3.0-or-later #} base: - 'mutt': + 'mail-reader': - match: nodegroup - - mutt.configure + - mail.configure-reader diff --git a/salt/mail/configure-sender.sls b/salt/mail/configure-sender.sls new file mode 100644 index 0000000..4460f0b --- /dev/null +++ b/salt/mail/configure-sender.sls @@ -0,0 +1,30 @@ +{# +SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +{% if grains['nodename'] != 'dom0' %} + +include: + - dotfiles.copy-x11 + - dotfiles.copy-sh + +"{{ slsdotpath }}-sender-msmtprc": + file.managed: + - name: /home/user/.msmtprc.example + - source: salt://{{ slsdotpath }}/files/sender/msmtprc.example + - mode: "0600" + - user: user + - group: user + - makedirs: True + +"{{ slsdotpath }}-sender-log-dir": + file.directory: + - name: /home/user/log + - mode: "0700" + - user: user + - group: user + - makedirs: True + +{% endif -%} diff --git a/salt/mutt/clone.sls b/salt/mail/configure-sender.top similarity index 52% rename from salt/mutt/clone.sls rename to salt/mail/configure-sender.top index 0554d7f..311c260 100644 --- a/salt/mutt/clone.sls +++ b/salt/mail/configure-sender.top @@ -4,5 +4,7 @@ SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. SPDX-License-Identifier: AGPL-3.0-or-later #} -{% from 'utils/macros/clone-template.sls' import clone_template -%} -{{ clone_template('debian-minimal', sls_path) }} +base: + 'dvm-mail-sender': + - match: nodegroup + - mail.configure-sender diff --git a/salt/mail/create.sls b/salt/mail/create.sls new file mode 100644 index 0000000..0d64cb1 --- /dev/null +++ b/salt/mail/create.sls @@ -0,0 +1,179 @@ +{# +SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +{%- from "qvm/template.jinja" import load -%} + +include: + - .clone + +{% load_yaml as defaults -%} +name: tpl-{{ slsdotpath }}-fetcher +force: True +require: +- sls: {{ slsdotpath }}.clone +prefs: +- audiovm: "" +{%- endload %} +{{ load(defaults) }} + +{% load_yaml as defaults -%} +name: tpl-{{ slsdotpath }}-reader +force: True +require: +- sls: {{ slsdotpath }}.clone +prefs: +- audiovm: "" +features: +- set: + - menu-items: "mutt.desktop qubes-run-terminal.desktop qubes-start.desktop" + - default-menu-items: "mutt.desktop qubes-run-terminal.desktop qubes-start.desktop" +{%- endload %} +{{ load(defaults) }} + +{% load_yaml as defaults -%} +name: tpl-{{ slsdotpath }}-sender +force: True +require: +- sls: {{ slsdotpath }}.clone +prefs: +- audiovm: "" +{%- endload %} +{{ load(defaults) }} + +{% load_yaml as defaults -%} +name: dvm-{{ slsdotpath }}-fetcher +force: True +require: +- qvm: tpl-{{ slsdotpath }}-fetcher +present: +- template: tpl-{{ slsdotpath }}-fetcher +- label: red +prefs: +- template: tpl-{{ slsdotpath }}-fetcher +- label: red +- audiovm: "" +- vcpus: 1 +- memory: 200 +- maxmem: 350 +- template_for_dispvms: True +- include_in_backups: False +features: +- enable: + - servicevm +- disable: + - service.cups + - service.cups-browsed + - service.tinyproxy +{%- endload %} +{{ load(defaults) }} + +{% load_yaml as defaults -%} +name: {{ slsdotpath }}-reader +force: True +require: +- qvm: tpl-{{ slsdotpath }}-reader +present: +- template: tpl-{{ slsdotpath }}-reader +- label: red +prefs: +- template: tpl-{{ slsdotpath }}-fetcher +- label: red +- audiovm: "" +- vcpus: 1 +- memory: 200 +- maxmem: 350 +- include_in_backups: False +features: +- disable: + - service.cups + - service.cups-browsed + - service.tinyproxy +{%- endload %} +{{ load(defaults) }} + +{% load_yaml as defaults -%} +name: dvm-{{ slsdotpath }}-sender +force: True +require: +- qvm: tpl-{{ slsdotpath }}-sender +present: +- template: tpl-{{ slsdotpath }}-sender +- label: red +prefs: +- template: tpl-{{ slsdotpath }}-sender +- label: red +- audiovm: "" +- vcpus: 1 +- memory: 200 +- maxmem: 350 +- template_for_dispvms: True +- include_in_backups: False +features: +- enable: + - servicevm +- disable: + - service.cups + - service.cups-browsed + - service.tinyproxy +{%- endload %} +{{ load(defaults) }} + +{% load_yaml as defaults -%} +name: disp-{{ slsdotpath }}-fetcher +force: True +require: +- qvm: dvm-{{ slsdotpath }}-fetcher +present: +- template: dvm-{{ slsdotpath }}-fetcher +- label: red +- class: DispVM +prefs: +- template: dvm-{{ slsdotpath }}-fetcher +- label: red +- audiovm: "" +- vcpus: 1 +- memory: 200 +- maxmem: 350 +- autostart: False +features: +- enable: + - servicevm +- disable: + - service.cups + - service.cups-browsed + - service.tinyproxy +{%- endload %} +{{ load(defaults) }} + +{% load_yaml as defaults -%} +name: disp-{{ slsdotpath }}-sender +force: True +require: +- qvm: dvm-{{ slsdotpath }}-sender +present: +- template: dvm-{{ slsdotpath }}-sender +- label: red +- class: DispVM +prefs: +- template: dvm-{{ slsdotpath }}-sender +- label: red +- audiovm: "" +- vcpus: 1 +- memory: 200 +- maxmem: 350 +- autostart: False +features: +- enable: + - servicevm +- disable: + - service.cups + - service.cups-browsed + - service.tinyproxy +{%- endload %} +{{ load(defaults) }} + +{% from 'utils/macros/policy.sls' import policy_set with context -%} +{{ policy_set(sls_path, '80') }} diff --git a/salt/mutt/create.top b/salt/mail/create.top similarity index 90% rename from salt/mutt/create.top rename to salt/mail/create.top index 13b9e6f..56c202a 100644 --- a/salt/mutt/create.top +++ b/salt/mail/create.top @@ -7,4 +7,4 @@ SPDX-License-Identifier: AGPL-3.0-or-later base: 'dom0': - match: nodegroup - - mutt.create + - mail.create diff --git a/salt/mail/files/admin/policy/default.policy b/salt/mail/files/admin/policy/default.policy new file mode 100644 index 0000000..fcb6c2b --- /dev/null +++ b/salt/mail/files/admin/policy/default.policy @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +## Do not modify this file, create a new policy with with a lower number in the +## file name instead. For example `30-user.policy`. +qusal.MailFetch * mail-fetcher @default ask target=mail-reader default_target=mail-reader +qusal.MailFetch * @anyvm @anyvm deny +qusal.MailEnqueue * mail-reader @default ask target=mail-sender default_target=mail-sender +qusal.MailEnqueue * @anyvm @anyvm deny +## vim:ft=qrexecpolicy diff --git a/salt/mail/files/fetcher/bin/qusal-send-inbox b/salt/mail/files/fetcher/bin/qusal-send-inbox new file mode 100755 index 0000000..053bf9b --- /dev/null +++ b/salt/mail/files/fetcher/bin/qusal-send-inbox @@ -0,0 +1,25 @@ +#!/bin/sh + +## SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. +## +## SPDX-License-Identifier: AGPL-3.0-or-later + +set -eu + +inbox_dir="${HOME}/mail/INBOX" +if test ! -d "${inbox_dir}"; then + echo "Inbox '${inbox_dir}' does not exist" >&2 + exit 1 +fi +cd "${inbox_dir}" || exit 1 + +files_to_send="$(find "${inbox_dir}" -type f)" +if test -z "${files_to_send}"; then + echo "Inbox '${inbox_dir}' is empty" >&2 + exit 1 +fi + +qrexec-client-vm --filter-escape-chars-stderr -- @default qusal.MailFetch \ + /usr/lib/qubes/qfile-agent * + +find "${inbox_dir}" -type f -delete diff --git a/salt/mail/files/fetcher/fdm.conf.example b/salt/mail/files/fetcher/fdm.conf.example new file mode 100644 index 0000000..7e10cff --- /dev/null +++ b/salt/mail/files/fetcher/fdm.conf.example @@ -0,0 +1,17 @@ +# ~/.fdm.conf + +## SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. +## +## SPDX-License-Identifier: AGPL-3.0-or-later + +##### DO NOT EDIT THIS BLOCK ##### +action "inbox" maildir "%h/mail/INBOX" + +##### EDIT THIS BLOCK ##### +account "john-doe" pop3s + server "pop.mail.example" + user "john-doe" + pass "secret123" + +##### DO NOT EDIT THIS BLOCK ##### +match all action "inbox" diff --git a/salt/mail/files/fetcher/mpoprc.example b/salt/mail/files/fetcher/mpoprc.example new file mode 100644 index 0000000..d454ed6 --- /dev/null +++ b/salt/mail/files/fetcher/mpoprc.example @@ -0,0 +1,20 @@ +## ~/.mpoprc + +## SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. +## +## SPDX-License-Identifier: AGPL-3.0-or-later + +##### DO NOT EDIT THIS BLOCK ##### +defaults + tls on + tls_starttls off + tls_trust_file system + delivery maildir ~/mail/INBOX + uidls_file ~/.local/share/%U_at_%H + +##### EDIT THIS BLOCK ##### +account main + host pop.mail.example + user john-doe + password secret123 +account default : main diff --git a/salt/mail/files/fetcher/systemd/fdm.service b/salt/mail/files/fetcher/systemd/fdm.service new file mode 100644 index 0000000..ec364bf --- /dev/null +++ b/salt/mail/files/fetcher/systemd/fdm.service @@ -0,0 +1,12 @@ +## SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. +## +## SPDX-License-Identifier: AGPL-3.0-or-later + +[Unit] +Description=Fetch mail using fdm +After=network.target network-online.target dbus.socket +Documentation=man:fdm(1) + +[Service] +Type=oneshot +ExecStart=/usr/bin/fdm fetch diff --git a/salt/mail/files/fetcher/systemd/fdm.timer b/salt/mail/files/fetcher/systemd/fdm.timer new file mode 100644 index 0000000..f51bc28 --- /dev/null +++ b/salt/mail/files/fetcher/systemd/fdm.timer @@ -0,0 +1,14 @@ +## SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. +## +## SPDX-License-Identifier: AGPL-3.0-or-later + +[Unit] +Description=Fetch mail using fdm + +[Timer] +OnBootSec=2m +OnUnitActiveSec=5m +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/salt/mail/files/fetcher/systemd/mpop.service b/salt/mail/files/fetcher/systemd/mpop.service new file mode 100644 index 0000000..ac4e897 --- /dev/null +++ b/salt/mail/files/fetcher/systemd/mpop.service @@ -0,0 +1,12 @@ +## SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. +## +## SPDX-License-Identifier: AGPL-3.0-or-later + +[Unit] +Description=Fetch mail using mpop +After=network.target network-online.target dbus.socket +Documentation=man:mpop(1) + +[Service] +Type=oneshot +ExecStart=/usr/bin/mpop diff --git a/salt/mail/files/fetcher/systemd/mpop.timer b/salt/mail/files/fetcher/systemd/mpop.timer new file mode 100644 index 0000000..6c8738b --- /dev/null +++ b/salt/mail/files/fetcher/systemd/mpop.timer @@ -0,0 +1,14 @@ +## SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. +## +## SPDX-License-Identifier: AGPL-3.0-or-later + +[Unit] +Description=Fetch mail using mpop + +[Timer] +OnBootSec=2m +OnUnitActiveSec=5m +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/salt/mail/files/reader/bin/qusal-send-mail b/salt/mail/files/reader/bin/qusal-send-mail new file mode 100755 index 0000000..a32aff8 --- /dev/null +++ b/salt/mail/files/reader/bin/qusal-send-mail @@ -0,0 +1,33 @@ +#!/bin/sh + +## SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. +## +## SPDX-License-Identifier: AGPL-3.0-or-later + +## Save mail to msmtp queue directory and copy it to sender queue directory. + +set -eu + +MSMTP_Q="${MSMTP_Q:-"${Q:-"${HOME}/.msmtp.queue"}"}" +if test -z "${MSMTP_Q}" || test ! -d "${MSMTP_Q}"; then + echo "Queue dir '${MSMTP_Q}' not found" >&2 + exit 1 +fi + +cd "${MSMTP_Q}" || exit 1 + +for mail in *; do + if ! test -e "${mail}"; then + echo "Mail queue '${MSMTP_Q}' is empty" >&2 + exit 1 + fi + if ! test -f "${mail}"; then + echo "Mail '${mail}' is not a regular file" >&2 + exit 1 + fi +done + +qrexec-client-vm --filter-escape-chars-stderr -- @default qusal.MailEnqueue \ + /usr/lib/qubes/qfile-agent * + +find "${MSMTP_Q}" -type f -delete diff --git a/salt/mail/files/reader/mailcap b/salt/mail/files/reader/mailcap new file mode 100644 index 0000000..b3c96e9 --- /dev/null +++ b/salt/mail/files/reader/mailcap @@ -0,0 +1,22 @@ +## ~/.mailcap +## +## SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. +## +## SPDX-License-Identifier: AGPL-3.0-or-later +## +## Definitions: https://www.iana.org/assignments/media-types/media-types.xhtml + +## Allow some type of media to be viewed. +text/html; w3m -I %{charset} -dump -T text/html '%s' | cat -s; nametemplate=%s.html; edit=; copiousoutput; needsterminal; test=test -t 0 +text/plain; VISUAL="echo Editing prohibited\; sleep 2\; false" LESS="" less -- '%s'; edit=; needsterminal; test=test -t 0 + +## The remaining media types are always opened in @dispvm. +application/*; echo "Opening file in DispVM" && qvm-open-in-dvm -- '%s' +audio/*; echo "Opening file in DispVM" && qvm-open-in-dvm -- '%s' +font/*; echo "Opening file in DispVM" && qvm-open-in-dvm -- '%s' +example/*; echo "Opening file in DispVM" && qvm-open-in-dvm -- '%s' +image/*; echo "Opening file in DispVM" && qvm-open-in-dvm -- '%s' +message/*; echo "Opening file in DispVM" && qvm-open-in-dvm -- '%s' +model/*; echo "Opening file in DispVM" && qvm-open-in-dvm -- '%s' +multipart/*; echo "Opening file in DispVM" && qvm-open-in-dvm -- '%s' +video/*; echo "Opening file in DispVM" && qvm-open-in-dvm -- '%s' diff --git a/salt/mail/files/reader/rpc/qusal.MailFetch b/salt/mail/files/reader/rpc/qusal.MailFetch new file mode 100755 index 0000000..471cf09 --- /dev/null +++ b/salt/mail/files/reader/rpc/qusal.MailFetch @@ -0,0 +1,15 @@ +#!/bin/sh + +## SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. +## +## SPDX-License-Identifier: AGPL-3.0-or-later + +umask 077 +inbox_dir="${HOME}/mail/INBOX" +uid="$(id -u user)" + +# shellcheck disable=SC2174 +mkdir -p "${inbox_dir}" +chmod 0700 "${inbox_dir}" + +qfile-unpacker "${uid}" "${inbox_dir}" diff --git a/salt/mail/files/sender/msmtprc.example b/salt/mail/files/sender/msmtprc.example new file mode 100644 index 0000000..6761f74 --- /dev/null +++ b/salt/mail/files/sender/msmtprc.example @@ -0,0 +1,20 @@ +# ~/.msmtprc + +## SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. +## +## SPDX-License-Identifier: AGPL-3.0-or-later + +##### DO NOT EDIT THIS BLOCK ##### +defaults + auth on + tls on + tls_starttls off + tls_trust_file system + logfile ~/log/msmtp.log + +##### EDIT THIS BLOCK ##### +account main + host smtp.mail.example + user john-doe + password secret123 +account default : main diff --git a/salt/mail/files/sender/rpc/qusal.MailEnqueue b/salt/mail/files/sender/rpc/qusal.MailEnqueue new file mode 100755 index 0000000..65ea313 --- /dev/null +++ b/salt/mail/files/sender/rpc/qusal.MailEnqueue @@ -0,0 +1,15 @@ +#!/bin/sh + +## SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. +## +## SPDX-License-Identifier: AGPL-3.0-or-later + +umask 077 +queue_dir="${MSMTP_Q:-"${Q:-"${HOME}/.msmtp.queue"}"}" +uid="$(id -u user)" + +# shellcheck disable=SC2174 +mkdir -p "${queue_dir}" +chmod 0700 "${queue_dir}" + +exec qfile-unpacker "${uid}" "${queue_dir}" diff --git a/salt/mail/init.top b/salt/mail/init.top new file mode 100644 index 0000000..8027d59 --- /dev/null +++ b/salt/mail/init.top @@ -0,0 +1,22 @@ +{# +SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +base: + 'dom0': + - match: nodegroup + - mail.create + 'tpl-mail-fetcher': + - mail.install-fetcher + 'tpl-mail-reader': + - mail.install-reader + 'tpl-mail-sender': + - mail.install-sender + 'dvm-mail-fetcher': + - mail.configure-fetcher + 'mail-reader': + - mail.configure-reader + 'dvm-mail-sender': + - mail.configure-sender diff --git a/salt/mail/install-fetcher.sls b/salt/mail/install-fetcher.sls new file mode 100644 index 0000000..3ae9baa --- /dev/null +++ b/salt/mail/install-fetcher.sls @@ -0,0 +1,64 @@ +{# +SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +{% if grains['nodename'] != 'dom0' %} + +include: + - dotfiles.copy-x11 + - dotfiles.copy-sh + - dotfiles.copy-net + +"{{ slsdotpath }}-fetcher-updated": + pkg.uptodate: + - refresh: True + +"{{ slsdotpath }}-fetcher-installed": + pkg.installed: + - refresh: True + - skip_suggestions: True + - install_recommends: False + - pkgs: + - qubes-core-agent-networking + - ca-certificates + - man-db + - offlineimap3 + - fdm + - mpop + - mb2md + - libio-socket-ssl-perl + - libnet-ssleay-perl + - libsasl2-2 + - libsasl2-modules + - libsasl2-modules-db + +"{{ slsdotpath }}-fetcher-systemd-fdm.timer": + file.managed: + - name: /usr/lib/systemd/user/fdm.timer + - source: salt://{{ slsdotpath }}/files/fetcher/systemd/fdm.timer + - mode: "0644" + - user: root + - group: root + - makedirs: True + +"{{ slsdotpath }}-fetcher-systemd-fdm.service": + file.managed: + - name: /usr/lib/systemd/user/fdm.service + - source: salt://{{ slsdotpath }}/files/fetcher/systemd/fdm.service + - mode: "0644" + - user: root + - group: root + - makedirs: true + +"{{ slsdotpath }}-fetcher-bin": + file.managed: + - name: /usr/bin/qusal-send-inbox + - source: salt://{{ slsdotpath }}/files/fetcher/bin/qusal-send-inbox + - mode: "0755" + - user: root + - group: root + - makedirs: True + +{% endif -%} diff --git a/salt/mail/install-fetcher.top b/salt/mail/install-fetcher.top new file mode 100644 index 0000000..fb14554 --- /dev/null +++ b/salt/mail/install-fetcher.top @@ -0,0 +1,9 @@ +{# +SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +base: + 'tpl-mail-fetcher': + - mail.install-fetcher diff --git a/salt/mail/install-reader.sls b/salt/mail/install-reader.sls new file mode 100644 index 0000000..c5fdeae --- /dev/null +++ b/salt/mail/install-reader.sls @@ -0,0 +1,71 @@ +{# +SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +{% if grains['nodename'] != 'dom0' %} + +include: + - dotfiles.copy-x11 + - dotfiles.copy-sh + - dotfiles.copy-net + - dotfiles.copy-mutt + - sys-pgp.install-client + +"{{ slsdotpath }}-reader-updated": + pkg.uptodate: + - refresh: True + +"{{ slsdotpath }}-reader-installed": + pkg.installed: + - refresh: True + - skip_suggestions: True + - install_recommends: False + - pkgs: + - qubes-app-shutdown-idle + - qubes-pdf-converter + - qubes-img-converter + - man-db + - vim + - mutt + - notmuch-mutt + - w3m + - less + - urlview + +"{{ slsdotpath }}-reader-symlink-msmtpq": + file.symlink: + - require: + - pkg: "{{ slsdotpath }}-reader-installed" + - name: /usr/bin/msmtpq + - target: /usr/libexec/msmtp/msmtpq/msmtpq + - force: True + +"{{ slsdotpath }}-reader-symlink-msmtp-queue": + file.symlink: + - require: + - pkg: "{{ slsdotpath }}-reader-installed" + - name: /usr/bin/msmtp-queue + - target: /usr/libexec/msmtp/msmtpq/msmtp-queue + - force: True + +"{{ slsdotpath }}-reader-rpc": + file.managed: + - name: /etc/qubes-rpc/qusal.MailFetch + - source: salt://{{ slsdotpath }}/files/reader/rpc/qusal.MailFetch + - mode: "0755" + - user: root + - group: root + - makedirs: True + +"{{ slsdotpath }}-reader-bin": + file.managed: + - name: /usr/bin/qusal-send-mail + - source: salt://{{ slsdotpath }}/files/reader/bin/qusal-send-mail + - mode: "0755" + - user: root + - group: root + - makedirs: True + +{% endif -%} diff --git a/salt/mutt/install.top b/salt/mail/install-reader.top similarity index 73% rename from salt/mutt/install.top rename to salt/mail/install-reader.top index 490adf5..e067959 100644 --- a/salt/mutt/install.top +++ b/salt/mail/install-reader.top @@ -5,5 +5,5 @@ SPDX-License-Identifier: AGPL-3.0-or-later #} base: - 'tpl-mutt': - - mutt.install + 'tpl-mail-reader': + - mail.install-reader diff --git a/salt/mutt/install.sls b/salt/mail/install-sender.sls similarity index 58% rename from salt/mutt/install.sls rename to salt/mail/install-sender.sls index e5a2d53..862a82b 100644 --- a/salt/mutt/install.sls +++ b/salt/mail/install-sender.sls @@ -10,35 +10,21 @@ include: - dotfiles.copy-x11 - dotfiles.copy-sh - dotfiles.copy-net - - dotfiles.copy-mutt - - sys-pgp.install-client -"{{ slsdotpath }}-updated": +"{{ slsdotpath }}-sender-updated": pkg.uptodate: - refresh: True -"{{ slsdotpath }}-installed": +"{{ slsdotpath }}-sender-installed": pkg.installed: - refresh: True - skip_suggestions: True - install_recommends: False - pkgs: - # general - - qubes-app-shutdown-idle - qubes-core-agent-networking - - qubes-pdf-converter - - qubes-img-converter - - w3m - - man-db - - less - # mutt - - vim - - mutt - - notmuch - - notmuch-mutt - - offlineimap3 - - mb2md - ca-certificates + - man-db + - msmtp - libgnutls30 - libio-socket-ssl-perl - libnet-smtp-ssl-perl @@ -46,10 +32,14 @@ include: - libsasl2-2 - libsasl2-modules - libsasl2-modules-db - # git-email - - git-email - - libemail-valid-perl - - libmailtools-perl - - libauthen-sasl-perl + +"{{ slsdotpath }}-sender-rpc": + file.managed: + - name: /etc/qubes-rpc/qusal.MailEnqueue + - source: salt://{{ slsdotpath }}/files/sender/rpc/qusal.MailEnqueue + - mode: "0755" + - user: root + - group: root + - makedirs: True {% endif -%} diff --git a/salt/mail/install-sender.top b/salt/mail/install-sender.top new file mode 100644 index 0000000..6398c42 --- /dev/null +++ b/salt/mail/install-sender.top @@ -0,0 +1,9 @@ +{# +SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. + +SPDX-License-Identifier: AGPL-3.0-or-later +#} + +base: + 'tpl-mail-sender': + - mail.install-sender diff --git a/salt/mutt/README.md b/salt/mutt/README.md deleted file mode 100644 index e1f46f2..0000000 --- a/salt/mutt/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# mutt - -Mutt text-based mail client in Qubes OS. - -## Table of Contents - -* [Description](#description) -* [Installation](#installation) -* [Usage](#usage) - -## Description - -Create a mail client qube named "mutt" based on the program Mutt. - -## Installation - -- Top -```sh -qubesctl top.enable mutt -qubesctl --targets=tpl-mutt,mutt state.apply -qubesctl top.disable mutt -qubesctl state.apply mutt.appmenus -``` - -- State - -```sh -qubesctl state.apply mutt.create -qubesctl --skip-dom0 --targets=tpl-mutt state.apply mutt.install -qubesctl --skip-dom0 --targets=mutt state.apply mutt.configure -qubesctl state.apply mutt.appmenus -``` - - -## Usage - -You will use local files to override the ones provided by this package. Few -options must be set. - -The file `~/.muttrc-credentials.local` will set some variables that will be -used by other configuration files sourced later: -```muttrc -set pgp_default_key = "0x1234567890ABCDEF" -set pgp_sign_as = "0x1234567890ABCDEF" -set my_name = "Bilbo Baggins" -set my_user = "bilbo" -set my_server = "shire.org" -set my_pass = "mypassword" -``` - -You can define aliases in `~/.muttrc-aliases.local`. - -If you want to override any option, put the settings in `~/.muttrc.local`, -as this is the last file to be sourced. You might want to put for example, -subscribed lists in this file: -```muttrc -lists .*@googlegroups\\.com -subscribe qubes-(announce|devel)@googlegroups\\.com -fcc-save-hook qubes-announce@googlegroups\\.com =list/qubes-announce/ -fcc-save-hook qubes-devel@googlegroups\\.com =list/qubes-devel/ -``` - -If you want to have your e-mail signature (not PGP) at the end of every mail -you send, place it in `~/.signature`. diff --git a/salt/mutt/create.sls b/salt/mutt/create.sls deleted file mode 100644 index 47dc179..0000000 --- a/salt/mutt/create.sls +++ /dev/null @@ -1,51 +0,0 @@ -{# -SPDX-FileCopyrightText: 2023 Benjamin Grande M. S. - -SPDX-License-Identifier: AGPL-3.0-or-later -#} - -{%- from "qvm/template.jinja" import load -%} - -include: - - .clone - -{% load_yaml as defaults -%} -name: tpl-{{ slsdotpath }} -force: True -require: -- sls: {{ slsdotpath }}.clone -prefs: -- audiovm: "" -features: -- set: - - menu-items: "mutt.desktop qubes-run-terminal.desktop qubes-start.desktop" - - default-menu-items: "mutt.desktop qubes-run-terminal.desktop qubes-start.desktop" -{%- endload %} -{{ load(defaults) }} - -{% load_yaml as defaults -%} -name: {{ slsdotpath }} -force: True -require: -- sls: {{ slsdotpath }}.clone -present: -- template: tpl-{{ slsdotpath }} -- label: yellow -prefs: -- template: tpl-{{ slsdotpath }} -- label: yellow -- audiovm: "" -- vcpus: 1 -- memory: 200 -- maxmem: 350 -- autostart: False -features: -- enable: - - service.split-gpg2-client - - service.shutdown-idle -- disable: - - service.cups - - service.cups-browsed - - service.tinyproxy -{%- endload %} -{{ load(defaults) }} diff --git a/salt/utils/macros/clone-template.sls b/salt/utils/macros/clone-template.sls index 73fe0ac..fea1665 100644 --- a/salt/utils/macros/clone-template.sls +++ b/salt/utils/macros/clone-template.sls @@ -13,16 +13,13 @@ Usage: {{ clone_template('debian-minimal', sls_path) }} #} -{% macro clone_template(source, name, noprefix) -%} +{% macro clone_template(source, name, prefix='tpl-', include_create=True) -%} {%- import source ~ "/template.jinja" as template -%} +{% if include_create -%} include: - {{ source }}.create - -{% set prefix = "tpl-" -%} -{% if noprefix is defined -%} - {%- set prefix = "" -%} {% endif -%} "{{ prefix }}{{ name }}-clone":