- 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
119 lines
3.3 KiB
TypeScript
119 lines
3.3 KiB
TypeScript
/**
|
|
* AdGuard Home API Client für RebreakMagic DNS-over-HTTPS Client-Provisioning.
|
|
* Docs: https://github.com/AdguardTeam/AdGuardHome/tree/master/openapi
|
|
*/
|
|
|
|
export interface AdGuardClientOptions {
|
|
use_global_settings?: boolean;
|
|
filtering_enabled?: boolean;
|
|
parental_enabled?: boolean;
|
|
safebrowsing_enabled?: boolean;
|
|
safesearch_enabled?: boolean;
|
|
blocked_services?: string[];
|
|
upstreams?: string[];
|
|
tags?: string[];
|
|
}
|
|
|
|
interface AdGuardClientPayload {
|
|
name: string;
|
|
ids: string[];
|
|
use_global_settings?: boolean;
|
|
filtering_enabled?: boolean;
|
|
parental_enabled?: boolean;
|
|
safebrowsing_enabled?: boolean;
|
|
safesearch_enabled?: boolean;
|
|
blocked_services?: string[];
|
|
upstreams?: string[];
|
|
tags?: string[];
|
|
}
|
|
|
|
/**
|
|
* Erstellt einen AdGuard Persistent Client mit gegebener Client-ID (DNS-Token).
|
|
* AdGuard nutzt die Client-ID im DoH-URL-Path: /dns-query/{clientId}
|
|
*
|
|
* @param name - Interner Client-Name (z.B. "magic_<deviceId>")
|
|
* @param clientId - DNS-Token (wird in DoH URL embedded)
|
|
* @param options - Filtering/Blocking-Optionen
|
|
*/
|
|
export async function createAdGuardClient(
|
|
name: string,
|
|
clientId: string,
|
|
options: AdGuardClientOptions = {},
|
|
): Promise<void> {
|
|
const config = useRuntimeConfig();
|
|
const baseUrl = config.adguardBaseUrl || 'https://dns.rebreak.org';
|
|
const user = config.adguardUser;
|
|
const password = config.adguardPassword;
|
|
|
|
if (!user || !password) {
|
|
throw createError({
|
|
statusCode: 500,
|
|
message: 'ADGUARD_USER and ADGUARD_PASSWORD required for Magic features',
|
|
});
|
|
}
|
|
|
|
const payload: AdGuardClientPayload = {
|
|
name,
|
|
ids: [clientId],
|
|
...options,
|
|
};
|
|
|
|
const authHeader = `Basic ${Buffer.from(`${user}:${password}`).toString('base64')}`;
|
|
|
|
try {
|
|
const response = await $fetch(`${baseUrl}/control/clients/add`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': authHeader,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: payload,
|
|
});
|
|
return response as void;
|
|
} catch (err: any) {
|
|
console.error('[AdGuard] Client creation failed:', err);
|
|
throw createError({
|
|
statusCode: 502,
|
|
message: `AdGuard API error: ${err.message || 'unknown'}`,
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Löscht einen AdGuard Persistent Client.
|
|
* @param name - Interner Client-Name (z.B. "magic_<deviceId>")
|
|
*/
|
|
export async function deleteAdGuardClient(name: string): Promise<void> {
|
|
const config = useRuntimeConfig();
|
|
const baseUrl = config.adguardBaseUrl || 'https://dns.rebreak.org';
|
|
const user = config.adguardUser;
|
|
const password = config.adguardPassword;
|
|
|
|
if (!user || !password) {
|
|
throw createError({
|
|
statusCode: 500,
|
|
message: 'ADGUARD_USER and ADGUARD_PASSWORD required for Magic features',
|
|
});
|
|
}
|
|
|
|
const authHeader = `Basic ${Buffer.from(`${user}:${password}`).toString('base64')}`;
|
|
|
|
try {
|
|
const response = await $fetch(`${baseUrl}/control/clients/delete`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Authorization': authHeader,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: { name },
|
|
});
|
|
return response as void;
|
|
} catch (err: any) {
|
|
console.error('[AdGuard] Client deletion failed:', err);
|
|
throw createError({
|
|
statusCode: 502,
|
|
message: `AdGuard API error: ${err.message || 'unknown'}`,
|
|
});
|
|
}
|
|
}
|