Implement email support with per-user permission model (closes #2)

New modules:
- server/mailer.mjs: nodemailer transport wrapper
- server/mail_perms.mjs: runtime permission store, persisted to disk

New actions:
- send-email: checks (caller, to, topic) permission before sending
- set-mail-permission: grant/revoke permissions, gated by canApprove
- get-mail-permissions: list current permissions

Handler signature extended to handler(params, ctx) where ctx carries
caller, users, mail_perm_store and mailer_send. Existing handlers
ignore ctx so the change is backwards-compatible.

SMTP config lives in secrets.json under optional 'smtp' key.
Mail permissions path via --mail-perms or CONDUIT_MAIL_PERMS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-17 22:34:26 +00:00
parent 5fb9d3ce07
commit b1ccbfef41
8 changed files with 190 additions and 12 deletions

18
server/mailer.mjs Normal file
View File

@@ -0,0 +1,18 @@
import nodemailer from 'nodemailer';
// Returns an async send(to, subject, body) function.
// If smtp_config is absent, returns a stub that always throws.
export function create_mailer(smtp_config) {
if (!smtp_config) {
return async () => {
throw new Error('SMTP not configured');
};
}
const { from, ...transport_config } = smtp_config;
const transporter = nodemailer.createTransport(transport_config);
return async function send(to, subject, body) {
await transporter.sendMail({ from, to, subject, text: body });
};
}