mirror of
https://github.com/profullstack/agentbbs.git
synced 2026-08-13 14:27:27 +00:00
* feat(mail): give every verified member a free @bbs.profullstack.com mailbox Email was built but paid-only (Founding Lifetime gate) and never wired to a running backend. Make it a free benefit of membership and split the address domain from the mail-server host. - internal/mailu: Mailu admin-API client; EnsureUser idempotently provisions a mailbox via the loopback admin REST API (token = mailu.env API_TOKEN). - main.go: auto-provision <name>@<mailDomain> at join@ verification and on first Mail open; un-gate the Mail hub entry + mail@ (membership/email-verified, not Premium); address domain (AGENTBBS_MAIL_ADDR_DOMAIN, default the BBS host) is now distinct from the mail server host (AGENTBBS_MAIL_DOMAIN) and the webmail URL. Drop the forwardemail alias path (Mailu now owns delivery for everyone). - mailbox: gate on membership (a registered handle) instead of Paid; ErrNotPaid -> ErrNotMember. - join@ copy: list email under free membership; premium now pitches custom domains + Tor only. - setup.sh / docs/mail.md / deploy/mailu: address-domain vs server-host split, Mailu API token, MX for the address domain, local-relay SMTP for verify codes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(mailu): pin Docker network subnet to match SUBNET; ignore runtime state The base compose declares no network, so Docker assigns the default bridge an arbitrary subnet that won't match mailu.env SUBNET — breaking Mailu's internal service auth/relay. Add a docker-compose.override.yml.example that pins the default network to 192.168.203.0/24, and gitignore the live override + Mailu runtime state (mailu.env, certs/, data/). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(mail): plaintext loopback IMAP so the gateway bypasses Mailu's front Mailu's front (nginx mail proxy) pre-authenticates against Mailu's user DB before proxying to Dovecot, which rejects the Dovecot master-user login <addr>*gateway. The gateway must reach Dovecot directly. The imap container has no TLS cert (only the front does), so the bypass is plaintext over loopback — the master password never leaves the host. - mailbox: IMAPConfig.Plaintext dials with DialInsecure (loopback only). - main.go: mailClientFor sets Plaintext from AGENTBBS_MAIL_IMAP_PLAINTEXT. - override.example: add the unbound resolver (admin needs DNSSEC), webmail image fix (2024.06 uses mailu/webmail), and publish Dovecot 143 on 127.0.0.1:14143. - docs/mail.md: document the front-bypass, the dovecot.conf master passdb (Mailu includes that exact filename), and the 644 master-users perms (640 = temp_fail). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * deploy(mailu): wire gateway IMAP to the loopback Dovecot path in setup.sh setup.sh §9e set AGENTBBS_MAIL_IMAP_ADDR to the front's :993, which the front's auth proxy rejects for the master-user login (and would clobber the working loopback wiring on every self-update). Point it at 127.0.0.1:14143 + AGENTBBS_MAIL_IMAP_PLAINTEXT=1 instead, matching the override + docs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(mail): give free members a webmail password at join@ The gateway opens mailboxes via the Dovecot master user (no member password), but webmail (Roundcube) needs the member to have a password. join@ now sets a fresh, readable webmail password via the Mailu API and shows it with the webmail URL + login, so free members can use webmail at mail.profullstack.com. - mailu: SetPassword (PATCH /user/<email> raw_password) + test. - main.go: setWebmailPassword + readablePassword; join@ displays url/login/password. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
51 lines
2 KiB
Bash
Executable file
51 lines
2 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# provision-mailbox.sh — create or update a member mailbox on the Mailu stack.
|
|
# Run on the mail host. The agentbbs gateway opens any member's mailbox via the
|
|
# Dovecot master user, so members never need an individual IMAP password — but
|
|
# the mailbox must exist, which is what this creates.
|
|
#
|
|
# Usage:
|
|
# provision-mailbox.sh <name> # create <name>@$DOMAIN (random pw)
|
|
# provision-mailbox.sh --master <pass> # (re)create the gateway master user
|
|
#
|
|
# Idempotent: re-running for an existing user is a no-op (or a password reset
|
|
# with --password). Wraps Mailu's admin CLI (flask mailu ...).
|
|
set -euo pipefail
|
|
|
|
MAILU_DIR="${MAILU_DIR:-/opt/agentbbs/deploy/mailu}"
|
|
# The address domain (the @-part), which may differ from the mail server host.
|
|
DOMAIN="${MAIL_ADDR_DOMAIN:-${MAIL_DOMAIN:-bbs.profullstack.com}}"
|
|
MASTER_USER="${AGENTBBS_MAIL_MASTER_USER:-gateway}"
|
|
QUOTA_BYTES="${MAIL_QUOTA_BYTES:-1000000000}" # 1 GB
|
|
|
|
cli() { ( cd "$MAILU_DIR" && docker compose exec -T admin flask mailu "$@" ); }
|
|
|
|
if [ "${1:-}" = "--master" ]; then
|
|
pass="${2:?usage: provision-mailbox.sh --master <password>}"
|
|
# A Dovecot master user can authenticate as any mailbox: login "<name>*gateway".
|
|
# Implemented in Mailu as a normal user flagged for master access via an
|
|
# override (see docs/mail.md); here we ensure the account + password exist.
|
|
cli user "$MASTER_USER" "$DOMAIN" "$pass" 2>/dev/null \
|
|
|| cli password "$MASTER_USER" "$DOMAIN" "$pass"
|
|
echo "gateway master user ${MASTER_USER}@${DOMAIN} set"
|
|
exit 0
|
|
fi
|
|
|
|
name="${1:?usage: provision-mailbox.sh <name>}"
|
|
pass="${2:-$(openssl rand -hex 16)}"
|
|
|
|
if cli user-import "$name" "$DOMAIN" "$(openssl passwd -6 "$pass")" 2>/dev/null; then
|
|
:
|
|
else
|
|
# already exists or older CLI: fall back to `user` (no-op if present)
|
|
cli user "$name" "$DOMAIN" "$pass" 2>/dev/null || true
|
|
fi
|
|
# Enforce a per-mailbox quota.
|
|
cli config-update <<EOF 2>/dev/null || true
|
|
users:
|
|
- email: ${name}@${DOMAIN}
|
|
quota_bytes: ${QUOTA_BYTES}
|
|
EOF
|
|
|
|
echo "mailbox ${name}@${DOMAIN} provisioned"
|