diff --git a/src/components/common/SecureWebView.tsx b/src/components/common/SecureWebView.tsx new file mode 100644 index 0000000..3d1fba6 --- /dev/null +++ b/src/components/common/SecureWebView.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { View, StyleSheet } from 'react-native'; +import { WebView, WebViewProps } from 'react-native-webview'; +import { CSP_TRUST_TIERS, TrustTier } from '../../config/security'; + +interface SecureWebViewProps extends Omit { + source: { html: string } | { uri: string }; + trustLevel?: TrustTier; + platformDomain?: string; +} + +export function SecureWebView({ + source, + trustLevel = 'restricted', + platformDomain = 'platform.com', + style, + ...props +}: SecureWebViewProps) { + const csp = CSP_TRUST_TIERS[trustLevel]; + const injectedJs = "(function(){var m=document.createElement('meta');m.httpEquiv='Content-Security-Policy';m.content='" + csp + "';document.head.insertBefore(m,document.head.firstChild);})();true;"; + const originWhitelist = trustLevel === 'restricted' ? undefined : ['https://*.' + platformDomain, 'https://' + platformDomain]; + + return ( + + + + ); +} + +const styles = StyleSheet.create({ container: { flex: 1 } }); diff --git a/src/config/security.ts b/src/config/security.ts index c5c82ef..02c6703 100644 --- a/src/config/security.ts +++ b/src/config/security.ts @@ -1,4 +1,4 @@ -export const NOTIFICATION_SCREEN_ALLOWLIST = new Set([ +export const NOTIFICATION_SCREEN_ALLOWLIST = new Set([ 'Home', 'Courses', 'CourseDetail', @@ -11,6 +11,13 @@ export const NOTIFICATION_SCREEN_ALLOWLIST = new Set([ 'AchievementDetail', ] as const); +export const CSP_TRUST_TIERS = { + restricted: "default-src 'none'; img-src 'self' data: https:; style-src 'self'; font-src 'self'; connect-src 'self'", + interactive: "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.platform.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https://api.platform.com; frame-src 'self'", + trusted: "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.platform.com; style-src 'self' 'unsafe-inline'; img-src * data: https:; font-src 'self' https://fonts.gstatic.com; connect-src *; frame-src *; media-src 'self' https://media.platform.com", +} as const; + +export type TrustTier = keyof typeof CSP_TRUST_TIERS; // ── SSL Certificate Pinning ─────────────────────────────────────────────────── // // SHA-256 SPKI fingerprints for the production API domain.