serverAssets approach didn't bundle the template into the Nitro output (no .output-staging/server/chunks/raw/ dir, no asset-storage mount in nitro.mjs). Logs confirm: '[Magic] Profile template missing in serverAssets'. Drop serverAssets entirely. Inline the template (~2KB) as a TS constant in backend/server/utils/magic-profile-template.ts. Build- robust, no FS/storage dependency at runtime. Canonical source of truth remains ops/mdm/rebreak-mac-dns-filter.mobileconfig — keep in sync manually until/unless we add a codegen step.
76 lines
2.6 KiB
TypeScript
76 lines
2.6 KiB
TypeScript
import { randomUUID } from "crypto";
|
||
import { findMagicDeviceByToken } from "../../db/devices";
|
||
import { MAGIC_PROFILE_TEMPLATE } from "../../utils/magic-profile-template";
|
||
|
||
/**
|
||
* GET /api/magic/profile.mobileconfig?token=<dnsToken>
|
||
*
|
||
* Generiert personalisiertes DNS-Configuration-Profile für macOS.
|
||
* Template: ops/mdm/rebreak-mac-dns-filter.mobileconfig (inlined als TS
|
||
* constant via backend/server/utils/magic-profile-template.ts — überlebt
|
||
* jeden Build/Deploy ohne FS- oder serverAssets-Magic).
|
||
*
|
||
* Ersetzt:
|
||
* - ServerURL: /dns-query → /dns-query/{token}
|
||
* - PayloadUUID: 2× neu generieren (DNSSettings + Profile root)
|
||
* - PayloadIdentifier: unique pro Device
|
||
*
|
||
* TODO: Profile-Signierung via Apple Developer Certificate (Phase 2)
|
||
*/
|
||
export default defineEventHandler(async (event) => {
|
||
const query = getQuery(event);
|
||
const token = query.token as string | undefined;
|
||
|
||
if (!token) {
|
||
throw createError({
|
||
statusCode: 400,
|
||
message: "token query parameter required",
|
||
});
|
||
}
|
||
|
||
// Token in DB suchen (nur aktive, nicht revoked)
|
||
const device = await findMagicDeviceByToken(token);
|
||
if (!device) {
|
||
throw createError({
|
||
statusCode: 404,
|
||
message: "Invalid or revoked DNS token",
|
||
});
|
||
}
|
||
|
||
// Template via Nitro serverAssets lesen (build-time eingebundelt → cwd-unabhängig).
|
||
const template = MAGIC_PROFILE_TEMPLATE;
|
||
|
||
// ServerURL ersetzen: /dns-query → /dns-query/{token}
|
||
const personalizedProfile = template
|
||
.replace(
|
||
"https://dns.rebreak.org/dns-query",
|
||
`https://dns.rebreak.org/dns-query/${token}`,
|
||
)
|
||
// PayloadUUID neu generieren (2 Stellen im Template)
|
||
.replace("7D2E8B1A-C3D4-4E76-8B23-A4B5C6D7E8F0", randomUUID().toUpperCase())
|
||
.replace("8C3F9A2B-D4E5-4F87-9A12-B5C6D7E8F901", randomUUID().toUpperCase())
|
||
// PayloadIdentifier unique machen (optional, verhindert Konflikt bei Multi-Device)
|
||
.replace(
|
||
"org.rebreak.protection.dns.filter",
|
||
`org.rebreak.protection.dns.filter.${device.deviceId.slice(0, 8)}`,
|
||
)
|
||
.replace(
|
||
"org.rebreak.protection.profile",
|
||
`org.rebreak.protection.profile.${device.deviceId.slice(0, 8)}`,
|
||
);
|
||
|
||
// Response-Headers
|
||
setHeader(event, "Content-Type", "application/x-apple-aspen-config");
|
||
setHeader(
|
||
event,
|
||
"Content-Disposition",
|
||
`attachment; filename="RebreakMagic-${device.deviceId.slice(0, 8)}.mobileconfig"`,
|
||
);
|
||
|
||
// TODO: Profile-Signierung via /usr/bin/security cms -S
|
||
// Requires: Apple Developer Certificate + Private Key in Keychain
|
||
// Siehe: https://developer.apple.com/documentation/devicemanagement/profile-specific_payload_keys
|
||
|
||
return personalizedProfile;
|
||
});
|