webadmin: add single-line form for looking up a cid for a received id

This commit is contained in:
Mechiel Lukkien 2024-03-05 10:50:56 +01:00
parent 5738d9e7b8
commit a9cb6f9d0a
No known key found for this signature in database
5 changed files with 94 additions and 1 deletions

View file

@ -2217,3 +2217,10 @@ func (Admin) TLSRPTSuppressExtend(ctx context.Context, id int64, until time.Time
err := tlsrptdb.SuppressUpdate(ctx, id, until) err := tlsrptdb.SuppressUpdate(ctx, id, until)
xcheckf(ctx, err, "updating reporting address in suppresslist") xcheckf(ctx, err, "updating reporting address in suppresslist")
} }
// LookupCid turns an ID from a Received header into a cid as used in logging.
func (Admin) LookupCid(ctx context.Context, recvID string) (cid string) {
v, err := mox.ReceivedToCid(recvID)
xcheckf(ctx, err, "received id to cid")
return fmt.Sprintf("%x", v)
}

View file

@ -1028,6 +1028,14 @@ var api;
const params = [id, until]; const params = [id, until];
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params); return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
} }
// LookupCid turns an ID from a Received header into a cid as used in logging.
async LookupCid(recvID) {
const fn = "LookupCid";
const paramTypes = [["string"]];
const returnTypes = [["string"]];
const params = [recvID];
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
}
} }
api.Client = Client; api.Client = Client;
api.defaultBaseURL = (function () { api.defaultBaseURL = (function () {
@ -1596,6 +1604,9 @@ const index = async () => {
let domain; let domain;
let account; let account;
let localpart; let localpart;
let recvIDFieldset;
let recvID;
let cidElem;
dom._kids(page, crumbs('Mox Admin'), checkUpdatesEnabled ? [] : dom.p(box(yellow, 'Warning: Checking for updates has not been enabled in mox.conf (CheckUpdates: true).', dom.br(), 'Make sure you stay up to date through another mechanism!', dom.br(), 'You have a responsibility to keep the internet-connected software you run up to date and secure!', dom.br(), 'See ', link('https://updates.xmox.nl/changelog'))), dom.p(dom.a('Accounts', attr.href('#accounts')), dom.br(), dom.a('Queue', attr.href('#queue')), ' (' + queueSize + ')', dom.br()), dom.h2('Domains'), (domains || []).length === 0 ? box(red, 'No domains') : dom._kids(page, crumbs('Mox Admin'), checkUpdatesEnabled ? [] : dom.p(box(yellow, 'Warning: Checking for updates has not been enabled in mox.conf (CheckUpdates: true).', dom.br(), 'Make sure you stay up to date through another mechanism!', dom.br(), 'You have a responsibility to keep the internet-connected software you run up to date and secure!', dom.br(), 'See ', link('https://updates.xmox.nl/changelog'))), dom.p(dom.a('Accounts', attr.href('#accounts')), dom.br(), dom.a('Queue', attr.href('#queue')), ' (' + queueSize + ')', dom.br()), dom.h2('Domains'), (domains || []).length === 0 ? box(red, 'No domains') :
dom.ul((domains || []).map(d => dom.li(dom.a(attr.href('#domains/' + domainName(d)), domainString(d))))), dom.br(), dom.h2('Add domain'), dom.form(async function submit(e) { dom.ul((domains || []).map(d => dom.li(dom.a(attr.href('#domains/' + domainName(d)), domainString(d))))), dom.br(), dom.h2('Add domain'), dom.form(async function submit(e) {
e.preventDefault(); e.preventDefault();
@ -1613,7 +1624,23 @@ const index = async () => {
fieldset.disabled = false; fieldset.disabled = false;
} }
window.location.hash = '#domains/' + domain.value; window.location.hash = '#domains/' + domain.value;
}, fieldset = dom.fieldset(dom.label(style({ display: 'inline-block' }), 'Domain', dom.br(), domain = dom.input(attr.required(''))), ' ', dom.label(style({ display: 'inline-block' }), 'Postmaster/reporting account', dom.br(), account = dom.input(attr.required(''))), ' ', dom.label(style({ display: 'inline-block' }), dom.span('Localpart (optional)', attr.title('Must be set if and only if account does not yet exist. The localpart for the user of this domain. E.g. postmaster.')), dom.br(), localpart = dom.input()), ' ', dom.submitbutton('Add domain', attr.title('Domain will be added and the config reloaded. You should add the required DNS records after adding the domain.')))), dom.br(), dom.h2('Reports'), dom.div(dom.a('DMARC', attr.href('#dmarc/reports'))), dom.div(dom.a('TLS', attr.href('#tlsrpt/reports'))), dom.br(), dom.h2('Operations'), dom.div(dom.a('MTA-STS policies', attr.href('#mtasts'))), dom.div(dom.a('DMARC evaluations', attr.href('#dmarc/evaluations'))), dom.div(dom.a('TLS connection results', attr.href('#tlsrpt/results'))), }, fieldset = dom.fieldset(dom.label(style({ display: 'inline-block' }), 'Domain', dom.br(), domain = dom.input(attr.required(''))), ' ', dom.label(style({ display: 'inline-block' }), 'Postmaster/reporting account', dom.br(), account = dom.input(attr.required(''))), ' ', dom.label(style({ display: 'inline-block' }), dom.span('Localpart (optional)', attr.title('Must be set if and only if account does not yet exist. The localpart for the user of this domain. E.g. postmaster.')), dom.br(), localpart = dom.input()), ' ', dom.submitbutton('Add domain', attr.title('Domain will be added and the config reloaded. You should add the required DNS records after adding the domain.')))), dom.br(), dom.h2('Reports'), dom.div(dom.a('DMARC', attr.href('#dmarc/reports'))), dom.div(dom.a('TLS', attr.href('#tlsrpt/reports'))), dom.br(), dom.h2('Operations'), dom.div(dom.a('MTA-STS policies', attr.href('#mtasts'))), dom.div(dom.a('DMARC evaluations', attr.href('#dmarc/evaluations'))), dom.div(dom.a('TLS connection results', attr.href('#tlsrpt/results'))), dom.div(style({ marginTop: '.5ex' }), dom.form(async function submit(e) {
e.preventDefault();
e.stopPropagation();
try {
dom._kids(cidElem);
recvIDFieldset.disabled = true;
const cid = await client.LookupCid(recvID.value);
dom._kids(cidElem, cid);
}
catch (err) {
console.log({ err });
window.alert('Error: ' + errmsg(err));
}
finally {
recvIDFieldset.disabled = false;
}
}, recvIDFieldset = dom.fieldset(dom.label('Received ID', attr.title('The ID in the Received header that was added during incoming delivery.')), ' ', recvID = dom.input(attr.required('')), ' ', dom.submitbutton('Lookup cid', attr.title('Logging about an incoming message includes an attribute "cid", a counter identifying the transaction related to delivery of the message. The ID in the received header is an encrypted cid, which this form decrypts, after which you can look it up in the logging.')), ' ', cidElem = dom.span()))),
// todo: routing, globally, per domain and per account // todo: routing, globally, per domain and per account
dom.br(), dom.h2('DNS blocklist status'), dom.div(dom.a('DNSBL status', attr.href('#dnsbl'))), dom.br(), dom.h2('Configuration'), dom.div(dom.a('Webserver', attr.href('#webserver'))), dom.div(dom.a('Files', attr.href('#config'))), dom.div(dom.a('Log levels', attr.href('#loglevels'))), footer); dom.br(), dom.h2('DNS blocklist status'), dom.div(dom.a('DNSBL status', attr.href('#dnsbl'))), dom.br(), dom.h2('Configuration'), dom.div(dom.a('Webserver', attr.href('#webserver'))), dom.div(dom.a('Files', attr.href('#config'))), dom.div(dom.a('Log levels', attr.href('#loglevels'))), footer);
}; };

View file

@ -265,6 +265,10 @@ const index = async () => {
let account: HTMLInputElement let account: HTMLInputElement
let localpart: HTMLInputElement let localpart: HTMLInputElement
let recvIDFieldset: HTMLFieldSetElement
let recvID: HTMLInputElement
let cidElem: HTMLSpanElement
dom._kids(page, dom._kids(page,
crumbs('Mox Admin'), crumbs('Mox Admin'),
checkUpdatesEnabled ? [] : dom.p(box(yellow, 'Warning: Checking for updates has not been enabled in mox.conf (CheckUpdates: true).', dom.br(), 'Make sure you stay up to date through another mechanism!', dom.br(), 'You have a responsibility to keep the internet-connected software you run up to date and secure!', dom.br(), 'See ', link('https://updates.xmox.nl/changelog'))), checkUpdatesEnabled ? [] : dom.p(box(yellow, 'Warning: Checking for updates has not been enabled in mox.conf (CheckUpdates: true).', dom.br(), 'Make sure you stay up to date through another mechanism!', dom.br(), 'You have a responsibility to keep the internet-connected software you run up to date and secure!', dom.br(), 'See ', link('https://updates.xmox.nl/changelog'))),
@ -329,6 +333,32 @@ const index = async () => {
dom.div(dom.a('MTA-STS policies', attr.href('#mtasts'))), dom.div(dom.a('MTA-STS policies', attr.href('#mtasts'))),
dom.div(dom.a('DMARC evaluations', attr.href('#dmarc/evaluations'))), dom.div(dom.a('DMARC evaluations', attr.href('#dmarc/evaluations'))),
dom.div(dom.a('TLS connection results', attr.href('#tlsrpt/results'))), dom.div(dom.a('TLS connection results', attr.href('#tlsrpt/results'))),
dom.div(
style({marginTop: '.5ex'}),
dom.form(
async function submit(e: SubmitEvent) {
e.preventDefault()
e.stopPropagation()
try {
dom._kids(cidElem)
recvIDFieldset.disabled = true
const cid = await client.LookupCid(recvID.value)
dom._kids(cidElem, cid)
} catch (err) {
console.log({err})
window.alert('Error: ' + errmsg(err))
} finally {
recvIDFieldset.disabled = false
}
},
recvIDFieldset=dom.fieldset(
dom.label('Received ID', attr.title('The ID in the Received header that was added during incoming delivery.')), ' ',
recvID=dom.input(attr.required('')), ' ',
dom.submitbutton('Lookup cid', attr.title('Logging about an incoming message includes an attribute "cid", a counter identifying the transaction related to delivery of the message. The ID in the received header is an encrypted cid, which this form decrypts, after which you can look it up in the logging.')), ' ',
cidElem=dom.span(),
),
),
),
// todo: routing, globally, per domain and per account // todo: routing, globally, per domain and per account
dom.br(), dom.br(),
dom.h2('DNS blocklist status'), dom.h2('DNS blocklist status'),

View file

@ -1125,6 +1125,26 @@
} }
], ],
"Returns": [] "Returns": []
},
{
"Name": "LookupCid",
"Docs": "LookupCid turns an ID from a Received header into a cid as used in logging.",
"Params": [
{
"Name": "recvID",
"Typewords": [
"string"
]
}
],
"Returns": [
{
"Name": "cid",
"Typewords": [
"string"
]
}
]
} }
], ],
"Sections": [], "Sections": [],

View file

@ -1535,6 +1535,15 @@ export class Client {
const params: any[] = [id, until] const params: any[] = [id, until]
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
} }
// LookupCid turns an ID from a Received header into a cid as used in logging.
async LookupCid(recvID: string): Promise<string> {
const fn: string = "LookupCid"
const paramTypes: string[][] = [["string"]]
const returnTypes: string[][] = [["string"]]
const params: any[] = [recvID]
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as string
}
} }
export const defaultBaseURL = (function() { export const defaultBaseURL = (function() {