Add DKIM selector fields for value-only Email DNS pastes
Let operators paste bare v=DKIM1 TXT values and enter selectors separately; keep full Stalwart zone-line paste working.
This commit is contained in:
@@ -12,6 +12,30 @@
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.selectorInput {
|
||||
width: 100%;
|
||||
min-height: var(--field-height);
|
||||
padding: var(--field-padding-y) var(--field-padding-x);
|
||||
font-size: var(--field-font-size);
|
||||
font-family: var(--font-ui);
|
||||
line-height: 1.4;
|
||||
color: var(--text-primary);
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
border: 1px solid rgba(148, 163, 184, 0.35);
|
||||
border-radius: var(--radius-sm);
|
||||
outline: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.selectorInput:focus {
|
||||
border-color: var(--primary);
|
||||
box-shadow: 0 0 0 3px rgba(var(--primary-rgb) / 0.12);
|
||||
}
|
||||
|
||||
.selectorInput:disabled {
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.textarea {
|
||||
width: 100%;
|
||||
min-height: 110px;
|
||||
|
||||
@@ -14,10 +14,22 @@ interface EmailDnsModalProps {
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
function pasteIncludesDomainkey(paste: string) {
|
||||
return /[a-z0-9][a-z0-9-]*\._domainkey/i.test(paste)
|
||||
}
|
||||
|
||||
function keyReady(paste: string, selector: string) {
|
||||
const trimmed = paste.trim()
|
||||
if (!trimmed) return false
|
||||
return pasteIncludesDomainkey(trimmed) || Boolean(selector.trim())
|
||||
}
|
||||
|
||||
export function EmailDnsModal({ domain, onClose }: EmailDnsModalProps) {
|
||||
const { showToast } = useToast()
|
||||
const [dnsProvider, setDnsProvider] = useState<ParkedDnsProvider>('arvan')
|
||||
const [ed25519Selector, setEd25519Selector] = useState('')
|
||||
const [ed25519Key, setEd25519Key] = useState('')
|
||||
const [rsaSelector, setRsaSelector] = useState('')
|
||||
const [rsaKey, setRsaKey] = useState('')
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
const [error, setError] = useState('')
|
||||
@@ -25,7 +37,9 @@ export function EmailDnsModal({ domain, onClose }: EmailDnsModalProps) {
|
||||
useEffect(() => {
|
||||
if (!domain) return
|
||||
setDnsProvider('arvan')
|
||||
setEd25519Selector('')
|
||||
setEd25519Key('')
|
||||
setRsaSelector('')
|
||||
setRsaKey('')
|
||||
setError('')
|
||||
setSubmitting(false)
|
||||
@@ -33,6 +47,8 @@ export function EmailDnsModal({ domain, onClose }: EmailDnsModalProps) {
|
||||
|
||||
if (!domain) return null
|
||||
const target = domain
|
||||
const canSubmit =
|
||||
keyReady(ed25519Key, ed25519Selector) && keyReady(rsaKey, rsaSelector)
|
||||
|
||||
async function submit() {
|
||||
setSubmitting(true)
|
||||
@@ -42,6 +58,10 @@ export function EmailDnsModal({ domain, onClose }: EmailDnsModalProps) {
|
||||
dnsProvider,
|
||||
ed25519Key,
|
||||
rsaKey,
|
||||
...(ed25519Selector.trim()
|
||||
? { ed25519Selector: ed25519Selector.trim() }
|
||||
: {}),
|
||||
...(rsaSelector.trim() ? { rsaSelector: rsaSelector.trim() } : {}),
|
||||
})
|
||||
showToast(result.message, 'success')
|
||||
onClose()
|
||||
@@ -65,8 +85,9 @@ export function EmailDnsModal({ domain, onClose }: EmailDnsModalProps) {
|
||||
}}
|
||||
>
|
||||
<p className={parkedStyles.hint}>
|
||||
Paste the two DKIM lines from Stalwart (Directory → Domains → ⋮ → View DNS
|
||||
zone file). We upsert mail records on{' '}
|
||||
Paste each DKIM <strong>TXT value</strong> (<code>v=DKIM1; …</code>) from
|
||||
Stalwart, or the full zone line. For value-only pastes, fill the selector
|
||||
(for example <code>v1-ed25519-20260901</code>). We upsert mail records on{' '}
|
||||
{dnsProvider === 'cloudflare' ? 'Cloudflare' : 'Arvan'} (DNS-only / not
|
||||
proxied): <strong>mail</strong> A → 185.214.101.41, MX → mail.meshkee.com,
|
||||
SPF, both DKIM keys, autoconfig / autodiscover. Extra MX,{' '}
|
||||
@@ -92,6 +113,25 @@ export function EmailDnsModal({ domain, onClose }: EmailDnsModalProps) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={tableStyles.field}>
|
||||
<label htmlFor="mail-dkim-ed25519-selector">Ed25519 selector</label>
|
||||
<input
|
||||
id="mail-dkim-ed25519-selector"
|
||||
className={styles.selectorInput}
|
||||
type="text"
|
||||
value={ed25519Selector}
|
||||
onChange={(e) => setEd25519Selector(e.target.value)}
|
||||
placeholder="v1-ed25519-20260901"
|
||||
disabled={submitting}
|
||||
spellCheck={false}
|
||||
dir="ltr"
|
||||
autoComplete="off"
|
||||
/>
|
||||
<p className={tableStyles.helperText}>
|
||||
Needed when pasting only the TXT value. Optional if the paste includes{' '}
|
||||
<code>…._domainkey</code>.
|
||||
</p>
|
||||
</div>
|
||||
<div className={tableStyles.field}>
|
||||
<label htmlFor="mail-dkim-ed25519">Ed25519 domain key</label>
|
||||
<textarea
|
||||
@@ -99,14 +139,33 @@ export function EmailDnsModal({ domain, onClose }: EmailDnsModalProps) {
|
||||
className={styles.textarea}
|
||||
value={ed25519Key}
|
||||
onChange={(e) => setEd25519Key(e.target.value)}
|
||||
placeholder="v1-ed25519-…. _domainkey IN TXT "v=DKIM1; k=ed25519; …""
|
||||
placeholder='v=DKIM1; k=ed25519; h=sha256; p=…'
|
||||
disabled={submitting}
|
||||
spellCheck={false}
|
||||
dir="ltr"
|
||||
rows={5}
|
||||
rows={4}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ height: 12 }} />
|
||||
<div className={tableStyles.field}>
|
||||
<label htmlFor="mail-dkim-rsa-selector">RSA selector</label>
|
||||
<input
|
||||
id="mail-dkim-rsa-selector"
|
||||
className={styles.selectorInput}
|
||||
type="text"
|
||||
value={rsaSelector}
|
||||
onChange={(e) => setRsaSelector(e.target.value)}
|
||||
placeholder="v1-rsa-20260901"
|
||||
disabled={submitting}
|
||||
spellCheck={false}
|
||||
dir="ltr"
|
||||
autoComplete="off"
|
||||
/>
|
||||
<p className={tableStyles.helperText}>
|
||||
Needed when pasting only the TXT value. Optional if the paste includes{' '}
|
||||
<code>…._domainkey</code>.
|
||||
</p>
|
||||
</div>
|
||||
<div className={tableStyles.field}>
|
||||
<label htmlFor="mail-dkim-rsa">RSA domain key</label>
|
||||
<textarea
|
||||
@@ -114,11 +173,11 @@ export function EmailDnsModal({ domain, onClose }: EmailDnsModalProps) {
|
||||
className={styles.textarea}
|
||||
value={rsaKey}
|
||||
onChange={(e) => setRsaKey(e.target.value)}
|
||||
placeholder="v1-rsa-…. _domainkey IN TXT "v=DKIM1; k=rsa; …""
|
||||
placeholder='v=DKIM1; k=rsa; h=sha256; p=…'
|
||||
disabled={submitting}
|
||||
spellCheck={false}
|
||||
dir="ltr"
|
||||
rows={7}
|
||||
rows={6}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -136,7 +195,7 @@ export function EmailDnsModal({ domain, onClose }: EmailDnsModalProps) {
|
||||
type="button"
|
||||
className={`${tableStyles.btn} ${tableStyles.btnPrimary}`}
|
||||
onClick={() => void submit()}
|
||||
disabled={submitting || !ed25519Key.trim() || !rsaKey.trim()}
|
||||
disabled={submitting || !canSubmit}
|
||||
>
|
||||
Update DNS
|
||||
</button>
|
||||
|
||||
@@ -114,6 +114,8 @@ export async function applyMailDns(
|
||||
dnsProvider: 'arvan' | 'cloudflare'
|
||||
ed25519Key: string
|
||||
rsaKey: string
|
||||
ed25519Selector?: string
|
||||
rsaSelector?: string
|
||||
},
|
||||
) {
|
||||
return apiRequest<ApplyMailDnsResponse>(`/domains/${domainId}/mail-dns`, {
|
||||
|
||||
Reference in New Issue
Block a user