DKIM rotation broke the domain it was run on. It retired the live key and inserted a placeholder as ACTIVE - private_key_enc was the literal string "dummy-encrypted-key" - so FindActiveKeys then failed for the whole domain and outbound mail stopped being signed, with the real key already gone. Reproduced against a database before changing anything. The root cause runs deeper: the auth service derives its encryption key with a plain SHA-256 of the master key while the protocols service uses HKDF with its own info string, so nothing the auth service seals can ever be opened by the signer. Rotation therefore moves to the protocols service, which owns that vault and the real key generator. It retires the previous key with a seven-day overlap in the same transaction rather than deleting it, because mail already sent under it is still being verified. Domain onboarding had three defects in one function. It built the alias destination by interpolating the domain name into the SQL text, which was injectable; it reused one placeholder for a CITEXT and a VARCHAR column, which made the statement fail and happened to hide the injection; and it ignored its scope argument entirely, so any DOMAIN_ADMIN could create domains. It also provisioned postmaster, abuse and security, missing the dmarc and tlsrpt aliases that the published records point at - PLAN.md section 7.4b is explicit that reports bounce without them. The TLS panel returned fixed values: acme_status "VALID" and 72 days to expiry, whatever the process actually held. It now reads the certificate watcher, and a compile-time assertion keeps the wiring from silently regressing into "disabled". The audit log and the readiness scorecard were fixtures too, and their field names did not match the API they now read. Two tests failed and a third asserted a fabricated constant: one depended on test order through a shared fixture that had a second factor enrolled, one used a fixed domain name and so passed once per database, and one expected "records: 13" from a function that never touches DNS. All three are fixed, and the suite now passes twice in a row against one database. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
148 lines
5.3 KiB
JSON
148 lines
5.3 KiB
JSON
{
|
|
"common": {
|
|
"appName": "LambdaMail",
|
|
"userPortal": "Webmail",
|
|
"adminPortal": "Management Console",
|
|
"loading": "Loading...",
|
|
"save": "Save Changes",
|
|
"cancel": "Cancel",
|
|
"delete": "Delete",
|
|
"confirm": "Confirm",
|
|
"search": "Search",
|
|
"status": "Status",
|
|
"actions": "Actions",
|
|
"refresh": "Refresh",
|
|
"logout": "Log Out"
|
|
},
|
|
"auth": {
|
|
"userLoginTitle": "Webmail Sign In",
|
|
"adminLoginTitle": "Admin Console Sign In",
|
|
"emailLabel": "Email Address",
|
|
"passwordLabel": "Password",
|
|
"signInButton": "Sign In",
|
|
"totpCodeLabel": "6-Digit Authenticator Code",
|
|
"verifyCodeButton": "Verify Code",
|
|
"invalidCredentials": "Invalid email or password",
|
|
"mfaRequired": "Two-factor authentication code required"
|
|
},
|
|
"mail": {
|
|
"inbox": "Inbox",
|
|
"sent": "Sent",
|
|
"drafts": "Drafts",
|
|
"trash": "Trash",
|
|
"junk": "Spam",
|
|
"archive": "Archive",
|
|
"compose": "Compose Email",
|
|
"noMessages": "No messages in this folder",
|
|
"unreadCount": "{count, plural, =0 {No unread messages} one {# unread message} other {# unread messages}}",
|
|
"loadImages": "Load Remote Images",
|
|
"reply": "Reply",
|
|
"forward": "Forward",
|
|
"undoSend": "Undo Send ({seconds}s remaining)"
|
|
},
|
|
"settings": {
|
|
"title": "Account Settings",
|
|
"security": "Security & 2FA",
|
|
"appPasswords": "App Passwords",
|
|
"sessions": "Active Sessions",
|
|
"mfaStatus": "Two-Factor Authentication Status",
|
|
"mfaEnabled": "2FA is Active",
|
|
"mfaDisabled": "2FA is Disabled",
|
|
"enableMfa": "Enable 2FA",
|
|
"generateAppPassword": "Generate App Password",
|
|
"recoveryCodesTitle": "Recovery Codes",
|
|
"saveRecoveryCodes": "Save these recovery codes in a safe place. They will not be shown again.",
|
|
"language": "Language",
|
|
"signOut": "Sign out",
|
|
"langEn": "English",
|
|
"langPtBR": "Portuguese (Brazil)",
|
|
"langEs": "Spanish"
|
|
},
|
|
"admin": {
|
|
"dashboardTitle": "System Dashboard",
|
|
"domainsTitle": "Domains & DNS (13 Records)",
|
|
"mailboxesTitle": "Mailboxes & Accounts",
|
|
"aliasesTitle": "Aliases & Routing",
|
|
"queueTitle": "Outbound Delivery Queue",
|
|
"dmarcTitle": "DMARC Analytics",
|
|
"securityTitle": "Security & Audit Log",
|
|
"preflightTitle": "Preflight Diagnostics",
|
|
"reconcileDns": "Reconcile DNS Records",
|
|
"dnsStatusVerified": "VERIFIED",
|
|
"dnsStatusDrift": "DRIFT DETECTED",
|
|
"dnsStatusPartial": "PARTIAL",
|
|
"retryJob": "Retry Delivery",
|
|
"cancelJob": "Cancel Job",
|
|
"freezeDomain": "Freeze Destination"
|
|
},
|
|
"errors": {
|
|
"unauthorized": "Session expired or unauthorized",
|
|
"forbidden": "Access forbidden for this account surface",
|
|
"serverError": "Internal server error occurred"
|
|
},
|
|
"ui": {
|
|
"accountStatus": "Account Status",
|
|
"actions": "Actions",
|
|
"active": "ACTIVE",
|
|
"activeSessions": "Active Webmail Sessions",
|
|
"actor": "Actor / Account",
|
|
"actualRecord": "Actual DNS Record (Cloudflare)",
|
|
"allChecksPassed": "ALL CHECKS PASSED",
|
|
"appPasswordGenerated": "App Password Generated:",
|
|
"appPasswordsSection": "App Passwords (IMAP / SMTP Clients)",
|
|
"attempts": "Attempts",
|
|
"clientIp": "Client IP",
|
|
"copyPasswordNow": "Copy this password now. It will not be shown again.",
|
|
"coreInfra": "Core Infrastructure Status",
|
|
"currentSession": "Current Webmail Browser Session",
|
|
"daneVerified": "DANE / MTA-STS verified",
|
|
"destination": "Destination",
|
|
"diskUsed": "Disk Capacity Used",
|
|
"dkimResult": "DKIM Result",
|
|
"dkimAlignment": "DKIM Signature Alignment",
|
|
"dmarcEnforcement": "DMARC Policy Enforcement",
|
|
"domainVerification": "Domain Verification Status",
|
|
"emailAddress": "Email Address",
|
|
"eventAction": "Event Action",
|
|
"expectedValue": "Expected Specification Value",
|
|
"healthy": "HEALTHY",
|
|
"imapEngine": "IMAP Protocol Engine (143/993)",
|
|
"inboundVolume": "Inbound Volume (24h)",
|
|
"jobId": "Job ID",
|
|
"lastError": "Last Error",
|
|
"liveMetrics": "Live operational metrics for LambdaMail mail node.",
|
|
"localDisk": "Local disk storage driver",
|
|
"preflightTitle": "Mail Server Preflight Diagnostics",
|
|
"messageBody": "Message Body",
|
|
"messageVolume": "Message Volume",
|
|
"noAppPasswords": "No app passwords generated yet.",
|
|
"online": "ONLINE",
|
|
"outboundDelivered": "Outbound Delivered (24h)",
|
|
"queueDepth": "Outbound Queue Depth",
|
|
"postgresRunner": "Postgres job runner active",
|
|
"provisionMailbox": "Provision New Mailbox Account",
|
|
"recipient": "Recipient",
|
|
"recordName": "Record Name",
|
|
"reportingOrg": "Reporting Organization",
|
|
"scanners": "Rspamd Anti-Spam Scanner & ClamAV",
|
|
"sender": "Sender",
|
|
"smtpListener": "SMTP Protocols Listener (25/587/465)",
|
|
"sourceIp": "Source IP",
|
|
"spfRatio": "SPF Alignment Pass Ratio",
|
|
"spfResult": "SPF Result",
|
|
"storageQuota": "Storage Quota",
|
|
"subject": "Subject",
|
|
"targetObject": "Target Object",
|
|
"timestamp": "Timestamp",
|
|
"toRecipients": "To (Recipients)",
|
|
"totalEvaluated": "Total Evaluated Messages",
|
|
"twoFactorSection": "Two-Factor Authentication (TOTP RFC 6238)",
|
|
"watching": "WATCHING",
|
|
"passwordChanged": "Password changed",
|
|
"signOutOthers": "Sign out other sessions",
|
|
"changePassword": "Change password",
|
|
"currentPassword": "Current password",
|
|
"newPassword": "New password (min. 12 characters)"
|
|
}
|
|
}
|