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:
@@ -2,7 +2,8 @@
|
||||
// policy: "auto-accept" | "auto-deny" | "queue"
|
||||
|
||||
|
||||
import { resolve_path, exec } from "./helpers.mjs";
|
||||
import { resolve_path, exec } from './helpers.mjs';
|
||||
import { check_can_approve } from './auth.mjs';
|
||||
|
||||
export const actions = {
|
||||
"list-actions": {
|
||||
@@ -67,4 +68,56 @@ export const actions = {
|
||||
return { opened: resolved };
|
||||
},
|
||||
},
|
||||
|
||||
'send-email': {
|
||||
description: 'Send an email to a permitted recipient',
|
||||
params: [
|
||||
{ name: 'to', required: true, type: 'string' },
|
||||
{ name: 'subject', required: true, type: 'string' },
|
||||
{ name: 'body', required: true, type: 'string' },
|
||||
{ name: 'topic', required: true, type: 'string' },
|
||||
],
|
||||
policy: 'auto-accept',
|
||||
handler: async ({ to, subject, body, topic }, { caller, mail_perm_store, mailer_send }) => {
|
||||
if (!mail_perm_store.check(caller, to, topic)) {
|
||||
throw new Error(`Mail permission denied: ${caller} → ${to} [${topic}]`);
|
||||
}
|
||||
await mailer_send(to, subject, body);
|
||||
return { sent: true, to, topic };
|
||||
},
|
||||
},
|
||||
|
||||
'set-mail-permission': {
|
||||
description: 'Grant or revoke permission for a user to send email to a recipient/topic',
|
||||
params: [
|
||||
{ name: 'target_user', required: true, type: 'string' },
|
||||
{ name: 'to', required: true, type: 'string' },
|
||||
{ name: 'topic', required: true, type: 'string' },
|
||||
{ name: 'allow', required: true, type: 'boolean' },
|
||||
],
|
||||
policy: 'auto-accept',
|
||||
handler: ({ target_user, to, topic, allow }, { caller, users, mail_perm_store }) => {
|
||||
if (!check_can_approve(users, caller, target_user)) {
|
||||
throw new Error(`Not authorized to set mail permissions for '${target_user}'`);
|
||||
}
|
||||
if (allow) {
|
||||
mail_perm_store.add(target_user, to, topic);
|
||||
} else {
|
||||
mail_perm_store.remove(target_user, to, topic);
|
||||
}
|
||||
return { target_user, to, topic, allow, permissions: mail_perm_store.list() };
|
||||
},
|
||||
},
|
||||
|
||||
'get-mail-permissions': {
|
||||
description: 'List current mail permissions, optionally filtered by user',
|
||||
params: [
|
||||
{ name: 'target_user', required: false, type: 'string' },
|
||||
],
|
||||
policy: 'auto-accept',
|
||||
handler: ({ target_user }, { mail_perm_store }) => {
|
||||
const all = mail_perm_store.list();
|
||||
return { permissions: target_user ? all.filter(e => e.user === target_user) : all };
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user