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:
49
server/mail_perms.mjs
Normal file
49
server/mail_perms.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
||||
|
||||
export function load_mail_perms(file_path) {
|
||||
let allowed = [];
|
||||
|
||||
if (file_path && existsSync(file_path)) {
|
||||
try {
|
||||
const parsed = JSON.parse(readFileSync(file_path, 'utf8'));
|
||||
if (!Array.isArray(parsed.allowed)) {
|
||||
throw new Error("'allowed' must be an array");
|
||||
}
|
||||
allowed = parsed.allowed;
|
||||
} catch (err) {
|
||||
throw new Error(`Cannot load mail permissions from ${file_path}: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
function write() {
|
||||
if (!file_path) {
|
||||
return;
|
||||
}
|
||||
writeFileSync(file_path, JSON.stringify({ allowed }, null, '\t') + '\n', 'utf8');
|
||||
}
|
||||
|
||||
function check(user, to, topic) {
|
||||
return allowed.some(e => e.user === user && e.to === to && e.topic === topic);
|
||||
}
|
||||
|
||||
function add(user, to, topic) {
|
||||
if (!check(user, to, topic)) {
|
||||
allowed.push({ user, to, topic });
|
||||
write();
|
||||
}
|
||||
}
|
||||
|
||||
function remove(user, to, topic) {
|
||||
const before = allowed.length;
|
||||
allowed = allowed.filter(e => !(e.user === user && e.to === to && e.topic === topic));
|
||||
if (allowed.length !== before) {
|
||||
write();
|
||||
}
|
||||
}
|
||||
|
||||
function list() {
|
||||
return [...allowed];
|
||||
}
|
||||
|
||||
return { check, add, remove, list };
|
||||
}
|
||||
Reference in New Issue
Block a user