Merge pull request 'Rename GPG-Mailgate to Lacre' (#138) from 81_rename-to-lacre into main
Reviewed-on: #138
This commit is contained in:
commit
d75ded751e
|
@ -29,10 +29,10 @@ pip-log.txt
|
|||
.tox
|
||||
nosetests.xml
|
||||
|
||||
# GPG-Mailgate test files
|
||||
# Lacre test files
|
||||
test/logs
|
||||
test/tmp
|
||||
test/gpg-mailgate.conf
|
||||
test/lacre.conf
|
||||
test/keyhome/random_seed
|
||||
|
||||
# Emacs files
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
#
|
||||
# gpg-mailgate
|
||||
# lacre
|
||||
#
|
||||
# This file is part of the gpg-mailgate source code.
|
||||
# This file is part of the lacre source code.
|
||||
#
|
||||
# gpg-mailgate is free software: you can redistribute it and/or modify
|
||||
# lacre is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gpg-mailgate source code is distributed in the hope that it will be useful,
|
||||
# lacre source code is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
# along with lacre source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
"""GnuPG wrapper module."""
|
||||
|
|
70
INSTALL.md
70
INSTALL.md
|
@ -3,19 +3,19 @@
|
|||
## Content
|
||||
|
||||
- General information
|
||||
- Install GPG-Mailgate
|
||||
- Install GPG-Mailgate-Web
|
||||
- Install Lacre
|
||||
- Install [Lacre-Webgate](https://git.disroot.org/Lacre/lacre-webgate)
|
||||
- Install Register-handler
|
||||
|
||||
## General information
|
||||
|
||||
GPG-Mailgate is divided in 3 main parts: GPG-Mailgate itself, GPG-Mailgate-Web and Register-handler. Some parts of the GPG-Mailgate project depend on other parts of the project. You will find information about these dependencies at the beginning of every installation part.
|
||||
Lacre is divided in 3 main parts: Lacre itself, Lacre-Webgate and Register-handler. Some parts of the Lacre project depend on other parts of the project. You will find information about these dependencies at the beginning of every installation part.
|
||||
|
||||
These instructions show you how to set up GPG-Mailgate in an easy way. If you are a more advanced user, feel free to experiment with the settings. For these instructions a home directory for the user `nobody` is set. Sadly this is an odd workaround but no better solution was found.
|
||||
These instructions show you how to set up Lacre in an easy way. If you are a more advanced user, feel free to experiment with the settings. For these instructions a home directory for the user `nobody` is set. Sadly this is an odd workaround but no better solution was found.
|
||||
|
||||
These instructions are based on an installation on an Ubuntu 14.04 LTS virtual machine. For other Linux distributions and other versions these instructions might need to be adapted to your distribution (e.g. installation of packages and used directories).
|
||||
|
||||
## Install GPG-Mailgate
|
||||
## Install Lacre
|
||||
|
||||
### Requirements
|
||||
|
||||
|
@ -41,29 +41,26 @@ usermod -d /var/gpgmailgate nobody
|
|||
3. Create dedicated directories for storing PGP keys and S/MIME certificates and make the user `nobody` owner of these:
|
||||
|
||||
```
|
||||
mkdir -p /var/gpgmailgate/.gnupg
|
||||
mkdir -p /var/gpgmailgate/smime
|
||||
chown -R nobody:nogroup /var/gpgmailgate/
|
||||
install -u nobody -g nobody -d /var/gpgmailgate/ /var/gpgmailgate/.gnupg /var/gpgmailgate/smime
|
||||
```
|
||||
|
||||
4. Place the `gpg-mailgate.py` in `/usr/local/bin/`, make the user `nobody` owner of the file and make it executable:
|
||||
4. Place the `lacre.py` in `/usr/local/bin/`, make the user `nobody` owner of the file and make it executable:
|
||||
|
||||
```
|
||||
chown nobody:nogroup /usr/local/bin/gpg-mailgate.py
|
||||
chmod u+x /usr/local/bin/gpg-mailgate.py
|
||||
install -u nobody -g nobody -mode u=rx lacre.py /usr/local/bin/
|
||||
```
|
||||
|
||||
5. Place the `GnuPG` directory in `/usr/local/lib/python3.x/dist-packages` (replace 3.x with your Python version)
|
||||
5. Place `GnuPG` and `lacre` directories in `/usr/local/lib/python3.x/dist-packages` (replace 3.x with your Python version). Make sure they're available for Python `import`s by executing `python -m lacre.admin -h` command.
|
||||
|
||||
6. Configure `/etc/gpg-mailgate.conf` based on the provided `gpg-mailgate.conf.sample`. Change the settings according to your configuration. If you follow this guide and have a standard configuration for postfix, you don't need to change much.
|
||||
6. Configure `/etc/lacre.conf` based on the provided `lacre.conf.sample`. Change the settings according to your configuration. If you follow this guide and have a standard configuration for postfix, you don't need to change much.
|
||||
|
||||
7. Configure logging by copying `gpg-lacre-logging.conf.sample` to `/etc/gpg-lacre-logging.conf` and editing it according to your needs. The path to this file is included in `[logging]` section of `gpg-mailgate.conf` file, so if you place it somewhere else, make sure to update the path too. See also: [Configuration file format](https://docs.python.org/3/library/logging.config.html#configuration-file-format).
|
||||
7. Configure logging by copying `lacre-logging.conf.sample` to `/etc/lacre-logging.conf` and editing it according to your needs. The path to this file is included in `[logging]` section of `lacre.conf` file, so if you place it somewhere else, make sure to update the path too. See also: Python logging package's [Configuration file format](https://docs.python.org/3/library/logging.config.html#configuration-file-format).
|
||||
|
||||
8. Add the following to the end of `/etc/postfix/master.cf`
|
||||
|
||||
```
|
||||
gpg-mailgate unix - n n - - pipe
|
||||
flags= user=nobody argv=/usr/local/bin/gpg-mailgate.py ${recipient}
|
||||
lacre unix - n n - - pipe
|
||||
flags= user=nobody argv=/usr/local/bin/lacre.py ${recipient}
|
||||
|
||||
127. 0. 0. 1:10028 inet n - n - 10 smtpd
|
||||
-o content_filter=
|
||||
|
@ -76,12 +73,12 @@ gpg-mailgate unix - n n - - pipe
|
|||
-o smtpd_authorized_xforward_hosts=127. 0. 0. 0/8
|
||||
```
|
||||
|
||||
If you use Postfix versions from 2.5 onwards, it is recommended to change `${recipient}` to `${original_recipient}` in line two of the lines above.
|
||||
If you use Postfix versions from 2.5 onwards, it is recommended to change `${recipient}` to `${original_recipient}` in second line of the snippet above.
|
||||
|
||||
9. Add the following line to `/etc/postfix/main.cf`
|
||||
|
||||
```
|
||||
content_filter = gpg-mailgate
|
||||
content_filter = lacre
|
||||
```
|
||||
|
||||
10. Optional: GPG can automatically download new public keys for automatic signature verification. To enable automatic create the file `/var/gpgmailgate/.gnupg/gpg.conf`. Add the following line to the file:
|
||||
|
@ -98,22 +95,23 @@ You are now ready to go. To add a public key for encryption just use the followi
|
|||
sudo -u nobody /usr/bin/gpg --homedir=/var/gpgmailgate/.gnupg --import /some/public.key
|
||||
```
|
||||
|
||||
- Replace `/some/public.key` with the location of a public key
|
||||
- `/some/public.key` can be deleted after importation
|
||||
- Replace `/some/public.key` with the location of a public key (`/some/public.key` can be deleted after the import).
|
||||
- Confirm that it's working: `sudo -u nobody /usr/bin/gpg --list-keys --homedir=/var/gpgmailgate/.gnupg`
|
||||
|
||||
If you already have a keyring you would like to import into Lacre, you can use `lacre.admin` command-line utility. Read more in [Lacre administration](doc/admin.md).
|
||||
|
||||
Please also test your installation before using it.
|
||||
|
||||
GPG-Mailgate is also able to handle S/MIME certificates for encrypting mails. However, it is best to use it in combination with Register-Handler described later to add new certificates. If you try to add them manually it might fail. The certificates are stored in `/var/gpgmailgate/smime` in PKCS7 format and are named like `User@example.com` (the user part is case sensitive, the domain part should be in lower case).
|
||||
Lacre is also able to handle S/MIME certificates for encrypting mails. However, it is best to use it in combination with Register-Handler described later to add new certificates. If you try to add them manually it might fail. The certificates are stored in `/var/gpgmailgate/smime` in PKCS7 format and are named like `User@example.com` (the user part is case sensitive, the domain part should be in lower case).
|
||||
|
||||
#### Additional settings
|
||||
|
||||
Most mail servers do not handle mail addresses case sensitive. If you know that all your recipient mail servers do not care about case sensitivity then you can set `mail_case_insensitive` in the settings to `yes` so looking up PGP keys or S/MIME certificates does also happen case insensitive.
|
||||
If your recipients have problems to decrypt mails encrypted by GPG-Mailgate they might use a piece of software that does not support PGP/MIME encrypted mails. You can tell GPG-Mailgate to use the legacy PGP/INLINE format by adding the recipient to the `pgp_style` map in the following format:
|
||||
If your recipients have problems to decrypt mails encrypted by Lacre they might use a piece of software that does not support PGP/MIME encrypted mails. You can tell Lacre to use the legacy PGP/INLINE format by adding the recipient to the `pgp_style` map in the following format:
|
||||
`User@example.com=inline`
|
||||
|
||||
|
||||
## Install GPG-Mailgate-Web
|
||||
## Install Lacre-Webgate
|
||||
|
||||
### Requirements
|
||||
|
||||
|
@ -134,13 +132,13 @@ repository.
|
|||
apt-get install python-mysqldb python-markdown
|
||||
```
|
||||
|
||||
2. Create a new database for GPG-Mailgate-Web.
|
||||
2. Create a new database for Lacre-Webgate.
|
||||
|
||||
3. Import the schema file `schema.sql` into the newly created database.
|
||||
|
||||
4. Edit the config file located at `/etc/gpg-mailgate.conf`. Set `enabled = yes` in `[database]` and fill in the necessary settings for the database connection.
|
||||
4. Edit the config file located at `/etc/lacre.conf`. Set `enabled = yes` in `[database]` and fill in the necessary settings for the database connection.
|
||||
|
||||
5. Copy the files located in the [public_html](gpg-mailgate-web/public_html) directory onto your webserver. They can also be placed in a subdirectory on your webserver.
|
||||
5. Copy the files located in the [public_html](https://git.disroot.org/Lacre/lacre-webgate/src/branch/main/public_html) directory onto your webserver. They can also be placed in a subdirectory on your webserver.
|
||||
|
||||
6. On your webserver move the `config.sample.php` file to `config.php` and edit the configuration file.
|
||||
|
||||
|
@ -156,28 +154,27 @@ mkdir -p /var/gpgmailgate/cron_templates
|
|||
chown -R nobody:nogroup /var/gpgmailgate/cron_templates
|
||||
```
|
||||
|
||||
9. Copy `cron.py` to `/usr/local/bin/gpgmw-cron.py`. Make it executable and and transfer ownership to `nobody`:
|
||||
9. Copy `cron.py` to `/usr/local/bin/cron.py`. Make it executable and and transfer ownership to `nobody`:
|
||||
|
||||
```
|
||||
chown nobody:nogroup /usr/local/bin/gpgmw-cron.py
|
||||
chmod u+x /usr/local/bin/gpgmw-cron.py
|
||||
install -u nobody -g nobody -m u+x cron.py /usr/local/bin/lacre-cron.py
|
||||
```
|
||||
|
||||
10. Create `/etc/cron.d/gpgmw` with contents:
|
||||
`*/3 * * * * nobody /usr/bin/python /usr/local/bin/gpgmw-cron.py > /dev/null`
|
||||
10. Create `/etc/cron.d/lacre-cron` with contents:
|
||||
`*/3 * * * * nobody /usr/bin/python /usr/local/bin/lacre-cron.py > /dev/null`
|
||||
for executing the cron job automatically.
|
||||
|
||||
11. Test your installation.
|
||||
|
||||
### GPG-Mailgate-Web as keyserver
|
||||
### Lacre-Webgate as keyserver
|
||||
|
||||
GPG-Mailgate-Web can also be used as a keyserver. For more information have a look at GPG-Mailgate-Web's [readme](gpg-mailgate-web/README).
|
||||
Lacre-Webgate can also be used as a keyserver. For more information have a look at Lacre-Webgate's [README](https://git.disroot.org/Lacre/lacre-webgate/src/branch/main/README.md).
|
||||
|
||||
## Install Register-handler
|
||||
|
||||
### Requirements
|
||||
|
||||
- Already set up and working GPG-Mailgate-Web. It should be reachable from the machine that will run register-handler
|
||||
- Already set up and working Lacre-Webgate. It should be reachable from the machine that will run register-handler
|
||||
- Postfix is already installed and configured. It is recommended that you have already tested your configuration so we can exclude this as a main cause of problems. Your Postfix configuration should also support aliases
|
||||
|
||||
### Installation
|
||||
|
@ -203,11 +200,10 @@ chown -R nobody:nogroup /var/gpgmailgate/register_templates
|
|||
4. Copy `register-handler.py` to `/usr/local/bin/register-handler.py`. Make it executable and own it to `nobody`:
|
||||
|
||||
```
|
||||
chown nobody:nogroup /usr/local/bin/register-handler.py
|
||||
chmod a+x /usr/local/bin/register-handler.py
|
||||
install -u nobody -g nogroup -m a+x register-handler.py /usr/local/bin/
|
||||
```
|
||||
|
||||
5. Edit the config file located at `/etc/gpg-mailgate.conf`. Set the parameter `webpanel_url` in `[mailregister]` to the url of your GPG-Mailgate-Web panel (the URL should be the same as the one you use to access the panel with your web browser). Also set the parameter `register_email` to the email address you want the user to see when receiving mails from the register-handler (it does not have to be an existing address but it is recommended). Register-handler will send users mails when they are registering S/MIME certificates or when neither a S/MIME certificate nor a PGP key was found in a mail sent to the register-handler.
|
||||
5. Edit the config file located at `/etc/lacre.conf`. Set the parameter `webpanel_url` in `[mailregister]` to the url of your Lacre-Webgate panel (the URL should be the same as the one you use to access the panel with your web browser). Also set the parameter `register_email` to the email address you want the user to see when receiving mails from the register-handler (it does not have to be an existing address but it is recommended). Register-handler will send users mails when they are registering S/MIME certificates or when neither a S/MIME certificate nor a PGP key was found in a mail sent to the register-handler.
|
||||
|
||||
6. Add `register: |/usr/local/bin/register-handler.py` to `/etc/aliases`
|
||||
|
||||
|
|
14
Makefile
14
Makefile
|
@ -28,9 +28,9 @@ test: e2etest daemontest unittest crontest
|
|||
#
|
||||
# Run a set of end-to-end tests.
|
||||
#
|
||||
# Test scenarios are described and configured by the test/e2e.ini
|
||||
# file. Basically this is just a script that feeds GPG Mailgate with
|
||||
# known input and checks whether output meets expectations.
|
||||
# Test scenarios are described and configured by the test/e2e.ini file.
|
||||
# Basically this is just a script that feeds Lacre with known input and checks
|
||||
# whether output meets expectations.
|
||||
#
|
||||
e2etest: test/tmp test/logs pre-clean restore-keyhome
|
||||
$(PYTHON) test/e2e_test.py
|
||||
|
@ -39,11 +39,11 @@ e2etest: test/tmp test/logs pre-clean restore-keyhome
|
|||
# Run a basic cron-job test.
|
||||
#
|
||||
# We use PYTHONPATH to make sure that cron.py can import GnuPG
|
||||
# package. We also set GPG_MAILGATE_CONFIG env. variable to make sure
|
||||
# package. We also set LACRE_CONFIG env. variable to make sure
|
||||
# it slurps the right config.
|
||||
#
|
||||
crontest: clean-db $(TEST_DB)
|
||||
GPG_MAILGATE_CONFIG=test/gpg-mailgate-cron-test.conf PYTHONPATH=`pwd` \
|
||||
LACRE_CONFIG=test/lacre-daemon.conf PYTHONPATH=`pwd` \
|
||||
$(PYTHON) webgate-cron.py
|
||||
|
||||
$(TEST_DB):
|
||||
|
@ -64,10 +64,10 @@ clean-db:
|
|||
# Run unit tests
|
||||
#
|
||||
unittest:
|
||||
GPG_MAILGATE_CONFIG=test/gpg-mailgate.conf $(PYTHON) -m unittest discover -s test/modules
|
||||
LACRE_CONFIG=test/lacre.conf $(PYTHON) -m unittest discover -s test/modules
|
||||
|
||||
pre-clean:
|
||||
rm -fv test/gpg-mailgate.conf
|
||||
rm -fv test/lacre.conf
|
||||
rm -f test/logs/*.log
|
||||
|
||||
restore-keyhome:
|
||||
|
|
33
doc/admin.md
33
doc/admin.md
|
@ -11,6 +11,20 @@ python -m lacre.admin -h
|
|||
|
||||
Of course `-h` displays some help.
|
||||
|
||||
**Note:** Help output includes information about the configuration file being
|
||||
in use, which may be useful at times.
|
||||
|
||||
|
||||
## Initialising database schema
|
||||
|
||||
If you want to initialise Lacre's database (which is also used by the
|
||||
frontend), run:
|
||||
|
||||
```sh
|
||||
python -m lacre.admin database -i
|
||||
```
|
||||
|
||||
|
||||
## Inspecting key confirmation queue
|
||||
|
||||
To find out how many keys are waiting to be confirmed, run:
|
||||
|
@ -19,6 +33,19 @@ To find out how many keys are waiting to be confirmed, run:
|
|||
python -m lacre.admin queue
|
||||
```
|
||||
|
||||
To see identities (emails) waiting for confirmation, use `--list` (or `-l`)
|
||||
option:
|
||||
|
||||
```sh
|
||||
python -m lacre.admin queue -l
|
||||
```
|
||||
|
||||
To delete one of these emails, use `--delete` (or `-d`) option:
|
||||
|
||||
```sh
|
||||
python -m lacre.admin queue -d malory@example.org
|
||||
```
|
||||
|
||||
## Inspecting identities registered
|
||||
|
||||
To list all identities, run:
|
||||
|
@ -35,12 +62,12 @@ python -m lacre.admin identities -e alice@example.com
|
|||
|
||||
## Importing identities from existing GnuPG keyring
|
||||
|
||||
If you already have a GnuPG keyring with your users' public keys or for some
|
||||
If you already have a GnuPG keyring with your users' public keys or for some
|
||||
reason Lacre's identity database needs to be re-populated with identities,
|
||||
there's a command to do that:
|
||||
there's a command to do that:
|
||||
|
||||
```sh
|
||||
python -m lacre.admin import -d /path/to/gnupg/directory
|
||||
python -m lacre.admin import -d /path/to/gnupg/directory
|
||||
```
|
||||
|
||||
If you want to just re-populate the database, Lacre can remove all identities
|
||||
|
|
|
@ -33,13 +33,13 @@ setting port to `10026`.
|
|||
Command to spawn a Lacre daemon process is:
|
||||
|
||||
```
|
||||
GPG_MAILGATE_CONFIG=/etc/gpg-mailgate.conf PYTHONPATH=... python -m lacre.daemon
|
||||
LACRE_CONFIG=/etc/lacre.conf PYTHONPATH=... python -m lacre.daemon
|
||||
```
|
||||
|
||||
Two environment variables used here are:
|
||||
|
||||
* `GPG_MAILGATE_CONFIG` (not mandatory) -- path to Lacre configuration,
|
||||
unless it's kept in default location (`/etc/gpg-maillgate.conf`).
|
||||
* `LACRE_CONFIG` (not mandatory) -- path to Lacre configuration,
|
||||
unless it's kept in default location (`/etc/lacre.conf`).
|
||||
* `PYTHONPATH` (not mandatory) -- location of Lacre modules. You can place
|
||||
them below your Python's `site-packages` to be reachable by any other
|
||||
Python software.
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# gpg-mailgate
|
||||
#
|
||||
# This file is part of the gpg-mailgate source code.
|
||||
#
|
||||
# gpg-mailgate is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gpg-mailgate source code is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import email
|
||||
from email.policy import SMTPUTF8
|
||||
import sys
|
||||
import time
|
||||
import logging
|
||||
|
||||
import lacre
|
||||
import lacre.config as conf
|
||||
|
||||
start = time.process_time()
|
||||
conf.load_config()
|
||||
lacre.init_logging(conf.get_item('logging', 'config'))
|
||||
|
||||
# This has to be executed *after* logging initialisation.
|
||||
import lacre.core as core
|
||||
|
||||
LOG = logging.getLogger('gpg-mailgate.py')
|
||||
|
||||
missing_params = conf.validate_config(additional=conf.SCRIPT_REQUIRED)
|
||||
config_file = conf.config_source()
|
||||
|
||||
if missing_params:
|
||||
LOG.error(f"Aborting delivery! Following mandatory config parameters are missing in {config_file!r}: {missing_params}")
|
||||
sys.exit(lacre.EX_CONFIG)
|
||||
|
||||
delivered = False
|
||||
try:
|
||||
# Read e-mail from stdin, parse it
|
||||
raw = sys.stdin.read()
|
||||
raw_message = email.message_from_string(raw, policy=SMTPUTF8)
|
||||
from_addr = raw_message['From']
|
||||
# Read recipients from the command-line
|
||||
to_addrs = sys.argv[1:]
|
||||
|
||||
# Let's start
|
||||
core.deliver_message(raw_message, from_addr, to_addrs)
|
||||
process_t = (time.process_time() - start) * 1000
|
||||
|
||||
LOG.info("Message delivered in {process:.2f} ms".format(process=process_t))
|
||||
delivered = True
|
||||
except:
|
||||
LOG.exception('Could not handle message')
|
||||
|
||||
if not delivered:
|
||||
# It seems we weren't able to deliver the message. In case it was some
|
||||
# silly message-encoding issue that shouldn't bounce the message, we just
|
||||
# try recoding the message body and delivering it.
|
||||
try:
|
||||
core.failover_delivery(raw_message, to_addrs, from_addr)
|
||||
except:
|
||||
LOG.exception('Failover delivery failed too')
|
|
@ -1,11 +1,11 @@
|
|||
[default]
|
||||
# Whether gpg-mailgate should add a header after it has processed an email
|
||||
# Whether lacre should add a header after it has processed an email
|
||||
# This may be useful for debugging purposes
|
||||
add_header = yes
|
||||
|
||||
# Whether we should only encrypt emails if they are explicitly defined in
|
||||
# the key mappings below ([enc_keymap] section)
|
||||
# This means gpg-mailgate won't automatically detect PGP recipients for encrypting
|
||||
# This means lacre won't automatically detect PGP recipients for encrypting
|
||||
enc_keymap_only = no
|
||||
|
||||
# Convert encrypted text/plain email to MIME-attached encrypt style.
|
||||
|
@ -20,36 +20,36 @@ mime_conversion = yes
|
|||
mail_case_insensitive = no
|
||||
|
||||
[gpg]
|
||||
# the directory where gpg-mailgate public keys are stored
|
||||
# the directory where lacre public keys are stored
|
||||
# (see INSTALL for details)
|
||||
#
|
||||
# Note that this directory should be accessible only for the Lacre user,
|
||||
# i.e. have mode 700.
|
||||
keyhome = /var/gpgmailgate/.gnupg
|
||||
keyhome = /var/lacre/.gnupg
|
||||
|
||||
[smime]
|
||||
# the directory for the S/MIME certificate files
|
||||
cert_path = /var/gpgmailgate/smime
|
||||
cert_path = /var/lacre/smime
|
||||
|
||||
[mailregister]
|
||||
# settings for the register-handler
|
||||
register_email = register@yourdomain.tld
|
||||
mail_templates = /var/gpgmailgate/register_templates
|
||||
mail_templates = /var/lacre/register_templates
|
||||
|
||||
# URL to webpanel. Upon receiving an email with a key, register-handler
|
||||
# uploads it to the web panel.
|
||||
webpanel_url = http://yourdomain.tld
|
||||
|
||||
[cron]
|
||||
# settings for the gpgmw cron job
|
||||
# settings for the cron job
|
||||
send_email = yes
|
||||
notification_email = gpg-mailgate@yourdomain.tld
|
||||
mail_templates = /var/gpgmailgate/cron_templates
|
||||
notification_email = lacre@yourdomain.tld
|
||||
mail_templates = /var/lacre/cron_templates
|
||||
|
||||
[logging]
|
||||
# path to the logging configuration; see documentation for details:
|
||||
# https://docs.python.org/3/library/logging.config.html#logging-config-fileformat
|
||||
config = /etc/gpg-lacre-logging.conf
|
||||
config = /etc/lacre-logging.conf
|
||||
|
||||
[daemon]
|
||||
# Advanced Content Filter section.
|
||||
|
@ -75,12 +75,12 @@ bounce_on_keys_missing = no
|
|||
|
||||
[relay]
|
||||
# the relay settings to use for Postfix
|
||||
# gpg-mailgate will submit email to this relay after it is done processing
|
||||
# lacre will submit email to this relay after it is done processing
|
||||
# unless you alter the default Postfix configuration, you won't have to modify this
|
||||
host = 127.0.0.1
|
||||
port = 10028
|
||||
# This is the default port of postfix. It is used to send some
|
||||
# mails through the GPG-Mailgate so they are encrypted
|
||||
# mails through the Lacre so they are encrypted
|
||||
enc_port = 25
|
||||
|
||||
# Set this option to yes to use TLS for SMTP Servers which require TLS.
|
||||
|
@ -89,7 +89,7 @@ starttls = no
|
|||
[smtp]
|
||||
# Options when smtp auth is required to send out emails
|
||||
enabled = false
|
||||
username = gpg-mailgate
|
||||
username = lacre
|
||||
password = changeme
|
||||
host = yourdomain.tld
|
||||
port = 587
|
||||
|
@ -97,7 +97,7 @@ starttls = true
|
|||
|
||||
[database]
|
||||
# edit the settings below if you want to read keys from a
|
||||
# gpg-mailgate-web database other than SQLite
|
||||
# lacre-webgate database other than SQLite
|
||||
enabled = yes
|
||||
url = sqlite:///test.db
|
||||
|
||||
|
@ -112,10 +112,10 @@ url = sqlite:///test.db
|
|||
#
|
||||
pooling_mode = optimistic
|
||||
|
||||
# For a MySQL database "gpgmw", user "gpgmw" and password "password",
|
||||
# For a MySQL database "lacre", user "lacre" and password "password",
|
||||
# use the following URL:
|
||||
#
|
||||
#url = mysql://gpgmw:password@localhost/gpgmw
|
||||
#url = mysql://lacre:password@localhost/lacre
|
||||
#
|
||||
# For other RDBMS backends, see:
|
||||
# https://docs.sqlalchemy.org/en/14/core/engines.html#database-urls
|
|
@ -0,0 +1,73 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# lacre
|
||||
#
|
||||
# This file is part of the lacre source code.
|
||||
#
|
||||
# lacre is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# lacre source code is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with lacre source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import email
|
||||
from email.policy import SMTPUTF8
|
||||
import sys
|
||||
import logging
|
||||
|
||||
import lacre
|
||||
import lacre.config as conf
|
||||
from lacre.stats import time_logger
|
||||
|
||||
conf.load_config()
|
||||
lacre.init_logging(conf.get_item('logging', 'config'))
|
||||
|
||||
# This has to be executed *after* logging initialisation.
|
||||
import lacre.core as core
|
||||
|
||||
LOG = logging.getLogger('lacre.py')
|
||||
|
||||
def main():
|
||||
with time_logger('Message delivery', LOG):
|
||||
missing_params = conf.validate_config()
|
||||
config_file = conf.config_source()
|
||||
|
||||
if missing_params:
|
||||
LOG.error(f"Aborting delivery! Following mandatory config parameters are missing in {config_file!r}: {missing_params}")
|
||||
sys.exit(lacre.EX_CONFIG)
|
||||
|
||||
delivered = False
|
||||
try:
|
||||
# Read e-mail from stdin, parse it
|
||||
raw = sys.stdin.read()
|
||||
raw_message = email.message_from_string(raw, policy=SMTPUTF8)
|
||||
from_addr = raw_message['From']
|
||||
# Read recipients from the command-line
|
||||
to_addrs = sys.argv[1:]
|
||||
|
||||
# Let's start
|
||||
core.deliver_message(raw_message, from_addr, to_addrs)
|
||||
delivered = True
|
||||
except:
|
||||
LOG.exception('Could not handle message')
|
||||
|
||||
if not delivered:
|
||||
# It seems we weren't able to deliver the message. In case it was
|
||||
# some silly message-encoding issue that shouldn't bounce the
|
||||
# message, we just try recoding the message body and delivering it.
|
||||
try:
|
||||
core.failover_delivery(raw_message, to_addrs, from_addr)
|
||||
except:
|
||||
LOG.exception('Failover delivery failed too')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -18,12 +18,26 @@ lacre.init_logging(conf.get_item('logging', 'config'))
|
|||
import lacre.repositories as repo
|
||||
import lacre.dbschema as db
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
if __name__ == '__main__':
|
||||
LOG = logging.getLogger('lacre.admin')
|
||||
else:
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _no_database():
|
||||
print('Database unavailable or not configured properly')
|
||||
exit(lacre.EX_CONFIG)
|
||||
sys.exit(lacre.EX_CONFIG)
|
||||
|
||||
|
||||
def sub_db(args):
|
||||
"""Sub-command to manipulate database."""
|
||||
LOG.debug('Database operations ahead')
|
||||
|
||||
if args.init:
|
||||
eng = repo.init_engine(conf.get_item('database', 'url'))
|
||||
LOG.warning('Initialising database schema with engine: %s', eng)
|
||||
print('Creating database tables')
|
||||
db.create_tables(eng)
|
||||
|
||||
|
||||
def sub_queue(args):
|
||||
|
@ -35,6 +49,12 @@ def sub_queue(args):
|
|||
|
||||
if args.delete:
|
||||
queue.delete_key_by_email(args.delete)
|
||||
elif args.list:
|
||||
for k in queue.fetch_keys():
|
||||
print(f'- {k.id}: {k.email}')
|
||||
elif args.to_delete:
|
||||
for k in queue.fetch_keys_to_delete():
|
||||
print(f'- {k.id}: {k.email}')
|
||||
else:
|
||||
cnt = queue.count_keys()
|
||||
if cnt is None:
|
||||
|
@ -86,7 +106,10 @@ def sub_import(args):
|
|||
|
||||
|
||||
def main():
|
||||
conf.validate_config(additional=conf.SCRIPT_REQUIRED)
|
||||
missing = conf.validate_config()
|
||||
if missing:
|
||||
LOG.error('Missing configuration parameters: %s', missing)
|
||||
sys.exit(lacre.EX_CONFIG)
|
||||
|
||||
general_conf = conf.config_source()
|
||||
log_conf = conf.get_item('logging', 'config')
|
||||
|
@ -99,6 +122,14 @@ def main():
|
|||
|
||||
sub_commands = parser.add_subparsers(help='Sub-commands', required=True)
|
||||
|
||||
cmd_db = sub_commands.add_parser('database',
|
||||
help='',
|
||||
aliases=['db']
|
||||
)
|
||||
cmd_db.add_argument('-i', '--init', action='store_true',
|
||||
help='Initialise database schema')
|
||||
cmd_db.set_defaults(operation=sub_db)
|
||||
|
||||
cmd_import = sub_commands.add_parser('import',
|
||||
help='Load identities from GnuPG directory to Lacre database'
|
||||
)
|
||||
|
@ -114,6 +145,10 @@ def main():
|
|||
)
|
||||
cmd_queue.add_argument('-D', '--delete',
|
||||
help='delete specified email from the queue')
|
||||
cmd_queue.add_argument('-l', '--list', action='store_true',
|
||||
help='list keys in the queue')
|
||||
cmd_queue.add_argument('-d', '--to-delete', action='store_true',
|
||||
help='list keys to be deleted')
|
||||
cmd_queue.set_defaults(operation=sub_queue)
|
||||
|
||||
cmd_identities = sub_commands.add_parser('identities',
|
||||
|
|
|
@ -11,9 +11,9 @@ import os
|
|||
|
||||
|
||||
# Environment variable name we read to retrieve configuration path. This is to
|
||||
# enable non-root users to set up and run GPG Mailgate and to make the software
|
||||
# enable non-root users to set up and run Lacre and to make the software
|
||||
# testable.
|
||||
CONFIG_PATH_ENV = "GPG_MAILGATE_CONFIG"
|
||||
CONFIG_PATH_ENV = "LACRE_CONFIG"
|
||||
|
||||
# List of mandatory configuration parameters. Each item on this list should be
|
||||
# a pair: a section name and a parameter name.
|
||||
|
@ -21,16 +21,12 @@ MANDATORY_CONFIG_ITEMS = [("relay", "host"),
|
|||
("relay", "port"),
|
||||
("daemon", "host"),
|
||||
("daemon", "port"),
|
||||
("gpg", "keyhome")]
|
||||
("gpg", "keyhome"),
|
||||
('database', 'enabled'),
|
||||
('database', 'url'),
|
||||
('database', 'pooling_mode')]
|
||||
|
||||
SCRIPT_REQUIRED = [('database', 'enabled'),
|
||||
('database', 'url'),
|
||||
('database', 'pooling_mode')]
|
||||
|
||||
CRON_REQUIRED = [('database', 'enabled'),
|
||||
('database', 'url'),
|
||||
('database', 'pooling_mode'),
|
||||
('cron', 'mail_templates')]
|
||||
CRON_REQUIRED = [('cron', 'mail_templates')]
|
||||
|
||||
# Global dict to keep configuration parameters. It's hidden behind several
|
||||
# utility functions to make it easy to replace it with ConfigParser object in
|
||||
|
@ -44,7 +40,7 @@ def load_config() -> dict:
|
|||
If environment variable identified by CONFIG_PATH_ENV
|
||||
variable is set, its value is taken as a configuration file
|
||||
path. Otherwise, the default is taken
|
||||
('/etc/gpg-mailgate.conf').
|
||||
('/etc/lacre.conf').
|
||||
"""
|
||||
config_file = config_source()
|
||||
|
||||
|
@ -61,9 +57,9 @@ def load_config() -> dict:
|
|||
def config_source() -> str:
|
||||
"""Return path of configuration file.
|
||||
|
||||
Taken from GPG_MAILGATE_CONFIG environment variable, and if it's not
|
||||
set, defaults to /etc/gpg-mailgate.conf."""
|
||||
return os.getenv(CONFIG_PATH_ENV, '/etc/gpg-mailgate.conf')
|
||||
Taken from LACRE_CONFIG environment variable, and if it's not
|
||||
set, defaults to /etc/lacre.conf."""
|
||||
return os.getenv(CONFIG_PATH_ENV, '/etc/lacre.conf')
|
||||
|
||||
|
||||
def _read_config(fileName) -> RawConfigParser:
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
#
|
||||
# gpg-mailgate
|
||||
# lacre
|
||||
#
|
||||
# This file is part of the gpg-mailgate source code.
|
||||
# This file is part of the lacre source code.
|
||||
#
|
||||
# gpg-mailgate is free software: you can redistribute it and/or modify
|
||||
# lacre is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gpg-mailgate source code is distributed in the hope that it will be useful,
|
||||
# lacre source code is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
# along with lacre source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
"""Lacre's actual mail-delivery module.
|
||||
|
@ -142,7 +142,7 @@ def _gpg_encrypt_and_deliver(message: EmailMessage, keys, recipients, encrypt_f)
|
|||
|
||||
def _customise_headers(message: EmailMessage):
|
||||
if conf.flag_enabled('default', 'add_header'):
|
||||
message['X-GPG-Mailgate'] = 'Encrypted by GPG Mailgate'
|
||||
message['X-Lacre'] = 'Encrypted by Lacre'
|
||||
|
||||
|
||||
def _encrypt_all_payloads_inline(message: EmailMessage, gpg_to_cmdline):
|
||||
|
|
|
@ -13,7 +13,7 @@ import email
|
|||
from email.policy import SMTPUTF8
|
||||
|
||||
# Load configuration and init logging, in this order. Only then can we load
|
||||
# the last Lacre module, i.e. lacre.mailgate.
|
||||
# the last Lacre module, i.e. lacre.core.
|
||||
conf.load_config()
|
||||
lacre.init_logging(conf.get_item("logging", "config"))
|
||||
LOG = logging.getLogger('lacre.daemon')
|
||||
|
|
|
@ -7,32 +7,58 @@ This definition includes:
|
|||
|
||||
- 'lacre_identities' -- identity catalogue, used by encryption logic to match
|
||||
emails with corresponding keys.
|
||||
|
||||
- 'lacre_locks' -- used only by the frontend.
|
||||
"""
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
# Values for lacre_keys.status column:
|
||||
# - ST_DEFAULT: initial state;
|
||||
# - ST_IMPORTED: key has been successfully processed by cron job;
|
||||
# - ST_TO_BE_DELETED: key can be deleted.
|
||||
ST_DEFAULT, ST_IMPORTED, ST_TO_BE_DELETED = range(3)
|
||||
|
||||
# lacre_keys.confirmed is set to an empty string when a key is confirmed by the user.
|
||||
CO_CONFIRMED = ''
|
||||
|
||||
_meta = sqlalchemy.MetaData()
|
||||
|
||||
LACRE_KEYS = sqlalchemy.Table('lacre_keys', _meta,
|
||||
sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True),
|
||||
sqlalchemy.Column('email', sqlalchemy.String(256)),
|
||||
sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True, autoincrement='auto'),
|
||||
sqlalchemy.Column('email', sqlalchemy.String(256), index=True),
|
||||
# ASCII-armored key
|
||||
sqlalchemy.Column('publickey', sqlalchemy.Text),
|
||||
# Empty string means this key has been confirmed.
|
||||
sqlalchemy.Column('confirm', sqlalchemy.String(32)),
|
||||
# Status: see ST_* constants at the top of the file.
|
||||
sqlalchemy.Column('status', sqlalchemy.Integer),
|
||||
sqlalchemy.Column('status', sqlalchemy.Integer, nullable=False),
|
||||
sqlalchemy.Column('time', sqlalchemy.DateTime))
|
||||
|
||||
LACRE_LOCKS = sqlalchemy.Table('lacre_locks', _meta,
|
||||
sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True, nullable=False, autoincrement='auto'),
|
||||
sqlalchemy.Column('ip', sqlalchemy.String(16)),
|
||||
sqlalchemy.Column('time', sqlalchemy.Integer),
|
||||
sqlalchemy.Column('action', sqlalchemy.String(16)),
|
||||
sqlalchemy.Column('num', sqlalchemy.Integer),
|
||||
)
|
||||
|
||||
LACRE_IDENTITIES = sqlalchemy.Table('lacre_identities', _meta,
|
||||
sqlalchemy.Column('email', sqlalchemy.String(256), index=True),
|
||||
sqlalchemy.Column('email', sqlalchemy.String(256), index=True, nullable=False),
|
||||
# Key fingerprint
|
||||
sqlalchemy.Column('fingerprint', sqlalchemy.String(64), index=True))
|
||||
sqlalchemy.Column('fingerprint', sqlalchemy.String(64), index=True, nullable=False))
|
||||
|
||||
def init_identities_table() -> sqlalchemy.Table:
|
||||
return LACRE_IDENTITIES
|
||||
|
||||
def init_locks_table() -> sqlalchemy.Table:
|
||||
return LACRE_LOCKS
|
||||
|
||||
def init_keys_table() -> sqlalchemy.Table:
|
||||
return LACRE_KEYS
|
||||
|
||||
def create_tables(engine):
|
||||
_meta.create_all(engine)
|
||||
|
||||
def table_metadata():
|
||||
return _meta
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
#
|
||||
# gpg-mailgate
|
||||
# lacre
|
||||
#
|
||||
# This file is part of the gpg-mailgate source code.
|
||||
# This file is part of the lacre source code.
|
||||
#
|
||||
# gpg-mailgate is free software: you can redistribute it and/or modify
|
||||
# lacre is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gpg-mailgate source code is distributed in the hope that it will be useful,
|
||||
# lacre source code is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
# along with lacre source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
"""Recipient processing package.
|
||||
|
|
|
@ -17,17 +17,17 @@ _HOUR_IN_SECONDS = 3600
|
|||
_engine = None
|
||||
|
||||
|
||||
def init_engine(url):
|
||||
def init_engine(url, db_debug=False):
|
||||
global _engine
|
||||
|
||||
if not _engine:
|
||||
config = _conn_config()
|
||||
config = _conn_config(db_debug)
|
||||
_engine = create_engine(url, **config)
|
||||
|
||||
return _engine
|
||||
|
||||
|
||||
def _conn_config():
|
||||
def _conn_config(db_debug):
|
||||
config = dict()
|
||||
|
||||
mode = PoolingMode.from_config('database', 'pooling_mode', required=True)
|
||||
|
@ -45,6 +45,10 @@ def _conn_config():
|
|||
if config_item_set('database', 'max_overflow'):
|
||||
config['max_overflow'] = int(get_item('database', 'max_overflow'))
|
||||
|
||||
if db_debug:
|
||||
config['echo'] = 'debug'
|
||||
config['echo_pool'] = 'debug'
|
||||
|
||||
LOG.debug('Database engine configuration: %s', config)
|
||||
return config
|
||||
|
||||
|
@ -71,7 +75,7 @@ class IdentityRepository(KeyRing):
|
|||
def _insert(self, email, fprint):
|
||||
insq = self._identities.insert().values(email=email, fingerprint=fprint)
|
||||
|
||||
LOG.debug('Registering identity %s: %s', email, insq)
|
||||
LOG.debug('Registering identity: %s -- %s', insq, insq.compile().params)
|
||||
with self._engine.connect() as conn:
|
||||
conn.execute(insq)
|
||||
|
||||
|
@ -80,13 +84,13 @@ class IdentityRepository(KeyRing):
|
|||
.values(fingerprint=fprint) \
|
||||
.where(self._identities.c.email == email)
|
||||
|
||||
LOG.debug('Updating identity %s: %s', email, upq)
|
||||
LOG.debug('Updating identity: %s -- %s', upq, upq.compile().params)
|
||||
with self._engine.connect() as conn:
|
||||
conn.execute(upq)
|
||||
|
||||
def delete(self, email):
|
||||
delq = delete(self._identities).where(self._identities.c.email == email)
|
||||
LOG.debug('Deleting keys assigned to %s', email)
|
||||
LOG.debug('Deleting assigned keys: %s -- %s', delq, delq.compile().params)
|
||||
|
||||
with self._engine.connect() as conn:
|
||||
conn.execute(delq)
|
||||
|
@ -118,7 +122,7 @@ class IdentityRepository(KeyRing):
|
|||
all_identities = select(self._identities.c.fingerprint, self._identities.c.email)
|
||||
with self._engine.connect() as conn:
|
||||
result = conn.execute(all_identities)
|
||||
LOG.debug('Retrieving all keys')
|
||||
LOG.debug('Retrieving all keys: %s', all_identities)
|
||||
return KeyCache({key_id: email for key_id, email in result})
|
||||
|
||||
|
||||
|
@ -135,33 +139,37 @@ class KeyConfirmationQueue:
|
|||
def fetch_keys(self, /, max_keys=None):
|
||||
"""Runs a query to retrieve at most `keys_read_max` keys and returns db result."""
|
||||
max_keys = max_keys or self.keys_read_max
|
||||
LOG.debug('Row limit: %d', max_keys)
|
||||
|
||||
selq = select(self._keys.c.publickey, self._keys.c.id, self._keys.c.email) \
|
||||
.where(and_(self._keys.c.status == db.ST_DEFAULT, self._keys.c.confirm == "")) \
|
||||
.where(and_(self._keys.c.status == db.ST_DEFAULT, self._keys.c.confirm == db.CO_CONFIRMED)) \
|
||||
.limit(max_keys)
|
||||
|
||||
LOG.debug('Retrieving keys to be processed: %s', selq)
|
||||
LOG.debug('Retrieving keys to be processed: %s -- %s', selq, selq.compile().params)
|
||||
with self._engine.connect() as conn:
|
||||
return conn.execute(selq)
|
||||
return [e for e in conn.execute(selq)]
|
||||
|
||||
def count_keys(self):
|
||||
selq = select(func.count(self._keys.c.id))
|
||||
selq = select(func.count(self._keys.c.id)) \
|
||||
.where(and_(self._keys.c.status == db.ST_DEFAULT, self._keys.c.confirm == db.CO_CONFIRMED))
|
||||
|
||||
LOG.debug('Counting all keys: %s', selq)
|
||||
LOG.debug('Counting all keys: %s -- %s', selq, selq.compile().params)
|
||||
try:
|
||||
with self._engine.connect() as conn:
|
||||
c = [cnt for cnt in conn.execute(selq)]
|
||||
|
||||
# Result is an iterable of tuples:
|
||||
return c[0][0]
|
||||
res = conn.execute(selq)
|
||||
# This is a 1-element tuple.
|
||||
return res.one_or_none()[0]
|
||||
except OperationalError:
|
||||
LOG.exception('Cannot count keys')
|
||||
return None
|
||||
|
||||
def fetch_keys_to_delete(self):
|
||||
seldel = select(self._keys.c.email, self._keys.c.id).where(self._keys.c.status == db.ST_TO_BE_DELETED).limit(self.keys_read_max)
|
||||
seldel = select(self._keys.c.email, self._keys.c.id) \
|
||||
.where(self._keys.c.status == db.ST_TO_BE_DELETED) \
|
||||
.limit(self.keys_read_max)
|
||||
|
||||
with self._engine.connect() as conn:
|
||||
return conn.execute(seldel)
|
||||
return [e for e in conn.execute(seldel)]
|
||||
|
||||
def delete_keys(self, row_id, /, email=None):
|
||||
"""Remove key from the database."""
|
||||
|
@ -174,7 +182,7 @@ class KeyConfirmationQueue:
|
|||
|
||||
with self._engine.connect() as conn:
|
||||
LOG.debug('Deleting public keys associated with confirmed email: %s', delq)
|
||||
return conn.execute(delq)
|
||||
conn.execute(delq)
|
||||
|
||||
def delete_key_by_email(self, email):
|
||||
"""Remove keys linked to the given email from the database."""
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
#
|
||||
# gpg-mailgate
|
||||
# lacre
|
||||
#
|
||||
# This file is part of the gpg-mailgate source code.
|
||||
# This file is part of the lacre source code.
|
||||
#
|
||||
# gpg-mailgate is free software: you can redistribute it and/or modify
|
||||
# lacre is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gpg-mailgate source code is distributed in the hope that it will be useful,
|
||||
# lacre source code is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
# along with lacre source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
"""S/MIME handling module."""
|
||||
|
@ -75,7 +75,7 @@ def encrypt(raw_message, recipients, from_addr):
|
|||
out.write('Subject: ' + raw_message['Subject'] + text.EOL_S)
|
||||
|
||||
if conf.config_item_equals('default', 'add_header', 'yes'):
|
||||
out.write('X-GPG-Mailgate: Encrypted by GPG Mailgate' + text.EOL_S)
|
||||
out.write('X-Lacre: Encrypted by Lacre' + text.EOL_S)
|
||||
|
||||
s.write(out, p7)
|
||||
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
#
|
||||
# gpg-mailgate
|
||||
# lacre
|
||||
#
|
||||
# This file is part of the gpg-mailgate source code.
|
||||
# This file is part of the lacre source code.
|
||||
#
|
||||
# gpg-mailgate is free software: you can redistribute it and/or modify
|
||||
# lacre is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gpg-mailgate source code is distributed in the hope that it will be useful,
|
||||
# lacre source code is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
# along with lacre source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import configparser
|
||||
|
@ -30,7 +30,7 @@ def _spawn(cmd):
|
|||
"PATH": os.getenv("PATH"),
|
||||
"PYTHONPATH": os.getcwd(),
|
||||
"LANG": 'en_US.UTF-8',
|
||||
"GPG_MAILGATE_CONFIG": "test/gpg-mailgate-daemon-test.conf"
|
||||
"LACRE_CONFIG": "test/lacre-daemon.conf"
|
||||
}
|
||||
logging.debug(f"Spawning command: {cmd} with environment: {env_dict!r}")
|
||||
return subprocess.Popen(cmd,
|
||||
|
|
|
@ -32,8 +32,8 @@ certs: test/certs
|
|||
e2e_log: test/logs/e2e.log
|
||||
e2e_log_format: %(asctime)s %(pathname)s:%(lineno)d %(levelname)s [%(funcName)s] %(message)s
|
||||
e2e_log_datefmt: %Y-%m-%d %H:%M:%S
|
||||
lacre_log: test/logs/gpg-mailgate.log
|
||||
log_config: test/gpg-lacre-log.ini
|
||||
lacre_log: test/logs/lacre-simple.log
|
||||
log_config: test/lacre-logging.conf
|
||||
|
||||
# TEST IDENTITIES AND SETTINGS:
|
||||
#
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
#
|
||||
# gpg-mailgate
|
||||
# lacre
|
||||
#
|
||||
# This file is part of the gpg-mailgate source code.
|
||||
# This file is part of the lacre source code.
|
||||
#
|
||||
# gpg-mailgate is free software: you can redistribute it and/or modify
|
||||
# lacre is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gpg-mailgate source code is distributed in the hope that it will be useful,
|
||||
# lacre source code is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
# along with lacre source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import os
|
||||
|
@ -27,7 +27,7 @@ import unittest
|
|||
|
||||
|
||||
RELAY_SCRIPT = "test/utils/relay.py"
|
||||
CONFIG_FILE = "test/gpg-mailgate.conf"
|
||||
CONFIG_FILE = "test/lacre.conf"
|
||||
|
||||
|
||||
def _build_config(config):
|
||||
|
@ -129,7 +129,7 @@ class SimpleMailFilterE2ETest(unittest.TestCase):
|
|||
following properties: 'descr', 'to', 'in' and 'out'.
|
||||
"""
|
||||
gpglacre_cmd = self._python_command(
|
||||
'gpg-mailgate.py',
|
||||
'lacre.py',
|
||||
self._e2e_config.get(case_name, 'to'))
|
||||
|
||||
relay_cmd = self._python_command(
|
||||
|
@ -147,7 +147,7 @@ class SimpleMailFilterE2ETest(unittest.TestCase):
|
|||
gpglacre_proc = subprocess.run(gpglacre_cmd,
|
||||
input=_load_file(self._e2e_config.get(case_name, "in")),
|
||||
capture_output=True,
|
||||
env={"GPG_MAILGATE_CONFIG": self._e2e_config_path,
|
||||
env={"LACRE_CONFIG": self._e2e_config_path,
|
||||
"PATH": os.getenv("PATH")})
|
||||
|
||||
# Let the relay process the data.
|
||||
|
|
Binary file not shown.
|
@ -1,5 +1,5 @@
|
|||
[logging]
|
||||
config = test/gpg-lacre-log.ini
|
||||
config = test/lacre-logging.conf
|
||||
file = test/logs/gpg-mailgate.log
|
||||
format = %(asctime)s %(module)s[%(process)d]: %(message)s
|
||||
date_format = ISO
|
||||
|
@ -17,6 +17,8 @@ port = not_used
|
|||
[database]
|
||||
enabled = yes
|
||||
url = sqlite:///test/lacre.db
|
||||
pooling_mode = optimistic
|
||||
max_connection_age = 3600
|
||||
|
||||
[relay]
|
||||
host = localhost
|
|
@ -1,5 +1,5 @@
|
|||
[logging]
|
||||
config = test/gpg-lacre-log.ini
|
||||
config = test/lacre-logging.conf
|
||||
file = test/logs/gpg-mailgate.log
|
||||
format = %(asctime)s %(module)s[%(process)d]: %(message)s
|
||||
date_format = ISO
|
||||
|
@ -26,6 +26,7 @@ log_headers = yes
|
|||
|
||||
[cron]
|
||||
send_email = no
|
||||
mail_templates = not_used
|
||||
|
||||
[pgp_style]
|
||||
# this recipient has PGP/MIME enabled, because the default approach is to use
|
|
@ -1,20 +1,20 @@
|
|||
#
|
||||
# gpg-mailgate
|
||||
# lacre
|
||||
#
|
||||
# This file is part of the gpg-mailgate source code.
|
||||
# This file is part of the lacre source code.
|
||||
#
|
||||
# gpg-mailgate is free software: you can redistribute it and/or modify
|
||||
# lacre is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gpg-mailgate source code is distributed in the hope that it will be useful,
|
||||
# lacre source code is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
# along with lacre source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
"""Unit-tests as contracts for external dependencies.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/local/bin/python2
|
||||
#
|
||||
# This quick-and-dirty script supports only the happy case of SMTP session,
|
||||
# i.e. what gpg-mailgate/gpg-lacre needs to deliver encrypted email.
|
||||
# i.e. what lacre needs to deliver encrypted email.
|
||||
#
|
||||
# It listens on the port given as the only command-line argument and consumes a
|
||||
# message, then prints it to standard output. The goal is to be able to
|
||||
|
|
|
@ -90,8 +90,8 @@ AQgHiHgEGBYIACAWIQQZz0tH7MnEevqE1L2W85/aDjG7ZwUCYdTF4AIbDAAKCRCW\n\
|
|||
OjjB6xRD0Q2FN+alsNGCtdutAs18AZ5l33RMzws=\n\
|
||||
=wWoq\n\
|
||||
-----END PGP PUBLIC KEY BLOCK-----\
|
||||
", "status": 0, "confirm": "", "time": None},
|
||||
{"id": 3, "email": "cecil@lacre.io", "publickey": "RUBBISH", "status": 0, "confirm": "", "time": None}
|
||||
", "status": 1, "confirm": "", "time": None},
|
||||
{"id": 3, "email": "cecil@lacre.io", "publickey": "RUBBISH", "status": 2, "confirm": "", "time": None}
|
||||
])
|
||||
|
||||
conn.execute(identities.insert(), [
|
||||
|
|
101
webgate-cron.py
101
webgate-cron.py
|
@ -1,22 +1,22 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
#
|
||||
# gpg-mailgate
|
||||
# lacre
|
||||
#
|
||||
# This file is part of the gpg-mailgate source code.
|
||||
# This file is part of the lacre source code.
|
||||
#
|
||||
# gpg-mailgate is free software: you can redistribute it and/or modify
|
||||
# lacre is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# gpg-mailgate source code is distributed in the hope that it will be useful,
|
||||
# lacre source code is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with gpg-mailgate source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
# along with lacre source code. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import sys
|
||||
|
@ -25,7 +25,7 @@ import lacre
|
|||
import lacre.config as conf
|
||||
from lacre.notify import notify
|
||||
|
||||
# Read configuration from /etc/gpg-mailgate.conf
|
||||
# Read configuration from /etc/lacre.conf
|
||||
conf.load_config()
|
||||
|
||||
lacre.init_logging(conf.get_item('logging', 'config'))
|
||||
|
@ -42,6 +42,49 @@ def _validate_config():
|
|||
exit(lacre.EX_CONFIG)
|
||||
|
||||
|
||||
def import_key(key_dir, armored_key, key_id, email, key_queue, identities):
|
||||
# import the key to gpg
|
||||
(fingerprint, _) = GnuPG.add_key(key_dir, armored_key)
|
||||
|
||||
key_queue.mark_accepted(key_id)
|
||||
identities.register_or_update(email, fingerprint)
|
||||
|
||||
LOG.info('Imported key from: %s', email)
|
||||
if conf.flag_enabled('cron', 'send_email'):
|
||||
notify("PGP key registration successful", "registrationSuccess.md", email)
|
||||
|
||||
|
||||
def import_failed(key_id, email, key_queue):
|
||||
key_queue.delete_keys(key_id)
|
||||
LOG.warning('Import confirmation failed: %s', email)
|
||||
|
||||
if conf.flag_enabled('cron', 'send_email'):
|
||||
notify("PGP key registration failed", "registrationError.md", email)
|
||||
|
||||
|
||||
def delete_key(key_id, email, key_queue):
|
||||
# delete key so we don't continue processing it
|
||||
LOG.debug('Empty key received, just deleting')
|
||||
|
||||
key_queue.delete_keys(row_id)
|
||||
if conf.flag_enabled('cron', 'send_email'):
|
||||
notify("PGP key deleted", "keyDeleted.md", email)
|
||||
|
||||
|
||||
def cleanup(key_dir, key_queue):
|
||||
"""Delete keys and queue entries."""
|
||||
|
||||
LOG.info('Cleaning up after a round of key confirmation')
|
||||
for email, row_id in key_queue.fetch_keys_to_delete():
|
||||
LOG.debug('Removing key from keyring: %s', email)
|
||||
GnuPG.delete_key(key_dir, email)
|
||||
|
||||
LOG.debug('Removing key from identity store: %s', row_id)
|
||||
key_queue.delete_keys(row_id)
|
||||
|
||||
LOG.info('Deleted key for: %s', email)
|
||||
|
||||
|
||||
_validate_config()
|
||||
|
||||
if not (conf.flag_enabled('database', 'enabled') and conf.config_item_set('database', 'url')):
|
||||
|
@ -59,49 +102,23 @@ try:
|
|||
key_dir = conf.get_item('gpg', 'keyhome')
|
||||
LOG.debug('Using GnuPG with home directory in %s', key_dir)
|
||||
|
||||
result_set = key_queue.fetch_keys()
|
||||
|
||||
for armored_key, row_id, email in result_set:
|
||||
for armored_key, row_id, email in key_queue.fetch_keys():
|
||||
# delete any other public keys associated with this confirmed email address
|
||||
key_queue.delete_keys(row_id, email=email)
|
||||
identities.delete(email)
|
||||
GnuPG.delete_key(key_dir, email)
|
||||
LOG.info('Deleted key for <%s> via import request', email)
|
||||
LOG.info('Deleted key via import request for: %s', email)
|
||||
|
||||
if armored_key.strip(): # we have this so that user can submit blank key to remove any encryption
|
||||
if GnuPG.confirm_key(armored_key, email):
|
||||
# import the key to gpg
|
||||
(fingerprint, _) = GnuPG.add_key(key_dir, armored_key)
|
||||
|
||||
key_queue.mark_accepted(row_id)
|
||||
identities.register_or_update(email, fingerprint)
|
||||
|
||||
LOG.info('Imported key from <%s>', email)
|
||||
if conf.flag_enabled('cron', 'send_email'):
|
||||
notify("PGP key registration successful", "registrationSuccess.md", email)
|
||||
else:
|
||||
key_queue.delete_keys(row_id)
|
||||
LOG.warning('Import confirmation failed for <%s>', email)
|
||||
|
||||
if conf.flag_enabled('cron', 'send_email'):
|
||||
notify("PGP key registration failed", "registrationError.md", email)
|
||||
else:
|
||||
if not armored_key.strip(): # we have this so that user can submit blank key to remove any encryption
|
||||
# delete key so we don't continue processing it
|
||||
LOG.debug('Empty key received, just deleting')
|
||||
delete_key(row_id, email, key_queue)
|
||||
continue
|
||||
|
||||
key_queue.delete_keys(row_id)
|
||||
if conf.flag_enabled('cron', 'send_email'):
|
||||
notify("PGP key deleted", "keyDeleted.md", email)
|
||||
if GnuPG.confirm_key(armored_key, email):
|
||||
import_key(key_dir, armored_key, row_id, email, key_queue, identities)
|
||||
else:
|
||||
import_failed(row_id, email, key_queue)
|
||||
|
||||
LOG.info('Cleaning up after a round of key confirmation')
|
||||
stat2_result_set = key_queue.fetch_keys_to_delete()
|
||||
for email, row_id in stat2_result_set:
|
||||
LOG.debug('Removing key from keyring: %s', email)
|
||||
GnuPG.delete_key(key_dir, email)
|
||||
|
||||
LOG.debug('Removing key from identity store: %s', row_id)
|
||||
key_queue.delete_keys(row_id)
|
||||
|
||||
LOG.info('Deleted key for <%s>', email)
|
||||
cleanup(key_dir, key_queue)
|
||||
except:
|
||||
LOG.exception('Unexpected issue during key confirmation')
|
||||
|
|
Loading…
Reference in New Issue