Files
headplane/app/routes/dns/dns-actions.ts
T
2026-03-07 17:10:34 -05:00

232 lines
6.2 KiB
TypeScript

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);
}
}