namespace VideoDownloader.Browser; public enum PermissionVerdict { Ask, Allow, Deny } /// /// T3-11 사이트별 권한 정책 — 출처×종류 단위 기억. WebView2 PermissionRequested 에서 /// Ask 만 프롬프트로 올리고 Allow/Deny 는 즉시 응답. "항상" 선택은 네이티브 /// Profile.SetPermissionStateAsync 로도 영속(세션 밖 저장). /// public sealed class PermissionGate { /// 프롬프트 없이 거절: 센서류(피싱 표면 축소). private static readonly HashSet AutoDeny = new(StringComparer.OrdinalIgnoreCase) { "OtherSensors" }; /// 프롬프트 없이 허용: 연속 다운로드(다운로더 앱 본업). private static readonly HashSet AutoAllow = new(StringComparer.OrdinalIgnoreCase) { "MultipleAutomaticDownloads" }; private readonly Dictionary<(string origin, string kind), PermissionVerdict> _saved = new(); public PermissionVerdict Decide(string kind, string origin) { if (AutoDeny.Contains(kind)) return PermissionVerdict.Deny; if (AutoAllow.Contains(kind)) return PermissionVerdict.Allow; return _saved.GetValueOrDefault((origin, kind), PermissionVerdict.Ask); } public void Remember(string kind, string origin, PermissionVerdict verdict) => _saved[(origin, kind)] = verdict; } /// T3-14: 추적 스크립트 블랙리스트 — 호스트 또는 서브도메인 매칭. public sealed class TrackerBlocklist { /// 주요 광고/분석 도메인(EasyList 공통 항목 발췌). 생성자 주입으로 교체 가능(테스트). public static readonly string[] DefaultDomains = { "google-analytics.com", "googletagmanager.com", "doubleclick.net", "googlesyndication.com", "googleadservices.com", "scorecardresearch.com", "hotjar.com", "mixpanel.com", "segment.io", "facebook.net", "connect.facebook.net", "amplitude.com", "branch.io", "appsflyer.com", "criteo.com", "taboola.com", "outbrain.com", "adnxs.com", "pubmatic.com", "rubiconproject.com", }; private readonly HashSet _domains; public TrackerBlocklist() : this(DefaultDomains) { } public TrackerBlocklist(IEnumerable domains) => _domains = new HashSet(domains, StringComparer.OrdinalIgnoreCase); public bool Matches(Uri url) { var host = url.Host; foreach (var d in _domains) if (host.Equals(d, StringComparison.OrdinalIgnoreCase) || host.EndsWith("." + d, StringComparison.OrdinalIgnoreCase)) return true; return false; } } /// T3-14: 차단 카운터 — 총계/도메인별 집계, 변경 통지(실드 배지 갱신용). public sealed class TrackerCounter { private int _total; public int Total => Volatile.Read(ref _total); public Dictionary ByDomain { get; } = new(StringComparer.OrdinalIgnoreCase); public event Action? Changed; public void Record(string url) { var host = new Uri(url).Host; var baseDomain = host.StartsWith("www.", StringComparison.OrdinalIgnoreCase) ? host[4..] : host; Interlocked.Increment(ref _total); lock (ByDomain) { ByDomain[baseDomain] = ByDomain.GetValueOrDefault(baseDomain) + 1; } Changed?.Invoke(); } }