chahinebrini c1edef8abd feat(magic): RebreakMagic device-binding + DNS profile
- 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
2026-06-02 09:15:19 +02:00

73 lines
1.8 KiB
TypeScript

/**
* POST /api/magic/devices/[deviceId]/request-release
*
* Startet 24h Cooldown für Magic-Device-Binding.
* Nach 24h wird Token automatisch via Cron invalidiert.
*
* Idempotent: wenn bereits gesetzt → return existing.
*/
export default defineEventHandler(async (event) => {
const user = await requireUser(event);
const deviceId = getRouterParam(event, 'deviceId');
if (!deviceId) {
throw createError({
statusCode: 400,
message: 'deviceId required',
});
}
const db = usePrisma();
// Ownership-Check + Magic-Binding-Check
const device = await db.userDevice.findUnique({
where: { userId_deviceId: { userId: user.id, deviceId } },
select: {
id: true,
magicEnrolledAt: true,
magicRevokedAt: true,
releaseRequestedAt: true,
},
});
if (!device || !device.magicEnrolledAt || device.magicRevokedAt) {
throw createError({
statusCode: 404,
message: 'Magic-Binding nicht gefunden oder bereits revoked',
});
}
// Idempotent: wenn bereits gesetzt → return existing
if (device.releaseRequestedAt) {
const releaseAvailableAt = new Date(
device.releaseRequestedAt.getTime() + 24 * 60 * 60 * 1000,
);
return {
success: true,
data: {
releaseRequestedAt: device.releaseRequestedAt.toISOString(),
releaseAvailableAt: releaseAvailableAt.toISOString(),
},
};
}
// Setze releaseRequestedAt
const now = new Date();
await db.userDevice.update({
where: { id: device.id },
data: { releaseRequestedAt: now },
});
const releaseAvailableAt = new Date(now.getTime() + 24 * 60 * 60 * 1000);
return {
success: true,
data: {
releaseRequestedAt: now.toISOString(),
releaseAvailableAt: releaseAvailableAt.toISOString(),
},
};
});