diff --git a/http/account.html b/http/account.html
index 0d3aff7..dccd419 100644
--- a/http/account.html
+++ b/http/account.html
@@ -106,16 +106,14 @@ const prop = x => { return {_prop: x} }
return [dom, style, attr, prop]
})()
-const tr = dom.tr
-const td = dom.td
-const th = dom.th
+const link = (href, anchorOpt) => dom.a(attr({href: href, rel: 'noopener noreferrer'}), anchorOpt || href)
const crumblink = (text, link) => dom.a(text, attr({href: link}))
const crumbs = (...l) => [dom.h1(l.map((e, index) => index === 0 ? e : [' / ', e])), dom.br()]
const footer = dom.div(
style({marginTop: '6ex', opacity: 0.75}),
- dom.a(attr({href: 'https://github.com/mjl-/mox'}), 'mox'),
+ link('https://github.com/mjl-/mox', 'mox'),
' ',
api._sherpa.version,
)
diff --git a/http/admin.html b/http/admin.html
index 56055b5..7b05607 100644
--- a/http/admin.html
+++ b/http/admin.html
@@ -107,20 +107,18 @@ const prop = x => { return {_prop: x} }
return [dom, style, attr, prop]
})()
-const tr = dom.tr
-const td = dom.td
-const th = dom.th
-
const green = '#1dea20'
const yellow = '#ffe400'
const red = '#ff7443'
+const link = (href, anchorOpt) => dom.a(attr({href: href, rel: 'noopener noreferrer'}), anchorOpt || href)
+
const crumblink = (text, link) => dom.a(text, attr({href: link}))
const crumbs = (...l) => [dom.h1(l.map((e, index) => index === 0 ? e : [' / ', e])), dom.br()]
const footer = dom.div(
style({marginTop: '6ex', opacity: 0.75}),
- dom.a(attr({href: 'https://github.com/mjl-/mox'}), 'mox'),
+ link('https://github.com/mjl-/mox', 'mox'),
' ',
api._sherpa.version,
)
@@ -533,8 +531,8 @@ const domain = async (d) => {
dom.div('If autoconfig/autodiscover does not work with an email client, use the settings below for this domain. Authenticate with email address and password.'),
dom.table(
dom.thead(
- tr(
- th('Protocol'), th('Host'), th('Port'), th('Listener'), th('Note'),
+ dom.tr(
+ dom.th('Protocol'), dom.th('Host'), dom.th('Port'), dom.th('Listener'), dom.th('Note'),
),
),
dom.tbody(
@@ -631,7 +629,7 @@ const domain = async (d) => {
dom.br(),
dom.h2('External checks'),
dom.ul(
- dom.li(dom.a('Check configuration at internet.nl', attr({href: 'https://internet.nl/mail/'+dnsdomain.ASCII+'/', rel: 'noopener noreferrer'}))),
+ dom.li(link('https://internet.nl/mail/'+dnsdomain.ASCII+'/', 'Check configuration at internet.nl')),
),
dom.br(),
dom.h2('Danger'),
@@ -726,9 +724,9 @@ const domainDNSCheck = async (d) => {
const detailsMX = empty(checks.MX.Records) ? [] : [
dom.table(
- tr(th('Preference'), th('Host'), th('IPs')),
+ dom.tr(dom.th('Preference'), dom.th('Host'), dom.th('IPs')),
checks.MX.Records.map(mx =>
- tr(td(''+mx.Pref), td(mx.Host), td((mx.IPs || []).join(', '))),
+ dom.tr(dom.td(''+mx.Pref), dom.td(mx.Host), dom.td((mx.IPs || []).join(', '))),
)
),
]
@@ -739,9 +737,9 @@ const domainDNSCheck = async (d) => {
]
const detailsDKIM = empty(checks.DKIM.Records) ? [] : [
dom.table(
- tr(th('Selector'), th('TXT record')),
+ dom.tr(dom.th('Selector'), dom.th('TXT record')),
checks.DKIM.Records.map(rec =>
- tr(td(rec.Selector), td(rec.TXT)),
+ dom.tr(dom.td(rec.Selector), dom.td(rec.TXT)),
),
)
]
@@ -759,13 +757,13 @@ const domainDNSCheck = async (d) => {
]
const detailsSRVConf = !Object.entries(checks.SRVConf.SRVs) ? [] : [
dom.table(
- tr(th('Service'), th('Priority'), th('Weight'), th('Port'), th('Host')),
+ dom.tr(dom.th('Service'), dom.th('Priority'), dom.th('Weight'), dom.th('Port'), dom.th('Host')),
Object.entries(checks.SRVConf.SRVs).map(t => {
const l = t[1]
if (!l || !l.length) {
- return tr(td(t[0]), td(attr({attr: '4'}), '(none)'))
+ return dom.tr(dom.td(t[0]), dom.td(attr({attr: '4'}), '(none)'))
}
- return t[1].map(r => tr([t[0], r.Priority, r.Weight, r.Port, r.Target].map(s => td(''+s))))
+ return t[1].map(r => dom.tr([t[0], r.Priority, r.Weight, r.Port, r.Target].map(s => dom.td(''+s))))
}),
),
]
@@ -774,9 +772,9 @@ const domainDNSCheck = async (d) => {
]
const detailsAutodiscover = !checks.Autodiscover.Records ? [] : [
dom.table(
- tr(th('Host'), th('Port'), th('Priority'), th('Weight'), th('IPs')),
+ dom.tr(dom.th('Host'), dom.th('Port'), dom.th('Priority'), dom.th('Weight'), dom.th('IPs')),
checks.Autodiscover.Records.map(r =>
- tr([r.Target, r.Port, r.Priority, r.Weight, (r.IPs || []).join(', ')].map(s => td(''+s)))
+ dom.tr([r.Target, r.Port, r.Priority, r.Weight, (r.IPs || []).join(', ')].map(s => dom.td(''+s)))
),
),
]
@@ -1230,7 +1228,7 @@ const mtasts = async () => {
crumblink('Mox Admin', '#'),
'MTA-STS policies',
),
- dom.p("MTA-STS is a mechanism allowing email domains to publish a policy for using SMTP STARTTLS and TLS verification. See ", dom.a(attr({rel: 'noopener noreferrer', href: 'https://www.rfc-editor.org/rfc/rfc8461.html'}), 'RFC 8461'), '.'),
+ dom.p("MTA-STS is a mechanism allowing email domains to publish a policy for using SMTP STARTTLS and TLS verification. See ", link('https://www.rfc-editor.org/rfc/rfc8461.html', 'RFC 8461'), '.'),
dom.p("The SMTP protocol is unencrypted by default, though the SMTP STARTTLS command is typically used to enable TLS on a connection. However, MTA's using STARTTLS typically do not validate the TLS certificate. An MTA-STS policy can specify that validation of host name, non-expiration and webpki trust is required."),
makeMTASTSTable(policies),
)
@@ -1313,7 +1311,7 @@ const dnsbl = async () => {
Object.entries(ipZoneResults).sort().map(ipZones => {
const [ip, zoneResults] = ipZones
return dom.li(
- dom.a(ip, attr({href: url(ip), target: '_blank', rel: 'noopener noreferrer'})),
+ link(url(ip), ip),
!ipZones.length ? [] : dom.ul(
Object.entries(zoneResults).sort().map(zoneResult =>
dom.li(