Files
ActivePush/tools/dev/test-backends.sh
2026-11-05 12:52:32 +01:00

150 lines
4.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# Local throw-away backends for development and end-to-end tests:
# Dovecot IMAP 127.0.0.1:11143 (plain, test only)
# Radicale 127.0.0.1:15232 (CalDAV + CardDAV)
# SMTP sink 127.0.0.1:12525 (prints/stores every message, no auth)
# Test account: jan@test.local / Test-Password-123
#
# NEVER use this configuration in production. Ctrl+C stops everything.
set -euo pipefail
ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)"
DIR="${AP_TEST_DIR:-$ROOT/data/test-backends}"
RUN_USER="${AP_TEST_USER:-$(id -un)}"
if [[ "$RUN_USER" == "root" ]]; then
printf 'Run as a normal user or set AP_TEST_USER=<unprivileged user>.\n' >&2
exit 2
fi
for bin in dovecot radicale python3; do
command -v "$bin" >/dev/null 2>&1 || { printf 'Missing %s (apt install dovecot-imapd; pip install radicale aiosmtpd)\n' "$bin" >&2; exit 127; }
done
python3 -c 'import aiosmtpd' 2>/dev/null || { printf 'Missing python aiosmtpd (pip install aiosmtpd)\n' >&2; exit 127; }
UIDN="$(id -u "$RUN_USER")"; GIDN="$(id -g "$RUN_USER")"
mkdir -p "$DIR"/{mail,run,radicale,sink}
chown -R "$RUN_USER" "$DIR" 2>/dev/null || true
cat > "$DIR/users" <<EOF
jan@test.local:{PLAIN}Test-Password-123:$UIDN:$GIDN::$DIR/mail/jan
anna@test.local:{PLAIN}Test-Password-123:$UIDN:$GIDN::$DIR/mail/anna
biuro@test.local:{PLAIN}Test-Password-123:$UIDN:$GIDN::$DIR/mail/biuro
kasia@test.local:{PLAIN}Test-Password-123:$UIDN:$GIDN::$DIR/mail/kasia
EOF
cat > "$DIR/dovecot.conf" <<EOF
protocols = imap
listen = 127.0.0.1
base_dir = $DIR/run
state_dir = $DIR/run
default_internal_user = $RUN_USER
default_login_user = $RUN_USER
default_internal_group = $(id -gn "$RUN_USER")
first_valid_uid = 1
ssl = no
disable_plaintext_auth = no
auth_mechanisms = plain login
log_path = $DIR/dovecot.log
mail_location = maildir:~/Maildir
passdb {
driver = passwd-file
args = $DIR/users
}
userdb {
driver = passwd-file
args = $DIR/users
}
service imap-login {
inet_listener imap {
address = 127.0.0.1
port = 11143
}
inet_listener imaps {
port = 0
}
}
service anvil {
chroot =
}
service imap-login {
chroot =
}
namespace inbox {
inbox = yes
separator = /
mailbox Drafts {
special_use = \Drafts
auto = subscribe
}
mailbox Sent {
special_use = \Sent
auto = subscribe
}
mailbox Trash {
special_use = \Trash
auto = subscribe
}
mailbox Junk {
special_use = \Junk
auto = subscribe
}
}
EOF
# Radicale: htpasswd plain
for u in jan anna biuro kasia; do printf '%s@test.local:Test-Password-123\n' "$u"; done > "$DIR/radicale/users"
cat > "$DIR/radicale/config" <<EOF
[server]
hosts = 127.0.0.1:15232
[auth]
type = htpasswd
htpasswd_filename = $DIR/radicale/users
htpasswd_encryption = plain
[storage]
filesystem_folder = $DIR/radicale/collections
[rights]
type = owner_only
EOF
cat > "$DIR/sink.py" <<'EOF'
import asyncio, sys, time, os
from aiosmtpd.controller import Controller
out = sys.argv[1]
class H:
async def handle_DATA(self, server, session, envelope):
name = os.path.join(out, f"{time.time():.6f}.eml")
with open(name, "wb") as f:
f.write(f"X-Envelope-From: {envelope.mail_from}\r\nX-Envelope-To: {', '.join(envelope.rcpt_tos)}\r\n".encode())
f.write(envelope.content)
print(f"[smtp-sink] {envelope.mail_from} -> {envelope.rcpt_tos} ({len(envelope.content)} bytes) saved {name}", flush=True)
return "250 OK"
c = Controller(H(), hostname="127.0.0.1", port=12525)
c.start()
print("[smtp-sink] listening on 127.0.0.1:12525", flush=True)
try:
asyncio.new_event_loop().run_forever()
except KeyboardInterrupt:
pass
EOF
pids=()
cleanup() { for p in "${pids[@]}"; do kill "$p" 2>/dev/null || true; done; dovecot -c "$DIR/dovecot.conf" stop 2>/dev/null || true; }
trap cleanup EXIT INT TERM
dovecot -c "$DIR/dovecot.conf"
if [[ "$(id -un)" == "$RUN_USER" ]]; then
radicale -C "$DIR/radicale/config" >"$DIR/radicale.log" 2>&1 & pids+=($!)
python3 "$DIR/sink.py" "$DIR/sink" & pids+=($!)
else
su -s /bin/bash "$RUN_USER" -c "radicale -C '$DIR/radicale/config' >'$DIR/radicale.log' 2>&1" & pids+=($!)
su -s /bin/bash "$RUN_USER" -c "python3 '$DIR/sink.py' '$DIR/sink'" & pids+=($!)
fi
sleep 1
cat <<EOF
Test backends running (data in $DIR):
IMAP 127.0.0.1:11143 (security: none)
CalDAV http://127.0.0.1:15232 path /%u/
CardDAV http://127.0.0.1:15232 path /%u/
SMTP 127.0.0.1:12525 (auth: none, security: none) -> $DIR/sink
accounts jan, anna, biuro, kasia @test.local, password Test-Password-123
Apply matching settings with: ./dev.sh config apply tools/dev/test-settings.json
Press Ctrl+C to stop.
EOF
wait