reorganize service and add timer, require auth on viewer

This commit is contained in:
Cyberes 2024-03-06 18:17:08 -07:00
parent 1fad7e1b23
commit fb1180ae60
6 changed files with 71 additions and 4 deletions

View File

@ -12,16 +12,33 @@ Does not support different accounts.
## Install ## Install
### Archiver
1. Create a venv 1. Create a venv
2. `pip install -r requirements.txt` 2. `pip install -r requirements.txt`
3. `cp config.yml.sample config.yml` 3. `cp config.yml.sample config.yml`
4. Edit `config.yml` and configure your login info. 4. Edit `config.yml` and configure your login info.
5. `python3 run.py` 5. `python3 archiver.py`
A sample systemd service file is included. ### Viewer
1. `sudo mkdir /etc/secrets`
2. `sudo chown -R root:root /etc/secrets`
3. Generate your password:
```shell
echo -n "<your password>" | base64
```
4. Edit `/etc/secrets/imapviewer` with this content:
```shell
SQLITE3_DB=<path to your sqlite3 database>
HTTP_AUTH_PASS=<your encoded password>
```
5. `sudo chmod 600 /etc/secrets/imapviewer`
6. Reload and start the service.
Sample systemd services file is included.
## To Do ## To Do
- [ ] Fix subject decoding. Some character sets aren't detected correctly. - [ ] Fix subject decoding. Some character sets aren't detected correctly.
- [ ] Sync Gmail categories as folders.
- [ ] In the viewer, format the raw email to something viewable. - [ ] In the viewer, format the raw email to something viewable.

View File

@ -4,3 +4,4 @@ humanize==4.9.0
mmh3==4.1.0 mmh3==4.1.0
flask==3.0.2 flask==3.0.2
python-magic==0.4.27 python-magic==0.4.27
flask_httpauth==4.8.0

View File

@ -1,3 +1,4 @@
import base64
import json import json
import os import os
import sqlite3 import sqlite3
@ -6,11 +7,31 @@ from pathlib import Path
import magic import magic
from flask import Flask, render_template, send_from_directory from flask import Flask, render_template, send_from_directory
from flask_httpauth import HTTPBasicAuth
app = Flask(__name__) app = Flask(__name__)
if not os.environ.get('SQLITE3_DB'): if not os.environ.get('SQLITE3_DB'):
raise Exception('SQLITE3_DB not set.') raise Exception('SQLITE3_DB not set.')
if not os.environ.get('HTTP_AUTH_PASS'):
raise Exception('HTTP_AUTH_PASS not set.')
try:
user_password = base64.b64decode(os.environ.get('HTTP_AUTH_PASS')).decode().replace('\n', '')
except UnicodeDecodeError:
raise Exception('Cannot decode password. Is it base64 encoded?')
auth = HTTPBasicAuth()
users = {
'admin': user_password,
}
@auth.get_password
def get_pw(username):
if username in users:
return users.get(username)
return None
def get_db_connection(): def get_db_connection():
@ -24,6 +45,7 @@ def dict_from_row(row):
@app.route('/') @app.route('/')
@auth.login_required
def index(): def index():
conn = get_db_connection() conn = get_db_connection()
folders = conn.execute('SELECT name, table_name FROM folders_mapping').fetchall() folders = conn.execute('SELECT name, table_name FROM folders_mapping').fetchall()
@ -36,6 +58,7 @@ def index():
@app.route('/folder/<table_name>') @app.route('/folder/<table_name>')
@auth.login_required
def folder(table_name): def folder(table_name):
conn = get_db_connection() conn = get_db_connection()
emails = conn.execute(f'SELECT * FROM {table_name} ORDER BY timestamp DESC').fetchall() emails = conn.execute(f'SELECT * FROM {table_name} ORDER BY timestamp DESC').fetchall()
@ -47,6 +70,7 @@ def folder(table_name):
@app.route('/email/<table_name>/<id>') @app.route('/email/<table_name>/<id>')
@auth.login_required
def email(table_name, id): def email(table_name, id):
conn = get_db_connection() conn = get_db_connection()
email = conn.execute(f'SELECT * FROM {table_name} WHERE id = ?', (id,)).fetchone() email = conn.execute(f'SELECT * FROM {table_name} WHERE id = ?', (id,)).fetchone()
@ -58,6 +82,7 @@ def email(table_name, id):
@app.route('/attachments/<path:filename>') @app.route('/attachments/<path:filename>')
@auth.login_required
def download_file(filename): def download_file(filename):
mimetype = magic.from_file(str(Path('attachments', filename)), mime=True) mimetype = magic.from_file(str(Path('attachments', filename)), mime=True)
return send_from_directory('attachments', filename, mimetype=mimetype) return send_from_directory('attachments', filename, mimetype=mimetype)

View File

@ -0,0 +1,9 @@
[Unit]
Description=IMAP archiver service timer
[Timer]
OnBootSec=15min
OnUnitActiveSec=12h
[Install]
WantedBy=timers.target

View File

@ -0,0 +1,15 @@
[Unit]
Description=IMAP archiver viewer
Wants=network-online.target
After=network-online.target
[Service]
User=emailsync
Group=emailsync
EnvironmentFile=/etc/secrets/imapviewer
ExecStart=/srv/email/imap-archiver/venv/bin/python3 /srv/email/imap-archiver/server.py
SyslogIdentifier=imap-viewer
Restart=on-failure
[Install]
WantedBy=multi-user.target