- backend: /api/magic/{register,devices,profile,release} + AdGuard provisioning + 24h cooldown
- prisma: magic_binding_fields migration (additive on UserDevice)
- mac-app: Phase 2 - Login + MacRegistration + Profile install
- marketing: landing section + /download/rebreakmagic + DMG
- lyra: forbidden phrases + RebreakMagic coach guidance
94 lines
2.7 KiB
TypeScript
94 lines
2.7 KiB
TypeScript
|
||
import { randomUUID } from 'crypto';
|
||
import { readFile } from 'fs/promises';
|
||
import { resolve } from 'path';
|
||
|
||
/**
|
||
* 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;
|
||
});
|