import { data } from "react-router"; import { Capabilities } from "~/server/web/roles"; import type { Route } from "./+types/overview"; export async function dnsAction({ request, context }: Route.ActionArgs) { const principal = await context.auth.require(request); const check = context.auth.can(principal, Capabilities.write_network); if (!check) { return data({ success: false }, 403); } if (!context.hs.writable()) { return data({ success: false }, 403); } // We only need it for health checks which don't require auth const api = context.hsApi.getRuntimeClient("fake-api-key"); const formData = await request.formData(); const action = formData.get("action_id")?.toString(); if (!action) { return data({ success: false }, 400); } switch (action) { case "rename_tailnet": { const newName = formData.get("new_name")?.toString(); if (!newName) { return data({ success: false }, 400); } await context.hs.patch([ { path: "dns.base_domain", value: newName, }, ]); await context.integration?.onConfigChange(api); return { message: "Tailnet renamed successfully" }; } case "toggle_magic": { const newState = formData.get("new_state")?.toString(); if (!newState) { return data({ success: false }, 400); } await context.hs.patch([ { path: "dns.magic_dns", value: newState === "enabled", }, ]); await context.integration?.onConfigChange(api); return { message: "Magic DNS state updated successfully" }; } case "remove_ns": { const config = context.hs.c!; const ns = formData.get("ns")?.toString(); const splitName = formData.get("split_name")?.toString(); if (!ns || !splitName) { return data({ success: false }, 400); } if (splitName === "global") { const servers = config.dns.nameservers.global.filter((i) => i !== ns); await context.hs.patch([ { path: "dns.nameservers.global", value: servers, }, ]); } else { const splits = config.dns.nameservers.split; const servers = splits[splitName].filter((i) => i !== ns); await context.hs.patch([ { path: `dns.nameservers.split."${splitName}"`, value: servers.length > 0 ? servers : null, }, ]); } await context.integration?.onConfigChange(api); return { message: "Nameserver removed successfully" }; } case "add_ns": { const config = context.hs.c!; const ns = formData.get("ns")?.toString(); const splitName = formData.get("split_name")?.toString(); if (!ns || !splitName) { return data({ success: false }, 400); } if (splitName === "global") { const servers = config.dns.nameservers.global; servers.push(ns); await context.hs.patch([ { path: "dns.nameservers.global", value: servers, }, ]); } else { const splits = config.dns.nameservers.split; const servers = splits[splitName] ?? []; servers.push(ns); await context.hs.patch([ { path: `dns.nameservers.split."${splitName}"`, value: servers, }, ]); } await context.integration?.onConfigChange(api); return { message: "Nameserver added successfully" }; } case "remove_domain": { const config = context.hs.c!; const domain = formData.get("domain")?.toString(); if (!domain) { return data({ success: false }, 400); } const domains = config.dns.search_domains.filter((i) => i !== domain); await context.hs.patch([ { path: "dns.search_domains", value: domains, }, ]); await context.integration?.onConfigChange(api); return { message: "Domain removed successfully" }; } case "add_domain": { const config = context.hs.c!; const domain = formData.get("domain")?.toString(); if (!domain) { return data({ success: false }, 400); } const domains = config.dns.search_domains; domains.push(domain); await context.hs.patch([ { path: "dns.search_domains", value: domains, }, ]); await context.integration?.onConfigChange(api); return { message: "Domain added successfully" }; } case "remove_record": { const recordName = formData.get("record_name")?.toString(); const recordType = formData.get("record_type")?.toString(); if (!recordName || !recordType) { return data({ success: false }, 400); } // Value is not needed for removal const restart = await context.hs.removeDNS({ name: recordName, type: recordType, value: "", }); if (!restart) { return; } await context.integration?.onConfigChange(api); return { message: "DNS record removed successfully" }; } case "add_record": { const recordName = formData.get("record_name")?.toString(); const recordType = formData.get("record_type")?.toString(); const recordValue = formData.get("record_value")?.toString(); if (!recordName || !recordType || !recordValue) { return data({ success: false }, 400); } const restart = await context.hs.addDNS({ name: recordName, type: recordType, value: recordValue, }); if (!restart) { return; } await context.integration?.onConfigChange(api); return { message: "DNS record added successfully" }; } case "override_dns": { const override = formData.get("override_dns")?.toString(); if (!override) { return data({ success: false }, 400); } const overrideValue = override === "true"; await context.hs.patch([ { path: "dns.override_local_dns", value: overrideValue, }, ]); await context.integration?.onConfigChange(api); return { message: "DNS override updated successfully" }; } default: return data({ success: false }, 400); } }