chore(debug): Redirect-Test-Karte — Layer-1-Bypass reproduzieren
Neue RedirectTestCard im Debug-Screen mit zwei Buttons: - Kontrolle: tipico.de direkt öffnen - Test: httpbin-302-Redirect → tipico.de Spielt den Casino-Mail-Fall nach (erlaubter Zwischen-Host → 302 → blockierte Domain), um zu prüfen ob der DNS-Filter die Zieldomain auch nach einem Redirect noch sinkholet. Frontend-only. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
23b91a1a3e
commit
bf28d81d13
@ -7,6 +7,7 @@ import {
|
|||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
Alert,
|
Alert,
|
||||||
Clipboard,
|
Clipboard,
|
||||||
|
Linking,
|
||||||
Platform,
|
Platform,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||||
@ -129,6 +130,8 @@ export default function DebugScreen() {
|
|||||||
<RealtimeLogCard />
|
<RealtimeLogCard />
|
||||||
{Platform.OS === 'ios' ? <ProtectionLogCard /> : null}
|
{Platform.OS === 'ios' ? <ProtectionLogCard /> : null}
|
||||||
|
|
||||||
|
<RedirectTestCard />
|
||||||
|
|
||||||
<DebugStub
|
<DebugStub
|
||||||
title="LLM-Provider Toggle"
|
title="LLM-Provider Toggle"
|
||||||
subtitle="Phase C: aus app/urge.tsx hierher migrieren"
|
subtitle="Phase C: aus app/urge.tsx hierher migrieren"
|
||||||
@ -149,6 +152,125 @@ export default function DebugScreen() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── Redirect-Test Card (Layer-1-Bypass-Repro) ─────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reproduziert den Casino-Mail-Fall: ein Klick geht erst auf einen ERLAUBTEN
|
||||||
|
* Zwischen-Host (wie SendGrid-Click-Tracking), der dann per HTTP-302 auf eine
|
||||||
|
* BLOCKIERTE Domain weiterleitet. Damit lässt sich gezielt prüfen, ob der
|
||||||
|
* DNS-Filter (Layer 1) die Zieldomain auch nach einem Redirect noch sinkholet.
|
||||||
|
*
|
||||||
|
* Nach dem Tippen: oben im "Protection Log" prüfen, ob ein `BLOCKED:`-Eintrag
|
||||||
|
* für tipico.de auftaucht.
|
||||||
|
*/
|
||||||
|
function RedirectTestCard() {
|
||||||
|
const colors = useColors();
|
||||||
|
|
||||||
|
// tipico.de ist sicher in der Blocklist (gambling-domains.json + 329k-Liste).
|
||||||
|
const BLOCKED = 'tipico.de';
|
||||||
|
// httpbin.org/redirect-to liefert eine echte HTTP-302-Response auf das Ziel —
|
||||||
|
// httpbin selbst ist nicht geblockt, spielt also den erlaubten Zwischen-Host.
|
||||||
|
const redirectUrl =
|
||||||
|
'https://httpbin.org/redirect-to?url=' +
|
||||||
|
encodeURIComponent('https://' + BLOCKED) +
|
||||||
|
'&status_code=302';
|
||||||
|
|
||||||
|
function open(url: string) {
|
||||||
|
Linking.openURL(url).catch((e) =>
|
||||||
|
Alert.alert('Fehler', String(e?.message ?? e)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Row({
|
||||||
|
icon,
|
||||||
|
label,
|
||||||
|
onPress,
|
||||||
|
}: {
|
||||||
|
icon: keyof typeof Ionicons.glyphMap;
|
||||||
|
label: string;
|
||||||
|
onPress: () => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={onPress}
|
||||||
|
activeOpacity={0.7}
|
||||||
|
style={{
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 8,
|
||||||
|
paddingVertical: 11,
|
||||||
|
paddingHorizontal: 12,
|
||||||
|
borderRadius: 10,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: colors.border,
|
||||||
|
marginTop: 8,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Ionicons name={icon} size={16} color={colors.textMuted} />
|
||||||
|
<Text style={{ flex: 1, fontSize: 13, fontFamily: 'Nunito_600SemiBold', color: colors.text }}>
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
<Ionicons name="open-outline" size={15} color={colors.textMuted} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
backgroundColor: colors.surface,
|
||||||
|
borderRadius: 14,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: 'rgba(0,0,0,0.05)',
|
||||||
|
padding: 14,
|
||||||
|
marginBottom: 12,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 10, marginBottom: 8 }}>
|
||||||
|
<View
|
||||||
|
style={{
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
borderRadius: 11,
|
||||||
|
backgroundColor: colors.surfaceElevated,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Ionicons name="arrow-redo-outline" size={18} color={colors.textMuted} />
|
||||||
|
</View>
|
||||||
|
<Text style={{ fontSize: 14, color: colors.text, fontFamily: 'Nunito_700Bold', flex: 1 }}>
|
||||||
|
Redirect-Test (Layer 1)
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
fontSize: 12,
|
||||||
|
fontFamily: 'Nunito_400Regular',
|
||||||
|
color: colors.textMuted,
|
||||||
|
lineHeight: 17,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Reproduziert den Casino-Mail-Fall: erlaubter Zwischen-Host → 302-Redirect
|
||||||
|
→ blockierte Domain (tipico.de). Beide tippen, dann oben den Protection
|
||||||
|
Log vergleichen — kommt ein „BLOCKED: tipico.de"?
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Row
|
||||||
|
icon="shield-checkmark-outline"
|
||||||
|
label="Kontrolle: tipico.de direkt"
|
||||||
|
onPress={() => open('https://' + BLOCKED)}
|
||||||
|
/>
|
||||||
|
<Row
|
||||||
|
icon="git-branch-outline"
|
||||||
|
label="Test: 302-Redirect → tipico.de"
|
||||||
|
onPress={() => open(redirectUrl)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ─── Realtime Status Card ──────────────────────────────────────────────────
|
// ─── Realtime Status Card ──────────────────────────────────────────────────
|
||||||
|
|
||||||
function RealtimeStatusCard() {
|
function RealtimeStatusCard() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user