47eb9502f8
Wire the mail/identity stack to real Stalwart/Authentik/OCIS provisioning, replacing the mocked Domains and Users pages. Domains (customer-admin): - StalwartClient: real JMAP management (v0.16 dropped REST) — create/list/delete email domains via x:Domain at the internal http://stalwart:8080 listener; DKIM auto-generated; the records to publish are read from the domain's dnsZoneFile. Gated by STALWART_PROVISIONING_ENABLED. - New Domain collection + DomainsModule: add/list/recheck/set-DMARC/remove, tenant-membership-gated and audited. - DnsVerifierService: verifies MX/SPF/DKIM/DMARC/ownership against a public resolver (1.1.1.1/8.8.8.8) and diffs them against the expected records. - Remove is guarded: refuses while accounts/aliases/mailing lists still use the domain (via Stalwart referential integrity). - Domains page + add wizard on real data; sidebar badge counts domains needing attention. Users & groups (customer-admin): - Create a member provisioned across Authentik SSO, a Stalwart mailbox on the tenant's primary domain, and OCIS — returning a one-time password. - Lifecycle: suspend/resume (Authentik is_active + freeze the mailbox via account permissions, original password preserved), force-logout (terminate sessions, filtered client-side so it can never end other users' sessions), reset password (new one-time password on SSO + mailbox), and remove (tear down mailbox + SSO identity + OCIS + doc; mailbox-in-use aware for multi-tenant users). Self-suspend / self-force-logout are blocked. Infra: point platform-api at the internal Stalwart listener; document the new STALWART_/provisioning vars in .env.example.
69 lines
2.2 KiB
TypeScript
69 lines
2.2 KiB
TypeScript
// Customer-admin email-domain data + mutations, backed by platform-api's
|
|
// /api/tenants/:slug/domains endpoints. Reads use useFetch (SSR-friendly list);
|
|
// writes go through useApiFetch so a lapsed session refreshes silently instead
|
|
// of redirecting away mid-action. Mirrors the read/write split in
|
|
// pages/admin/security.vue.
|
|
|
|
export type RecordStatus = 'ok' | 'warn' | 'bad' | 'pending'
|
|
export type DomainStatus = 'pending' | 'verifying' | 'active' | 'error'
|
|
export type RecordKind = 'ownership' | 'mx' | 'spf' | 'dkim' | 'dmarc'
|
|
export type DmarcPolicy = 'none' | 'quarantine' | 'reject'
|
|
|
|
export interface DomainRecordView {
|
|
kind: RecordKind
|
|
type: string
|
|
host: string
|
|
fqdn: string
|
|
expected: string
|
|
priority?: number
|
|
observed?: string
|
|
status: RecordStatus
|
|
}
|
|
|
|
export interface DomainView {
|
|
id: string
|
|
domain: string
|
|
isPrimary: boolean
|
|
status: DomainStatus
|
|
ownershipVerified: boolean
|
|
verificationToken: string
|
|
dmarcPolicy: DmarcPolicy
|
|
stalwartProvisioned: boolean
|
|
stalwartError?: string
|
|
mailboxes: number
|
|
checks: Record<'ownership' | 'mx' | 'spf' | 'dkim' | 'dmarc', RecordStatus>
|
|
records: DomainRecordView[]
|
|
lastCheckedAt?: string
|
|
}
|
|
|
|
export function useDomains() {
|
|
const { tenant } = useTenant()
|
|
const slug = computed(() => tenant.value?.slug ?? '')
|
|
const { request } = useApiFetch()
|
|
|
|
const base = () => `/api/tenants/${slug.value}/domains`
|
|
const one = (domain: string) => `${base()}/${encodeURIComponent(domain)}`
|
|
|
|
const { data: domains, refresh, pending } = useFetch<DomainView[]>(base, {
|
|
key: 'admin-domains',
|
|
default: () => [],
|
|
immediate: !!slug.value,
|
|
watch: [slug],
|
|
})
|
|
|
|
const add = (domain: string) =>
|
|
request<DomainView>(base(), { method: 'POST', body: { domain } })
|
|
|
|
const getOne = (domain: string) => request<DomainView>(one(domain))
|
|
|
|
const recheck = (domain: string) =>
|
|
request<DomainView>(`${one(domain)}/recheck`, { method: 'POST' })
|
|
|
|
const setDmarcPolicy = (domain: string, dmarcPolicy: DmarcPolicy) =>
|
|
request<DomainView>(`${one(domain)}/dmarc`, { method: 'PATCH', body: { dmarcPolicy } })
|
|
|
|
const remove = (domain: string) => request(one(domain), { method: 'DELETE' })
|
|
|
|
return { domains, pending, refresh, slug, add, getOne, recheck, setDmarcPolicy, remove }
|
|
}
|