From: uazo Date: Tue, 14 Mar 2023 15:48:21 +0000 Subject: Keyboard protection flag Hides user preference on the system keyboard by setting the standard eng layout and removing the layout information from the javascript keyboard events. License: GPL-2.0-or-later - https://spdx.org/licenses/GPL-2.0-or-later.html --- .../common/ProductionSupportedFlagList.java | 5 + .../Keyboard-protection-flag.inc | 10 ++ .../renderer/core/events/keyboard_event.cc | 136 ++++++++++++++++++ .../renderer/core/events/keyboard_event.h | 2 + ui/base/ui_base_features.cc | 8 ++ ui/base/ui_base_features.h | 2 + .../dom/dom_keyboard_layout_map_win.cc | 13 ++ .../keycodes/keyboard_code_conversion.cc | 10 +- ui/events/keycodes/keyboard_code_conversion.h | 2 +- 9 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 cromite_flags/chrome/browser/about_flags_cc/Keyboard-protection-flag.inc diff --git a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java --- a/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java +++ b/android_webview/java/src/org/chromium/android_webview/common/ProductionSupportedFlagList.java @@ -993,6 +993,11 @@ public final class ProductionSupportedFlagList { + " also enable the same behaviour as this flag. Additionally, developer" + " preferences via the AndroidX API or manifest metadata supersedes this" + " flag."), + Flag.baseFeature( + "SystemKeyboardProtection", + "Hides user preference on the system keyboard by setting the standard " + + "eng layout and removing the layout information from the " + + "javascript keyboard events."), Flag.baseFeature( BlinkFeatures.ASYNC_SET_COOKIE, "When enabled, the communication between renderer and network service is " diff --git a/cromite_flags/chrome/browser/about_flags_cc/Keyboard-protection-flag.inc b/cromite_flags/chrome/browser/about_flags_cc/Keyboard-protection-flag.inc new file mode 100644 --- /dev/null +++ b/cromite_flags/chrome/browser/about_flags_cc/Keyboard-protection-flag.inc @@ -0,0 +1,10 @@ +#ifdef FLAG_SECTION + + {"system-keyboard-protection", + "System keyboard protection", + "Hides user preference on the system keyboard by setting the standard " + "eng layout and removing the layout information from the " + "javascript keyboard events.", kOsAll, + FEATURE_VALUE_TYPE(features::kSystemKeyboardProtection)}, + +#endif diff --git a/third_party/blink/renderer/core/events/keyboard_event.cc b/third_party/blink/renderer/core/events/keyboard_event.cc --- a/third_party/blink/renderer/core/events/keyboard_event.cc +++ b/third_party/blink/renderer/core/events/keyboard_event.cc @@ -36,6 +36,18 @@ #include "third_party/blink/renderer/platform/windows_keyboard_codes.h" #include "ui/events/keycodes/dom/keycode_converter.h" +#include "base/feature_list.h" +#include "third_party/blink/renderer/core/dom/element.h" +#include "third_party/blink/renderer/core/dom/events/event_dispatch_result.h" +#include "third_party/blink/renderer/core/dom/events/event_dispatcher.h" +#include "third_party/blink/renderer/core/editing/editing_utilities.h" +#include "third_party/blink/renderer/core/html/forms/text_control_element.h" +#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h" +#include "ui/base/ui_base_features.h" +#include "ui/events/event_constants.h" +#include "ui/events/keycodes/dom/dom_codes_array.h" +#include "ui/events/keycodes/keyboard_code_conversion.h" + namespace blink { namespace { @@ -132,6 +144,124 @@ KeyboardEvent::KeyboardEvent(const WebKeyboardEvent& key, else key_code_ = char_code_; + bool keyboard_protection = features::IsSystemKeyboardProtectionEnabled(); + if (dom_window) { + if (auto* frame = dom_window->GetFrame()) { + String protocol = + frame->GetSecurityContext()->GetSecurityOrigin()->Protocol(); + if (SchemeRegistry::IsWebUIScheme(protocol)) { + keyboard_protection = false; + } + } + } + if (keyboard_protection) { + // we need character for transformation + ui::DomKey ascii_key; + ui::DomKey original_dom_key = + static_cast(key.dom_key); + // 1 <= char_code <= 26: exclude ctrl-a ... control-z + if (char_code_ > 26 && original_dom_key.IsCharacter()) + ascii_key = ui::DomKey::FromCharacter(key.text[0]); + else + ascii_key = original_dom_key; + + // if there is an element with focus, do not transform + // the characters into the English layout, since the + // recalculated character in the html innerText could + // be used to reconstruct the user's layout. + // if there is no focus, the event will contain the English + // layout information, since the real character will not be + // available for a textbox or content-editable element + // for comparision. + bool is_editable; + if (modifiers_ & WebInputEvent::kControlKey) { + // special case for ctrl keys + is_editable = false; + } else if (Document* document = dom_window->document()) { + if (Node* node = EventTargetNodeForDocument(document)) { + auto* text_control = ToTextControlOrNull(node); + auto* element = DynamicTo(node); + is_editable = IsEditable(*node) || + (text_control && !text_control->IsDisabledOrReadOnly()) || + (element && + EqualIgnoringAsciiCase( + element->FastGetAttribute(html_names::kRoleAttr), "textbox")); + } + } + + // get domcode of us layout keyboard + // we transform the character pressed by the user into + // the relevant domkey of the English keyboard + // so, for example: + // for ascii_key = " + // in italian keyboard --> shift + Digit2 + // in us keybord --> shift + Quote + int shift_needed = 0; + ui::DomCode us_code = ui::UsLayoutDomKeyToDomCode(ascii_key, &shift_needed); + if (us_code == ui::DomCode::NONE && !is_editable) { + // the keyboard may have non latin characters + // we have to traslate the DomCode to us layout DomCode + // but do not recalculate if there is an element with + // focus (or is a contenteditable) + ui::KeyboardCode ignored; + int flags = ui::EF_NONE; + if (modifiers_ & WebInputEvent::kAltKey) + flags |= ui::EF_ALT_DOWN; + if (modifiers_ & WebInputEvent::kControlKey) + flags |= ui::EF_CONTROL_DOWN; + if (modifiers_& WebInputEvent::kMetaKey) + flags |= ui::EF_COMMAND_DOWN; + if (modifiers_ & WebInputEvent::kShiftKey || + modifiers_ & WebInputEvent::kCapsLockOn) + flags |= ui::EF_SHIFT_DOWN; + if (modifiers_ & WebInputEvent::kNumLockOn) + flags |= ui::EF_NUM_LOCK_ON; + if (ui::DomCodeToUsLayoutDomKey( + static_cast(key.dom_code), flags, &ascii_key, &ignored)) { + us_code = ui::UsLayoutDomKeyToDomCode(ascii_key, &shift_needed); + } + } + + // adjust the shift modifier + if (shift_needed == 0) + modifiers_ &= ~WebInputEvent::kShiftKey; + else if (shift_needed == 1) + modifiers_ |= WebInputEvent::kShiftKey; + + // convert keyboard code to us layout (platform code) + if (type() == event_type_names::kKeydown || + type() == event_type_names::kKeyup) { + int windows_key_code = ui::DomCodeToUsLayoutNonLocatedKeyboardCode(us_code); + key_code_ = windows_key_code; + } + + // regenerate key_ and code_ for us keyboard + // if the value is not recalculated, or a key is not found + // in the English layout, the value is empty + key_ = FromUtf8(ui::KeycodeConverter::DomKeyToKeyString(ascii_key)); + code_ = FromUtf8(ui::KeycodeConverter::DomCodeToCodeString(us_code)); + + // suppress event if is ctrl/shift/alt... otherwise key_code of + // the next character can be stolen + // and do not send dead keys + // we cannot do otherwise because some characters are generated + // with the shift or without depending on the keyboard + if (ui::KeycodeConverter::IsDomKeyForModifier(original_dom_key) || + original_dom_key.IsDeadKey()) { + suppress_event_ = true; + } + + // do not leak status of numlock/capslock/scrolllock/etc + modifiers_ &= ~(WebInputEvent::kSymbolKey | WebInputEvent::kFnKey | + WebInputEvent::kAltGrKey | WebInputEvent::kMetaKey | + /*WebInputEvent::kAltKey |*/ WebInputEvent::kIsKeyPad | + WebInputEvent::kSymbolKey | WebInputEvent::kScrollLockOn | + WebInputEvent::kCapsLockOn | WebInputEvent::kNumLockOn); + + // always clear location + location_ = KeyboardEvent::kDomKeyLocationStandard; + } + #if BUILDFLAG(IS_ANDROID) // FIXME: Check to see if this applies to other OS. // If the key event belongs to IME composition then propagate to JS. @@ -205,6 +335,12 @@ unsigned KeyboardEvent::which() const { return (unsigned)keyCode(); } +DispatchEventResult KeyboardEvent::DispatchEvent(EventDispatcher& dispatcher) { + if (suppress_event_) + return DispatchEventResult::kNotCanceled; + return dispatcher.Dispatch(); +} + void KeyboardEvent::InitLocationModifiers(unsigned location) { switch (location) { case KeyboardEvent::kDomKeyLocationNumpad: diff --git a/third_party/blink/renderer/core/events/keyboard_event.h b/third_party/blink/renderer/core/events/keyboard_event.h --- a/third_party/blink/renderer/core/events/keyboard_event.h +++ b/third_party/blink/renderer/core/events/keyboard_event.h @@ -99,6 +99,7 @@ class CORE_EXPORT KeyboardEvent final : public UIEventWithKeyState { unsigned which() const override; bool isComposing() const { return is_composing_; } + DispatchEventResult DispatchEvent(EventDispatcher&) override; void Trace(Visitor*) const override; @@ -112,6 +113,7 @@ class CORE_EXPORT KeyboardEvent final : public UIEventWithKeyState { bool is_composing_ = false; unsigned char_code_ = 0; unsigned key_code_ = 0; + bool suppress_event_ = false; }; template <> diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc --- a/ui/base/ui_base_features.cc +++ b/ui/base/ui_base_features.cc @@ -145,6 +145,14 @@ bool ShouldUseCursorEventHook() { // Allows system keyboard event capture via the keyboard lock API. BASE_FEATURE(kSystemKeyboardLock, base::FEATURE_ENABLED_BY_DEFAULT); +CROMITE_FEATURE(kSystemKeyboardProtection, + "SystemKeyboardProtection", + base::FEATURE_ENABLED_BY_DEFAULT); + +bool IsSystemKeyboardProtectionEnabled() { + return base::FeatureList::IsEnabled(kSystemKeyboardProtection); +} + // Enables GPU rasterization for all UI drawing (where not blocklisted). BASE_FEATURE(kUiGpuRasterization, base::FEATURE_ENABLED_BY_DEFAULT); diff --git a/ui/base/ui_base_features.h b/ui/base/ui_base_features.h --- a/ui/base/ui_base_features.h +++ b/ui/base/ui_base_features.h @@ -29,6 +29,8 @@ COMPONENT_EXPORT(UI_BASE_FEATURES) BASE_DECLARE_FEATURE(kSettingsShowsPerKeyboardSettings); #endif // BUILDFLAG(IS_CHROMEOS) COMPONENT_EXPORT(UI_BASE_FEATURES) BASE_DECLARE_FEATURE(kSystemKeyboardLock); +COMPONENT_EXPORT(UI_BASE_FEATURES) BASE_DECLARE_FEATURE(kSystemKeyboardProtection); +COMPONENT_EXPORT(UI_BASE_FEATURES) bool IsSystemKeyboardProtectionEnabled(); COMPONENT_EXPORT(UI_BASE_FEATURES) BASE_DECLARE_FEATURE(kUiCompositorScrollWithLayers); COMPONENT_EXPORT(UI_BASE_FEATURES) diff --git a/ui/events/keycodes/dom/dom_keyboard_layout_map_win.cc b/ui/events/keycodes/dom/dom_keyboard_layout_map_win.cc --- a/ui/events/keycodes/dom/dom_keyboard_layout_map_win.cc +++ b/ui/events/keycodes/dom/dom_keyboard_layout_map_win.cc @@ -13,6 +13,8 @@ #include "base/check_op.h" #include "base/containers/flat_map.h" #include "base/logging.h" +#include "base/feature_list.h" +#include "ui/base/ui_base_features.h" #include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/keycodes/dom/dom_key.h" #include "ui/events/keycodes/dom/dom_keyboard_layout_map_base.h" @@ -73,6 +75,17 @@ uint32_t DomKeyboardLayoutMapWin::GetKeyboardLayoutCount() { iter != keyboard_layout_handles_.end()) std::iter_swap(keyboard_layout_handles_.begin(), iter); + if (features::IsSystemKeyboardProtectionEnabled()) { + HKL actual_layout = GetKeyboardLayout(0); + + // get handle for en-us keyboard layout + keyboard_layout_handles_.clear(); + keyboard_layout_handles_.resize(1); + keyboard_layout_handles_[0] = LoadKeyboardLayoutA("00000409", KLF_ACTIVATE); + + // reactivate user keyboard layout + ActivateKeyboardLayout(actual_layout, KLF_SETFORPROCESS); + } return keyboard_layout_handles_.size(); } diff --git a/ui/events/keycodes/keyboard_code_conversion.cc b/ui/events/keycodes/keyboard_code_conversion.cc --- a/ui/events/keycodes/keyboard_code_conversion.cc +++ b/ui/events/keycodes/keyboard_code_conversion.cc @@ -297,16 +297,22 @@ int ModifierDomKeyToEventFlag(DomKey key) { // DomKey::SYMBOL_LOCK } -DomCode UsLayoutDomKeyToDomCode(DomKey dom_key) { +DomCode UsLayoutDomKeyToDomCode(DomKey dom_key, int *need_shift) { if (dom_key.IsCharacter()) { char16_t c = dom_key.ToCharacter(); for (const auto& it : kPrintableCodeMap) { - if (it.character[0] == c || it.character[1] == c) { + if (it.character[0] == c) { + *need_shift = 0; + return it.dom_code; + } + if (it.character[1] == c) { + *need_shift = 1; return it.dom_code; } } } + *need_shift = -1; for (const auto& it : kNonPrintableCodeMap) { if (it.dom_key == dom_key) return it.dom_code; diff --git a/ui/events/keycodes/keyboard_code_conversion.h b/ui/events/keycodes/keyboard_code_conversion.h --- a/ui/events/keycodes/keyboard_code_conversion.h +++ b/ui/events/keycodes/keyboard_code_conversion.h @@ -111,7 +111,7 @@ EVENTS_BASE_EXPORT int ModifierDomKeyToEventFlag(DomKey key); // Returns the physical DOM code along with a corresponding non-located // Windows-based key_code. -EVENTS_BASE_EXPORT DomCode UsLayoutDomKeyToDomCode(DomKey dom_key); +EVENTS_BASE_EXPORT DomCode UsLayoutDomKeyToDomCode(DomKey dom_key, int *need_shift); } // namespace ui --