- backend/api/magic/register: explicit import of MAGIC_DEVICE_LIMIT and createAdGuardClient (Nitro auto-import was missing them → ReferenceError → HTTP 500 on /api/magic/register) - mac-app: default backendBaseUrl falls back to staging.rebreak.org (app.rebreak.org serves wrong TLS cert) - native MagicSheet: fallback download/dmg URLs point to staging - native settings: Magic sheet capped at detents=[0.85] so AppHeader stays visible - bundles all in-flight Magic feature work (pair create/redeem, device endpoints, schema, adguard utils, mac-app, locales)
88 lines
2.7 KiB
TypeScript
88 lines
2.7 KiB
TypeScript
import { randomUUID } from "crypto";
|
||
import { readFile } from "fs/promises";
|
||
import { resolve } from "path";
|
||
import { findMagicDeviceByToken } from "../../db/devices";
|
||
|
||
/**
|
||
* GET /api/magic/profile.mobileconfig?token=<dnsToken>
|
||
*
|
||
* Generiert personalisiertes DNS-Configuration-Profile für macOS.
|
||
* Template: ops/mdm/rebreak-mac-dns-filter.mobileconfig
|
||
*
|
||
* 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 lesen
|
||
const templatePath = resolve(
|
||
process.cwd(),
|
||
"ops/mdm/rebreak-mac-dns-filter.mobileconfig",
|
||
);
|
||
let template: string;
|
||
try {
|
||
template = await readFile(templatePath, "utf-8");
|
||
} catch (err: any) {
|
||
console.error("[Magic] Failed to read profile template:", err);
|
||
throw createError({
|
||
statusCode: 500,
|
||
message: "Profile template not found",
|
||
});
|
||
}
|
||
|
||
// 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;
|
||
});
|