- Add server/utils/regfile.ts: generateWindowsDohRegFile() producing
UTF-16 LE + BOM .reg content for DohWellKnownServers registry path.
label and dohTemplate values are properly escape'd (\, ", \n, \r, \t).
- Add GET /api/devices/:id/profile.reg — public, windows-platform-gated,
returns octet-stream with Content-Disposition attachment.
- Update enroll.post.ts: downloadUrl is now platform-aware
(windows → .reg, all others → .mobileconfig).
- Add tests/devices/regfile.test.ts: 13 tests covering BOM, CRLF,
token embed, subkey naming, AutoUpgradeFlag, label escaping (", \, \n),
and labelToSlug edge cases. All 111 tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
49 lines
1.6 KiB
TypeScript
49 lines
1.6 KiB
TypeScript
import { getProtectedDevice } from "../../../db/protectedDevices";
|
|
import { labelToSlug } from "../../../utils/mobileconfig";
|
|
import { generateWindowsDohRegFile } from "../../../utils/regfile";
|
|
|
|
/**
|
|
* GET /api/devices/:id/profile.reg
|
|
*
|
|
* PUBLIC — Windows muss ohne Auth-Header zugreifen können.
|
|
* Der dnsToken im Profil IST die Device-Authentifizierung beim DoH-Server.
|
|
*
|
|
* Liefert ein Windows-Registry-File (.reg) das DoH für den ReBreak-DNS-Server
|
|
* in Windows 11 einrichtet.
|
|
*
|
|
* Content-Type: application/octet-stream
|
|
* Encoding: UTF-16 LE mit BOM (required by regedit.exe)
|
|
*/
|
|
export default defineEventHandler(async (event) => {
|
|
const id = getRouterParam(event, "id");
|
|
if (!id) throw createError({ statusCode: 400, data: { error: "ID_REQUIRED" } });
|
|
|
|
const device = await getProtectedDevice(id);
|
|
|
|
if (!device || device.status === "revoked") {
|
|
throw createError({ statusCode: 404, data: { error: "DEVICE_NOT_FOUND" } });
|
|
}
|
|
|
|
if (device.platform !== "windows") {
|
|
throw createError({
|
|
statusCode: 400,
|
|
data: { error: "WRONG_PLATFORM", expected: "windows", actual: device.platform },
|
|
});
|
|
}
|
|
|
|
const regBuffer = generateWindowsDohRegFile({
|
|
deviceId: device.id,
|
|
dnsToken: device.dnsToken,
|
|
label: device.label,
|
|
});
|
|
|
|
const slug = labelToSlug(device.label);
|
|
const filename = `rebreak-${slug || "schutz"}.reg`;
|
|
|
|
setHeader(event, "Content-Type", "application/octet-stream");
|
|
setHeader(event, "Content-Disposition", `attachment; filename="${filename}"`);
|
|
setHeader(event, "Cache-Control", "no-store");
|
|
|
|
return regBuffer;
|
|
});
|