#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Standalone demonstration of the UTF-16 vs UTF-8 length mismatch that causes
PasswordProtectionJavaScriptFeature::ScriptMessageReceived to drop every
non-ASCII keystroke on iOS.

  JS side  (password_protection.ts:20):  event.key.length === 1   -> UTF-16 code units
  C++ side (password_protection_java_script_feature.mm:78):
           if ((*text).size() > 1) return;                       -> UTF-8 bytes

base::Value(std::u16string_view) stores strings as UTF-8 (base/values.cc:183),
so any code point >= U+0080 that the JS filter accepts (1 UTF-16 unit) arrives
in the .mm handler as 2-3 UTF-8 bytes and is silently dropped.
"""

SAMPLES = ['a', 'Z', '7', 'é', 'ü', 'ñ', 'ß', 'ø', 'я', '中', '€']

print(f"{'char':6} {'codepoint':10} {'utf16_units':12} {'utf8_bytes':11} "
      f"{'JS forwards?':13} {'mm handler'}")
print('-' * 70)
for ch in SAMPLES:
    cp = ord(ch)
    utf16_units = len(ch)                 # Python str length == UTF-16-ish code-unit count for BMP
    utf8_bytes  = len(ch.encode('utf-8'))
    js_forwards = utf16_units == 1
    mm_drops    = js_forwards and utf8_bytes > 1
    verdict = 'DROPPED (size()>1)' if mm_drops else ('OnKeyPressed' if js_forwards else 'filtered@JS')
    print(f"{ch!r:6} U+{cp:04X}     {utf16_units:<12} {utf8_bytes:<11} "
          f"{('yes' if js_forwards else 'no'):<13} {verdict}")

print()
print("Effect on PasswordReuseDetectionManager::input_characters_ for sample passwords:")
for pwd in ['café1234', 'Paßword1', 'contraseña', 'пароль123']:
    delivered = ''.join(c for c in pwd if len(c.encode('utf-8')) == 1)
    print(f"  saved={pwd!r:14}  delivered_to_reuse_manager={delivered!r:14}  "
          f"match? {'YES' if delivered == pwd else 'NO  -> PhishGuard never fires'}")
