diff options
Diffstat (limited to 'chromium/components')
36 files changed, 716 insertions, 207 deletions
diff --git a/chromium/components/arc/common/notifications.mojom b/chromium/components/arc/common/notifications.mojom index 563ee775d83..50621f101b0 100644 --- a/chromium/components/arc/common/notifications.mojom +++ b/chromium/components/arc/common/notifications.mojom @@ -45,6 +45,15 @@ enum ArcNotificationExpandState { EXPANDED = 2, }; +// These values represent what shows in an ARC custom notification. +[Extensible, MinVersion=11] +enum ArcNotificationShownContents { + // The normal notification contents are shown. + CONTENTS_SHOWN = 0, + // The notification settings view is shown. + SETTINGS_SHOWN = 1, +}; + struct ArcNotificationData { // Identifier of notification string key; @@ -98,6 +107,9 @@ struct ArcNotificationData { // Flag if the notification is expandable [MinVersion=10] ArcNotificationExpandState expand_state; + // Flag for what shows in a notification. + [MinVersion=11] + ArcNotificationShownContents shown_contents; }; [MinVersion=2] diff --git a/chromium/components/autofill/content/browser/BUILD.gn b/chromium/components/autofill/content/browser/BUILD.gn index 88576886284..5fa6ea67efd 100644 --- a/chromium/components/autofill/content/browser/BUILD.gn +++ b/chromium/components/autofill/content/browser/BUILD.gn @@ -10,6 +10,8 @@ static_library("browser") { "content_autofill_driver.h", "content_autofill_driver_factory.cc", "content_autofill_driver_factory.h", + "key_press_handler_manager.cc", + "key_press_handler_manager.h", "risk/fingerprint.cc", "risk/fingerprint.h", ] @@ -61,6 +63,7 @@ source_set("unit_tests") { testonly = true sources = [ "content_autofill_driver_unittest.cc", + "key_press_handler_manager_unittest.cc", "payments/payments_client_unittest.cc", ] diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.cc b/chromium/components/autofill/content/browser/content_autofill_driver.cc index 710a1e74c9a..38bf3070fd2 100644 --- a/chromium/components/autofill/content/browser/content_autofill_driver.cc +++ b/chromium/components/autofill/content/browser/content_autofill_driver.cc @@ -20,6 +20,7 @@ #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/storage_partition.h" @@ -41,6 +42,7 @@ ContentAutofillDriver::ContentAutofillDriver( app_locale, enable_download_manager)), autofill_external_delegate_(autofill_manager_.get(), this), + key_press_handler_manager_(this), binding_(this) { autofill_manager_->SetExternalDelegate(&autofill_external_delegate_); } @@ -265,4 +267,29 @@ const mojom::AutofillAgentPtr& ContentAutofillDriver::GetAutofillAgent() { return autofill_agent_; } +void ContentAutofillDriver::RegisterKeyPressHandler( + const content::RenderWidgetHost::KeyPressEventCallback& handler) { + key_press_handler_manager_.RegisterKeyPressHandler(handler); +} + +void ContentAutofillDriver::RemoveKeyPressHandler() { + key_press_handler_manager_.RemoveKeyPressHandler(); +} + +void ContentAutofillDriver::AddHandler( + const content::RenderWidgetHost::KeyPressEventCallback& handler) { + content::RenderWidgetHostView* view = render_frame_host_->GetView(); + if (!view) + return; + view->GetRenderWidgetHost()->AddKeyPressEventCallback(handler); +} + +void ContentAutofillDriver::RemoveHandler( + const content::RenderWidgetHost::KeyPressEventCallback& handler) { + content::RenderWidgetHostView* view = render_frame_host_->GetView(); + if (!view) + return; + view->GetRenderWidgetHost()->RemoveKeyPressEventCallback(handler); +} + } // namespace autofill diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.h b/chromium/components/autofill/content/browser/content_autofill_driver.h index 0f6fb084027..f038f76f89c 100644 --- a/chromium/components/autofill/content/browser/content_autofill_driver.h +++ b/chromium/components/autofill/content/browser/content_autofill_driver.h @@ -9,6 +9,7 @@ #include <string> #include "base/supports_user_data.h" +#include "components/autofill/content/browser/key_press_handler_manager.h" #include "components/autofill/content/common/autofill_agent.mojom.h" #include "components/autofill/content/common/autofill_driver.mojom.h" #include "components/autofill/core/browser/autofill_driver.h" @@ -29,7 +30,8 @@ class AutofillClient; // communication from the renderer and from the external world. There is one // instance per RenderFrameHost. class ContentAutofillDriver : public AutofillDriver, - public mojom::AutofillDriver { + public mojom::AutofillDriver, + public KeyPressHandlerManager::Delegate { public: ContentAutofillDriver( content::RenderFrameHost* render_frame_host, @@ -103,12 +105,23 @@ class ContentAutofillDriver : public AutofillDriver, const mojom::AutofillAgentPtr& GetAutofillAgent(); + // Methods forwarded to key_press_handler_manager_. + void RegisterKeyPressHandler( + const content::RenderWidgetHost::KeyPressEventCallback& handler); + void RemoveKeyPressHandler(); + protected: // Sets the manager to |manager| and sets |manager|'s external delegate // to |autofill_external_delegate_|. Takes ownership of |manager|. void SetAutofillManager(std::unique_ptr<AutofillManager> manager); private: + // KeyPressHandlerManager::Delegate: + void AddHandler( + const content::RenderWidgetHost::KeyPressEventCallback& handler) override; + void RemoveHandler( + const content::RenderWidgetHost::KeyPressEventCallback& handler) override; + // Weak ref to the RenderFrameHost the driver is associated with. Should // always be non-NULL and valid for lifetime of |this|. content::RenderFrameHost* const render_frame_host_; @@ -124,6 +137,8 @@ class ContentAutofillDriver : public AutofillDriver, // case where the Autofill native UI is enabled. AutofillExternalDelegate autofill_external_delegate_; + KeyPressHandlerManager key_press_handler_manager_; + mojo::Binding<mojom::AutofillDriver> binding_; mojom::AutofillAgentPtr autofill_agent_; diff --git a/chromium/components/autofill/content/browser/key_press_handler_manager.cc b/chromium/components/autofill/content/browser/key_press_handler_manager.cc new file mode 100644 index 00000000000..96b463bc5d4 --- /dev/null +++ b/chromium/components/autofill/content/browser/key_press_handler_manager.cc @@ -0,0 +1,37 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/content/browser/key_press_handler_manager.h" + +namespace autofill { + +KeyPressHandlerManager::KeyPressHandlerManager(Delegate* delegate) + : delegate_(delegate) {} + +KeyPressHandlerManager::~KeyPressHandlerManager() = default; + +void KeyPressHandlerManager::RegisterKeyPressHandler( + const content::RenderWidgetHost::KeyPressEventCallback& handler) { + // It would have been nice to be able to tell if two callbacks are just the + // same function with the same bound arguments. That's not what Equals() does + // (they have to have the same BindState), but it's the closest approximation + // available. + if (handler.is_null() || handler.Equals(handler_)) + return; + + if (!handler_.is_null()) + delegate_->RemoveHandler(handler_); + handler_ = handler; + delegate_->AddHandler(handler_); +} + +void KeyPressHandlerManager::RemoveKeyPressHandler() { + if (handler_.is_null()) + return; + + delegate_->RemoveHandler(handler_); + handler_.Reset(); +} + +} // namespace autofill diff --git a/chromium/components/autofill/content/browser/key_press_handler_manager.h b/chromium/components/autofill/content/browser/key_press_handler_manager.h new file mode 100644 index 00000000000..916ca9df3bb --- /dev/null +++ b/chromium/components/autofill/content/browser/key_press_handler_manager.h @@ -0,0 +1,47 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_AUTOFILL_CONTENT_BROWSER_KEY_PRESS_HANDLER_MANAGER_H_ +#define COMPONENTS_AUTOFILL_CONTENT_BROWSER_KEY_PRESS_HANDLER_MANAGER_H_ + +#include "base/macros.h" +#include "content/public/browser/render_widget_host.h" + +namespace autofill { + +// KeyPressHandlerManager allows registering a key press handler and ensuring +// its unregistering in case of destruction of the manager or request for +// registration of another handler. It still needs a Delegate implementation to +// use the low-level handler registration API. + +class KeyPressHandlerManager { + public: + class Delegate { + public: + virtual void AddHandler( + const content::RenderWidgetHost::KeyPressEventCallback& handler) = 0; + virtual void RemoveHandler( + const content::RenderWidgetHost::KeyPressEventCallback& handler) = 0; + }; + + explicit KeyPressHandlerManager(Delegate* delegate); + + virtual ~KeyPressHandlerManager(); + + void RegisterKeyPressHandler( + const content::RenderWidgetHost::KeyPressEventCallback& handler); + + void RemoveKeyPressHandler(); // Unregisters previous handler. + + private: + Delegate* const delegate_; + + content::RenderWidgetHost::KeyPressEventCallback handler_; + + DISALLOW_COPY_AND_ASSIGN(KeyPressHandlerManager); +}; + +} // namespace autofill + +#endif // COMPONENTS_AUTOFILL_CONTENT_BROWSER_KEY_PRESS_HANDLER_MANAGER_H_ diff --git a/chromium/components/autofill/content/browser/key_press_handler_manager_unittest.cc b/chromium/components/autofill/content/browser/key_press_handler_manager_unittest.cc new file mode 100644 index 00000000000..e839b3d2b2e --- /dev/null +++ b/chromium/components/autofill/content/browser/key_press_handler_manager_unittest.cc @@ -0,0 +1,113 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill/content/browser/key_press_handler_manager.h" + +#include <string> + +#include "base/bind.h" +#include "content/public/browser/native_web_keyboard_event.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace autofill { + +namespace { + +const content::NativeWebKeyboardEvent + kDummyEvent(blink::WebInputEvent::Undefined, 0, 0); + +// Dummy keyboard event handler: ignores the event, but appends the given |name| +// to a logging |target|. +bool DummyHandler(const char* name, + std::string* target, + const content::NativeWebKeyboardEvent& /*event*/) { + target->append(name); + return false; +} + +// A delegate which logs the handlers instead of adding and removing them. +class LoggingDelegate : public KeyPressHandlerManager::Delegate { + public: + explicit LoggingDelegate(std::string* target) : target_(target) {} + + // KeyPressHandlerManager::Delegate: + void AddHandler(const content::RenderWidgetHost::KeyPressEventCallback& + handler) override { + target_->append("A"); + handler.Run(kDummyEvent); + } + void RemoveHandler(const content::RenderWidgetHost::KeyPressEventCallback& + handler) override { + target_->append("R"); + handler.Run(kDummyEvent); + } + + private: + std::string* const target_; +}; + +} // namespace + +class KeyPressHandlerManagerTest : public testing::Test { + public: + KeyPressHandlerManagerTest() : delegate_(&callback_trace_) {} + + protected: + content::RenderWidgetHost::KeyPressEventCallback CallbackForName( + const char* name) { + return base::Bind(DummyHandler, name, &callback_trace_); + } + + // String encoding the events related to adding and removing callbacks. For + // example, "A1R1A2R2" means that callback "1" was added, then removed, and + // then callback "2" was added and removed. + std::string callback_trace_; + + LoggingDelegate delegate_; +}; + +// Removing should remove the previously added callback. +TEST_F(KeyPressHandlerManagerTest, AddRemove) { + KeyPressHandlerManager manager(&delegate_); + manager.RegisterKeyPressHandler(CallbackForName("1")); + manager.RemoveKeyPressHandler(); + EXPECT_EQ("A1R1", callback_trace_); +} + +// Registering a new callback should remove the old one. +TEST_F(KeyPressHandlerManagerTest, AddReplace) { + KeyPressHandlerManager manager(&delegate_); + manager.RegisterKeyPressHandler(CallbackForName("1")); + manager.RegisterKeyPressHandler(CallbackForName("2")); + manager.RemoveKeyPressHandler(); + EXPECT_EQ("A1R1A2R2", callback_trace_); +} + +// Without registering a callback first, none should be removed. +TEST_F(KeyPressHandlerManagerTest, NoRemove) { + KeyPressHandlerManager manager(&delegate_); + manager.RemoveKeyPressHandler(); + EXPECT_EQ(std::string(), callback_trace_); +} + +// Adding one callback twice should be a no-op. +TEST_F(KeyPressHandlerManagerTest, AddTwice) { + KeyPressHandlerManager manager(&delegate_); + auto callback = CallbackForName("1"); + manager.RegisterKeyPressHandler(callback); + manager.RegisterKeyPressHandler(callback); + manager.RemoveKeyPressHandler(); + EXPECT_EQ("A1R1", callback_trace_); +} + +// Removing one callback twice should be a no-op. +TEST_F(KeyPressHandlerManagerTest, RemoveTwice) { + KeyPressHandlerManager manager(&delegate_); + manager.RegisterKeyPressHandler(CallbackForName("1")); + manager.RemoveKeyPressHandler(); + manager.RemoveKeyPressHandler(); + EXPECT_EQ("A1R1", callback_trace_); +} + +} // namespace autofill diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.cc b/chromium/components/autofill/core/browser/autofill_external_delegate.cc index 5853a8de1d7..3db7f0fd00b 100644 --- a/chromium/components/autofill/core/browser/autofill_external_delegate.cc +++ b/chromium/components/autofill/core/browser/autofill_external_delegate.cc @@ -285,6 +285,10 @@ bool AutofillExternalDelegate::IsCreditCardPopup() { return is_credit_card_popup_; } +AutofillDriver* AutofillExternalDelegate::GetAutofillDriver() { + return driver_; +} + void AutofillExternalDelegate::Reset() { manager_->client()->HideAutofillPopup(); } diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.h b/chromium/components/autofill/core/browser/autofill_external_delegate.h index 6a9807a0505..a5984209fa9 100644 --- a/chromium/components/autofill/core/browser/autofill_external_delegate.h +++ b/chromium/components/autofill/core/browser/autofill_external_delegate.h @@ -54,6 +54,7 @@ class AutofillExternalDelegate : public AutofillPopupDelegate { // Returns false for all popups prior to |onQuery|, true for credit card // popups after call to |onQuery|. bool IsCreditCardPopup() override; + AutofillDriver* GetAutofillDriver() override; // Records and associates a query_id with web form data. Called // when the renderer posts an Autofill query to the browser. |bounds| diff --git a/chromium/components/autofill/core/browser/autofill_popup_delegate.h b/chromium/components/autofill/core/browser/autofill_popup_delegate.h index 5a864242755..6febbf91cfc 100644 --- a/chromium/components/autofill/core/browser/autofill_popup_delegate.h +++ b/chromium/components/autofill/core/browser/autofill_popup_delegate.h @@ -9,6 +9,8 @@ namespace autofill { +class AutofillDriver; + // An interface for interaction with AutofillPopupController. Will be notified // of events by the controller. class AutofillPopupDelegate { @@ -46,6 +48,9 @@ class AutofillPopupDelegate { // Returns true if popup is for credit card. virtual bool IsCreditCardPopup() = 0; + + // Returns the associated AutofillDriver. + virtual AutofillDriver* GetAutofillDriver() = 0; }; } // namespace autofill diff --git a/chromium/components/display_compositor/buffer_queue.cc b/chromium/components/display_compositor/buffer_queue.cc index afb40e1a491..60b50d7a8bb 100644 --- a/chromium/components/display_compositor/buffer_queue.cc +++ b/chromium/components/display_compositor/buffer_queue.cc @@ -183,13 +183,32 @@ std::unique_ptr<BufferQueue::AllocatedSurface> BufferQueue::RecreateBuffer( } void BufferQueue::PageFlipComplete() { - DCHECK(!in_flight_surfaces_.empty()); + // Early out when no surface is in-flight. This can happen when using + // overlays and page flipping without changing the primary plane. + if (in_flight_surfaces_.empty()) + return; if (displayed_surface_) available_surfaces_.push_back(std::move(displayed_surface_)); displayed_surface_ = std::move(in_flight_surfaces_.front()); in_flight_surfaces_.pop_front(); } +uint32_t BufferQueue::GetCurrentTextureId() const { + // Return current surface texture if bound. + if (current_surface_) + return current_surface_->texture; + + // Return in-flight or displayed surface texture if no surface is + // currently bound. This can happen when using overlays and surface + // damage is empty. + if (!in_flight_surfaces_.empty()) + return in_flight_surfaces_.back()->texture; + if (displayed_surface_) + return displayed_surface_->texture; + + return 0; +} + void BufferQueue::FreeAllSurfaces() { displayed_surface_.reset(); current_surface_.reset(); diff --git a/chromium/components/display_compositor/buffer_queue.h b/chromium/components/display_compositor/buffer_queue.h index 7ac212e1be7..c6bedbb1757 100644 --- a/chromium/components/display_compositor/buffer_queue.h +++ b/chromium/components/display_compositor/buffer_queue.h @@ -60,12 +60,9 @@ class DISPLAY_COMPOSITOR_EXPORT BufferQueue { float scale_factor, const gfx::ColorSpace& color_space, bool use_stencil); - void RecreateBuffers(); + uint32_t GetCurrentTextureId() const; - uint32_t current_texture_id() const { - return current_surface_ ? current_surface_->texture : 0; - } uint32_t fbo() const { return fbo_; } uint32_t internal_format() const { return internal_format_; } diff --git a/chromium/components/exo/pointer.cc b/chromium/components/exo/pointer.cc index 61442ed0608..1697f5c34dc 100644 --- a/chromium/components/exo/pointer.cc +++ b/chromium/components/exo/pointer.cc @@ -380,8 +380,12 @@ void Pointer::OnCursorCaptured(const gfx::Point& hotspot, void Pointer::UpdateCursor() { DCHECK(focus_); + aura::Window* root_window = focus_->window()->GetRootWindow(); + if (!root_window) + return; + aura::client::CursorClient* cursor_client = - aura::client::GetCursorClient(focus_->window()->GetRootWindow()); + aura::client::GetCursorClient(root_window); if (cursor_client) cursor_client->SetCursor(cursor_); } diff --git a/chromium/components/exo/shell_surface.cc b/chromium/components/exo/shell_surface.cc index 97c18fee52e..57460ab9654 100644 --- a/chromium/components/exo/shell_surface.cc +++ b/chromium/components/exo/shell_surface.cc @@ -596,7 +596,7 @@ void ShellSurface::SetGeometry(const gfx::Rect& geometry) { void ShellSurface::SetRectangularShadowEnabled(bool enabled) { TRACE_EVENT1("exo", "ShellSurface::SetRectangularShadowEnabled", "enabled", enabled); - shadow_underlay_in_surface_ = false; + pending_shadow_underlay_in_surface_ = false; shadow_enabled_ = enabled; } @@ -604,7 +604,7 @@ void ShellSurface::SetRectangularShadow_DEPRECATED( const gfx::Rect& content_bounds) { TRACE_EVENT1("exo", "ShellSurface::SetRectangularShadow_DEPRECATED", "content_bounds", content_bounds.ToString()); - shadow_underlay_in_surface_ = false; + pending_shadow_underlay_in_surface_ = false; shadow_content_bounds_ = content_bounds; shadow_enabled_ = !content_bounds.IsEmpty(); } @@ -613,7 +613,7 @@ void ShellSurface::SetRectangularSurfaceShadow( const gfx::Rect& content_bounds) { TRACE_EVENT1("exo", "ShellSurface::SetRectangularSurfaceShadow", "content_bounds", content_bounds.ToString()); - shadow_underlay_in_surface_ = true; + pending_shadow_underlay_in_surface_ = true; shadow_content_bounds_ = content_bounds; shadow_enabled_ = !content_bounds.IsEmpty(); } @@ -847,13 +847,26 @@ base::string16 ShellSurface::GetWindowTitle() const { return title_; } +void ShellSurface::SaveWindowPlacement(const gfx::Rect& bounds, + ui::WindowShowState show_state) { + if (bounds_mode_ != BoundsMode::CLIENT) + WidgetDelegate::SaveWindowPlacement(bounds, show_state); +} + +bool ShellSurface::GetSavedWindowPlacement( + const views::Widget* widget, + gfx::Rect* bounds, + ui::WindowShowState* show_state) const { + if (bounds_mode_ != BoundsMode::CLIENT) + return WidgetDelegate::GetSavedWindowPlacement(widget, bounds, show_state); + return false; +} + void ShellSurface::WindowClosing() { if (resizer_) EndDrag(true /* revert */); SetEnabled(false); widget_ = nullptr; - shadow_overlay_ = nullptr; - shadow_underlay_ = nullptr; } views::Widget* ShellSurface::GetWidget() { @@ -1143,8 +1156,7 @@ void ShellSurface::CreateShellSurfaceWidget(ui::WindowShowState show_state) { // Allow the client to request bounds that do not fill the entire work area // when maximized, or the entire display when fullscreen. - window_state->set_allow_set_bounds_in_maximized( - bounds_mode_ == BoundsMode::CLIENT); + window_state->set_allow_set_bounds_direct(bounds_mode_ == BoundsMode::CLIENT); // Notify client of initial state if different than normal. if (window_state->GetStateType() != ash::wm::WINDOW_STATE_TYPE_NORMAL && @@ -1388,7 +1400,7 @@ void ShellSurface::UpdateWidgetBounds() { ash::wm::WindowState* window_state = ash::wm::GetWindowState(widget_->GetNativeWindow()); if (window_state->IsMaximizedOrFullscreenOrPinned() && - !window_state->allow_set_bounds_in_maximized()) { + !window_state->allow_set_bounds_direct()) { return; } @@ -1449,8 +1461,23 @@ void ShellSurface::UpdateSurfaceBounds() { void ShellSurface::UpdateShadow() { if (!widget_ || !surface_) return; + if (shadow_underlay_in_surface_ != pending_shadow_underlay_in_surface_) { + shadow_underlay_in_surface_ = pending_shadow_underlay_in_surface_; + shadow_overlay_.reset(); + shadow_underlay_.reset(); + } + aura::Window* window = widget_->GetNativeWindow(); - if (!shadow_enabled_) { + + bool underlay_capture_events = + WMHelper::GetInstance()->IsSpokenFeedbackEnabled() && widget_->IsActive(); + bool black_background_enabled = + ((widget_->IsFullscreen() || widget_->IsMaximized()) || + underlay_capture_events) && + ash::wm::GetWindowState(window)->allow_set_bounds_direct() && + window->layer()->GetTargetTransform().IsIdentity(); + + if (!shadow_enabled_ && !black_background_enabled) { wm::SetShadowElevation(window, wm::ShadowElevation::NONE); if (shadow_underlay_) shadow_underlay_->Hide(); @@ -1497,11 +1524,12 @@ void ShellSurface::UpdateShadow() { // Always create and show the underlay, even in maximized/fullscreen. if (!shadow_underlay_) { - shadow_underlay_ = new aura::Window(nullptr); + shadow_underlay_ = base::MakeUnique<aura::Window>(nullptr); + shadow_underlay_->set_owned_by_parent(false); shadow_underlay_event_handler_ = base::MakeUnique<ShadowUnderlayEventHandler>(); shadow_underlay_->SetTargetHandler(shadow_underlay_event_handler_.get()); - DCHECK(shadow_underlay_->owned_by_parent()); + DCHECK(!shadow_underlay_->owned_by_parent()); // Ensure the background area inside the shadow is solid black. // Clients that provide translucent contents should not be using // rectangular shadows as this method requires opaque contents to @@ -1510,18 +1538,14 @@ void ShellSurface::UpdateShadow() { shadow_underlay_->layer()->SetColor(SK_ColorBLACK); DCHECK(shadow_underlay_->layer()->fills_bounds_opaquely()); if (shadow_underlay_in_surface_) { - surface_->window()->AddChild(shadow_underlay_); - surface_->window()->StackChildAtBottom(shadow_underlay_); + surface_->window()->AddChild(shadow_underlay()); + surface_->window()->StackChildAtBottom(shadow_underlay()); } else { - window->AddChild(shadow_underlay_); - window->StackChildAtBottom(shadow_underlay_); + window->AddChild(shadow_underlay()); + window->StackChildAtBottom(shadow_underlay()); } } - bool underlay_capture_events = - WMHelper::GetInstance()->IsSpokenFeedbackEnabled() && - widget_->IsActive(); - float shadow_underlay_opacity = shadow_background_opacity_; // Put the black background layer behind the window if @@ -1531,10 +1555,7 @@ void ShellSurface::UpdateShadow() { // thus the background can be visible). // 3) the window has no transform (the transformed background may // not cover the entire background, e.g. overview mode). - if ((widget_->IsFullscreen() || widget_->IsMaximized() || - underlay_capture_events) && - ash::wm::GetWindowState(window)->allow_set_bounds_in_maximized() && - window->layer()->GetTargetTransform().IsIdentity()) { + if (black_background_enabled) { if (shadow_underlay_in_surface_) { shadow_underlay_bounds = gfx::Rect(surface_->window()->bounds().size()); } else { @@ -1558,6 +1579,9 @@ void ShellSurface::UpdateShadow() { shadow_underlay_->SetBounds(shadow_underlay_bounds); + if (!shadow_underlay_->IsVisible()) + shadow_underlay_->Show(); + // TODO(oshima): Setting to the same value should be no-op. // crbug.com/642223. if (shadow_underlay_opacity != @@ -1565,25 +1589,24 @@ void ShellSurface::UpdateShadow() { shadow_underlay_->layer()->SetOpacity(shadow_underlay_opacity); } - shadow_underlay_->Show(); - wm::Shadow* shadow = wm::ShadowController::GetShadowForWindow(window); // Maximized/Fullscreen window does not create a shadow. if (!shadow) return; if (!shadow_overlay_) { - shadow_overlay_ = new aura::Window(nullptr); - DCHECK(shadow_overlay_->owned_by_parent()); + shadow_overlay_ = base::MakeUnique<aura::Window>(nullptr); + shadow_overlay_->set_owned_by_parent(false); + DCHECK(!shadow_overlay_->owned_by_parent()); shadow_overlay_->set_ignore_events(true); shadow_overlay_->Init(ui::LAYER_NOT_DRAWN); shadow_overlay_->layer()->Add(shadow->layer()); - window->AddChild(shadow_overlay_); + window->AddChild(shadow_overlay()); if (shadow_underlay_in_surface_) { - window->StackChildBelow(shadow_overlay_, surface_->window()); + window->StackChildBelow(shadow_overlay(), surface_->window()); } else { - window->StackChildAbove(shadow_overlay_, shadow_underlay_); + window->StackChildAbove(shadow_overlay(), shadow_underlay()); } shadow_overlay_->Show(); } diff --git a/chromium/components/exo/shell_surface.h b/chromium/components/exo/shell_surface.h index d621a988607..0bf2b7e916f 100644 --- a/chromium/components/exo/shell_surface.h +++ b/chromium/components/exo/shell_surface.h @@ -220,6 +220,11 @@ class ShellSurface : public SurfaceDelegate, bool CanMaximize() const override; bool CanMinimize() const override; base::string16 GetWindowTitle() const override; + void SaveWindowPlacement(const gfx::Rect& bounds, + ui::WindowShowState show_state) override; + bool GetSavedWindowPlacement(const views::Widget* widget, + gfx::Rect* bounds, + ui::WindowShowState* show_state) const override; void WindowClosing() override; views::Widget* GetWidget() override; const views::Widget* GetWidget() const override; @@ -260,8 +265,8 @@ class ShellSurface : public SurfaceDelegate, // Overridden from ui::AcceleratorTarget: bool AcceleratorPressed(const ui::Accelerator& accelerator) override; - aura::Window* shadow_overlay() { return shadow_overlay_; } - aura::Window* shadow_underlay() { return shadow_underlay_; } + aura::Window* shadow_overlay() { return shadow_overlay_.get(); } + aura::Window* shadow_underlay() { return shadow_underlay_.get(); } Surface* surface_for_testing() { return surface_; } @@ -342,8 +347,8 @@ class ShellSurface : public SurfaceDelegate, gfx::Vector2d pending_origin_offset_accumulator_; int resize_component_ = HTCAPTION; // HT constant (see ui/base/hit_test.h) int pending_resize_component_ = HTCAPTION; - aura::Window* shadow_overlay_ = nullptr; - aura::Window* shadow_underlay_ = nullptr; + std::unique_ptr<aura::Window> shadow_overlay_; + std::unique_ptr<aura::Window> shadow_underlay_; std::unique_ptr<ui::EventHandler> shadow_underlay_event_handler_; gfx::Rect shadow_content_bounds_; float shadow_background_opacity_ = 1.0; @@ -353,6 +358,7 @@ class ShellSurface : public SurfaceDelegate, int top_inset_height_ = 0; int pending_top_inset_height_ = 0; bool shadow_underlay_in_surface_ = true; + bool pending_shadow_underlay_in_surface_ = true; bool system_modal_ = false; DISALLOW_COPY_AND_ASSIGN(ShellSurface); diff --git a/chromium/components/exo/shell_surface_unittest.cc b/chromium/components/exo/shell_surface_unittest.cc index 5e300222acb..b8dbca007cd 100644 --- a/chromium/components/exo/shell_surface_unittest.cc +++ b/chromium/components/exo/shell_surface_unittest.cc @@ -829,6 +829,20 @@ TEST_F(ShellSurfaceTest, ShadowStartMaximized) { ASSERT_TRUE(shell_surface->shadow_underlay()); EXPECT_TRUE(shell_surface->shadow_underlay()->IsVisible()); + shell_surface->SetRectangularSurfaceShadow(gfx::Rect(0, 0, 0, 0)); + // Underlay should be created even without shadow. + ASSERT_TRUE(shell_surface->shadow_underlay()); + EXPECT_TRUE(shell_surface->shadow_underlay()->IsVisible()); + shell_surface->SetRectangularShadowEnabled(false); + surface->Commit(); + // Underlay should be created even without shadow. + ASSERT_TRUE(shell_surface->shadow_underlay()); + EXPECT_TRUE(shell_surface->shadow_underlay()->IsVisible()); + + shell_surface->SetRectangularShadowEnabled(true); + shell_surface->SetRectangularSurfaceShadow(gfx::Rect(10, 10, 100, 100)); + surface->Commit(); + // Restore the window and make sure the shadow is created, visible and // has the latest bounds. widget->Restore(); @@ -1011,5 +1025,41 @@ TEST_F(ShellSurfaceTest, SpokenFeedbackFullscreenBackground) { EXPECT_EQ(shadow_bounds, shell_surface2.shadow_underlay()->bounds()); } +// Make sure that a surface shell started in maximize creates deprecated +// shadow correctly. +TEST_F(ShellSurfaceTest, + StartMaximizedThenMinimizeWithSetRectangularShadow_DEPRECATED) { + const gfx::Size display_size = + display::Screen::GetScreen()->GetPrimaryDisplay().size(); + const gfx::Size buffer_size(display_size); + std::unique_ptr<Buffer> buffer( + new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size))); + std::unique_ptr<Surface> surface(new Surface); + std::unique_ptr<ShellSurface> shell_surface(new ShellSurface( + surface.get(), nullptr, ShellSurface::BoundsMode::CLIENT, gfx::Point(), + true, false, ash::kShellWindowId_DefaultContainer)); + + // Start in maximized. + shell_surface->Maximize(); + surface->Attach(buffer.get()); + surface->Commit(); + + gfx::Rect shadow_bounds = + display::Screen::GetScreen()->GetPrimaryDisplay().bounds(); + shell_surface->SetGeometry(shadow_bounds); + shell_surface->SetRectangularShadow_DEPRECATED(shadow_bounds); + surface->Commit(); + EXPECT_EQ(shadow_bounds, + shell_surface->GetWidget()->GetWindowBoundsInScreen()); + ASSERT_EQ(shadow_bounds, shell_surface->shadow_underlay()->bounds()); + EXPECT_EQ(display::Screen::GetScreen()->GetPrimaryDisplay().size(), + shell_surface->surface_for_testing()->window()->bounds().size()); + + ash::wm::WMEvent minimize_event(ash::wm::WM_EVENT_MINIMIZE); + ash::WmWindow* window = + ash::WmWindow::Get(shell_surface->GetWidget()->GetNativeWindow()); + window->GetWindowState()->OnWMEvent(&minimize_event); +} + } // namespace } // namespace exo diff --git a/chromium/components/exo/touch.cc b/chromium/components/exo/touch.cc index fa2de6dd507..2ebdbb5950d 100644 --- a/chromium/components/exo/touch.cc +++ b/chromium/components/exo/touch.cc @@ -147,8 +147,13 @@ void Touch::OnTouchEvent(ui::TouchEvent* event) { return; } if (send_details) { - delegate_->OnTouchShape(touch_pointer_id, event->pointer_details().radius_x, - event->pointer_details().radius_y); + // Some devices do not report radius_y/minor. We assume a circular shape + // in that case. + float major = event->pointer_details().radius_x * 2.0f; + float minor = event->pointer_details().radius_y * 2.0f; + if (!minor) + minor = major; + delegate_->OnTouchShape(touch_pointer_id, major, minor); if (stylus_delegate_ && event->pointer_details().pointer_type != diff --git a/chromium/components/exo/touch_unittest.cc b/chromium/components/exo/touch_unittest.cc index 18917fb7544..1384229ac62 100644 --- a/chromium/components/exo/touch_unittest.cc +++ b/chromium/components/exo/touch_unittest.cc @@ -164,23 +164,24 @@ TEST_F(TouchTest, OnTouchShape) { testing::InSequence sequence; EXPECT_CALL(delegate, OnTouchDown(window.surface(), testing::_, testing::_, gfx::PointF())); - EXPECT_CALL(delegate, OnTouchShape(testing::_, 1, 1)); + EXPECT_CALL(delegate, OnTouchShape(testing::_, 20, 10)); EXPECT_CALL(delegate, OnTouchFrame()); EXPECT_CALL(delegate, OnTouchMotion(testing::_, testing::_, gfx::PointF(5, 5))); - EXPECT_CALL(delegate, OnTouchShape(testing::_, 1, 1)); + EXPECT_CALL(delegate, OnTouchShape(testing::_, 20, 10)); EXPECT_CALL(delegate, OnTouchFrame()); EXPECT_CALL(delegate, OnTouchMotion(testing::_, testing::_, gfx::PointF(10, 10))); - EXPECT_CALL(delegate, OnTouchShape(testing::_, 20, 10)); + EXPECT_CALL(delegate, OnTouchShape(testing::_, 20, 20)); EXPECT_CALL(delegate, OnTouchFrame()); EXPECT_CALL(delegate, OnTouchUp(testing::_, testing::_)); EXPECT_CALL(delegate, OnTouchFrame()); } generator.set_current_location(window.origin()); + generator.SetTouchRadius(10, 5); generator.PressTouch(); generator.MoveTouchBy(5, 5); - generator.SetTouchRadius(20, 10); + generator.SetTouchRadius(10, 0); // Minor not supported generator.MoveTouchBy(5, 5); generator.ReleaseTouch(); EXPECT_CALL(delegate, OnTouchDestroying(touch.get())); diff --git a/chromium/components/exo/wayland/server.cc b/chromium/components/exo/wayland/server.cc index 0abc727db2a..0faf554a77f 100644 --- a/chromium/components/exo/wayland/server.cc +++ b/chromium/components/exo/wayland/server.cc @@ -157,6 +157,10 @@ DEFINE_UI_CLASS_PROPERTY_KEY(bool, kSurfaceHasSecurityKey, false); // associated with window. DEFINE_UI_CLASS_PROPERTY_KEY(bool, kSurfaceHasBlendingKey, false); +// A property key containing a boolean set to true whether the current +// OnWindowActivated invocation should be ignored. +DEFINE_UI_CLASS_PROPERTY_KEY(bool, kIgnoreWindowActivated, false); + wl_resource* GetSurfaceResource(Surface* surface) { return surface->GetProperty(kSurfaceResourceKey); } @@ -1925,7 +1929,14 @@ void remote_surface_set_top_inset(wl_client* client, void remote_surface_activate(wl_client* client, wl_resource* resource, uint32_t serial) { + ShellSurface* shell_surface = GetUserDataAs<ShellSurface>(resource); + aura::Window* window = shell_surface->GetWidget()->GetNativeWindow(); + + // Activation on Aura is synchronous, so activation callbacks will be called + // before the flag is reset. + window->SetProperty(kIgnoreWindowActivated, true); GetUserDataAs<ShellSurface>(resource)->Activate(); + window->ClearProperty(kIgnoreWindowActivated); } void remote_surface_maximize(wl_client* client, wl_resource* resource) { @@ -2106,6 +2117,13 @@ class WaylandRemoteShell : public WMHelper::MaximizeModeObserver, // Overridden from WMHelper::ActivationObserver: void OnWindowActivated(aura::Window* gained_active, aura::Window* lost_active) override { + // If the origin of activation is Wayland client, then assume it's been + // already activated on the client side, so do not notify about the + // activation. It means that zcr_remote_shell_v1_send_activated is used + // only to notify about activations originating in Aura. + if (gained_active && gained_active->GetProperty(kIgnoreWindowActivated)) + return; + SendActivated(gained_active, lost_active); } @@ -2934,7 +2952,7 @@ void seat_release(wl_client* client, wl_resource* resource) { const struct wl_seat_interface seat_implementation = { seat_get_pointer, seat_get_keyboard, seat_get_touch, seat_release}; -const uint32_t seat_version = 5; +const uint32_t seat_version = 6; void bind_seat(wl_client* client, void* data, uint32_t version, uint32_t id) { wl_resource* resource = wl_resource_create( diff --git a/chromium/components/offline_pages/core/downloads/download_notifying_observer.cc b/chromium/components/offline_pages/core/downloads/download_notifying_observer.cc index 37836088129..00cc67daf40 100644 --- a/chromium/components/offline_pages/core/downloads/download_notifying_observer.cc +++ b/chromium/components/offline_pages/core/downloads/download_notifying_observer.cc @@ -67,9 +67,8 @@ void DownloadNotifyingObserver::OnChanged(const SavePageRequest& request) { void DownloadNotifyingObserver::OnNetworkProgress( const SavePageRequest& request, int64_t received_bytes) { - DownloadUIItem item(request); - item.download_progress_bytes = received_bytes; - notifier_->NotifyDownloadProgress(item); + // TODO(dimich): Enable this back in M59. See bug 704049 for more info and + // what was temporarily (for M58) reverted. } void DownloadNotifyingObserver::OnCompleted( diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver.cc b/chromium/components/password_manager/content/browser/content_password_manager_driver.cc index 0c26839db26..26695612a11 100644 --- a/chromium/components/password_manager/content/browser/content_password_manager_driver.cc +++ b/chromium/components/password_manager/content/browser/content_password_manager_driver.cc @@ -155,6 +155,11 @@ void ContentPasswordManagerDriver::AllowToRunFormClassifier() { GetPasswordGenerationAgent()->AllowToRunFormClassifier(); } +autofill::AutofillDriver* ContentPasswordManagerDriver::GetAutofillDriver() { + return autofill::ContentAutofillDriver::GetForRenderFrameHost( + render_frame_host_); +} + PasswordGenerationManager* ContentPasswordManagerDriver::GetPasswordGenerationManager() { return &password_generation_manager_; diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver.h b/chromium/components/password_manager/content/browser/content_password_manager_driver.h index eb6d2881dcf..a1c2168995b 100644 --- a/chromium/components/password_manager/content/browser/content_password_manager_driver.h +++ b/chromium/components/password_manager/content/browser/content_password_manager_driver.h @@ -77,6 +77,7 @@ class ContentPasswordManagerDriver void GeneratePassword() override; void SendLoggingAvailability() override; void AllowToRunFormClassifier() override; + autofill::AutofillDriver* GetAutofillDriver() override; PasswordGenerationManager* GetPasswordGenerationManager() override; PasswordManager* GetPasswordManager() override; diff --git a/chromium/components/password_manager/core/browser/password_autofill_manager.cc b/chromium/components/password_manager/core/browser/password_autofill_manager.cc index 091b2062c2e..a242d655fc0 100644 --- a/chromium/components/password_manager/core/browser/password_autofill_manager.cc +++ b/chromium/components/password_manager/core/browser/password_autofill_manager.cc @@ -17,7 +17,7 @@ #include "base/strings/string16.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" -#include "components/autofill/core/browser/autofill_driver.h" +#include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/autofill_experiments.h" #include "components/autofill/core/browser/popup_item_ids.h" #include "components/autofill/core/browser/suggestion.h" @@ -138,8 +138,7 @@ PasswordAutofillManager::PasswordAutofillManager( autofill::AutofillClient* autofill_client) : password_manager_driver_(password_manager_driver), autofill_client_(autofill_client), - weak_ptr_factory_(this) { -} + weak_ptr_factory_(this) {} PasswordAutofillManager::~PasswordAutofillManager() { } @@ -353,6 +352,10 @@ bool PasswordAutofillManager::IsCreditCardPopup() { return false; } +autofill::AutofillDriver* PasswordAutofillManager::GetAutofillDriver() { + return password_manager_driver_->GetAutofillDriver(); +} + //////////////////////////////////////////////////////////////////////////////// // PasswordAutofillManager, private: diff --git a/chromium/components/password_manager/core/browser/password_autofill_manager.h b/chromium/components/password_manager/core/browser/password_autofill_manager.h index 56a5b5c62ba..737bc926e3a 100644 --- a/chromium/components/password_manager/core/browser/password_autofill_manager.h +++ b/chromium/components/password_manager/core/browser/password_autofill_manager.h @@ -43,6 +43,7 @@ class PasswordAutofillManager : public autofill::AutofillPopupDelegate { bool RemoveSuggestion(const base::string16& value, int identifier) override; void ClearPreviewedForm() override; bool IsCreditCardPopup() override; + autofill::AutofillDriver* GetAutofillDriver() override; // Invoked when a password mapping is added. void OnAddPasswordFormMapping( diff --git a/chromium/components/password_manager/core/browser/password_manager_driver.h b/chromium/components/password_manager/core/browser/password_manager_driver.h index 8ec6b5e8261..028bf7273ac 100644 --- a/chromium/components/password_manager/core/browser/password_manager_driver.h +++ b/chromium/components/password_manager/core/browser/password_manager_driver.h @@ -14,6 +14,7 @@ #include "components/autofill/core/common/password_form_field_prediction_map.h" namespace autofill { +class AutofillDriver; struct FormData; struct PasswordForm; struct PasswordFormGenerationData; @@ -97,6 +98,9 @@ class PasswordManagerDriver // Allows the form classifier to find generation fields. virtual void AllowToRunFormClassifier() {} + // Return the associated AutofillDriver. + virtual autofill::AutofillDriver* GetAutofillDriver() = 0; + private: DISALLOW_COPY_AND_ASSIGN(PasswordManagerDriver); }; diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_driver.cc b/chromium/components/password_manager/core/browser/stub_password_manager_driver.cc index ba19e68c086..18b7dc56a7c 100644 --- a/chromium/components/password_manager/core/browser/stub_password_manager_driver.cc +++ b/chromium/components/password_manager/core/browser/stub_password_manager_driver.cc @@ -56,4 +56,8 @@ StubPasswordManagerDriver::GetPasswordAutofillManager() { return nullptr; } +autofill::AutofillDriver* StubPasswordManagerDriver::GetAutofillDriver() { + return nullptr; +} + } // namespace password_manager diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_driver.h b/chromium/components/password_manager/core/browser/stub_password_manager_driver.h index 88d1ff38b28..f7a1703d1d9 100644 --- a/chromium/components/password_manager/core/browser/stub_password_manager_driver.h +++ b/chromium/components/password_manager/core/browser/stub_password_manager_driver.h @@ -36,6 +36,7 @@ class StubPasswordManagerDriver : public PasswordManagerDriver { PasswordGenerationManager* GetPasswordGenerationManager() override; PasswordManager* GetPasswordManager() override; PasswordAutofillManager* GetPasswordAutofillManager() override; + autofill::AutofillDriver* GetAutofillDriver() override; private: DISALLOW_COPY_AND_ASSIGN(StubPasswordManagerDriver); diff --git a/chromium/components/ssl_errors/error_classification.cc b/chromium/components/ssl_errors/error_classification.cc index 572b5729528..52827fe1565 100644 --- a/chromium/components/ssl_errors/error_classification.cc +++ b/chromium/components/ssl_errors/error_classification.cc @@ -38,32 +38,13 @@ using base::TimeDelta; namespace ssl_errors { namespace { -// Events for UMA. Do not reorder or change! -enum SSLInterstitialCause { - CLOCK_PAST, - CLOCK_FUTURE, - WWW_SUBDOMAIN_MATCH, - SUBDOMAIN_MATCH, - SUBDOMAIN_INVERSE_MATCH, - SUBDOMAIN_OUTSIDE_WILDCARD, - HOST_NAME_NOT_KNOWN_TLD, - LIKELY_MULTI_TENANT_HOSTING, - LOCALHOST, - PRIVATE_URL, - AUTHORITY_ERROR_CAPTIVE_PORTAL, // Deprecated in M47. - SELF_SIGNED, - EXPIRED_RECENTLY, - LIKELY_SAME_DOMAIN, - UNUSED_INTERSTITIAL_CAUSE_ENTRY, -}; - void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) { if (overridable) { UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.overridable", event, - UNUSED_INTERSTITIAL_CAUSE_ENTRY); + SSL_INTERSTITIAL_CAUSE_MAX); } else { UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.nonoverridable", event, - UNUSED_INTERSTITIAL_CAUSE_ENTRY); + SSL_INTERSTITIAL_CAUSE_MAX); } } @@ -109,7 +90,7 @@ bool IsWWWSubDomainMatch(const GURL& request_url, const net::X509Certificate& cert) { std::string www_host; std::vector<std::string> dns_names; - cert.GetDNSNames(&dns_names); + cert.GetSubjectAltName(&dns_names, nullptr); return GetWWWSubDomainMatch(request_url, dns_names, &www_host); } @@ -148,24 +129,28 @@ void RecordUMAStatistics(bool overridable, } case ssl_errors::ErrorInfo::CERT_COMMON_NAME_INVALID: { std::string host_name = request_url.host(); + std::vector<std::string> dns_names; + cert.GetSubjectAltName(&dns_names, nullptr); + std::vector<HostnameTokens> dns_name_tokens = + GetTokenizedDNSNames(dns_names); + + if (dns_names.empty()) + RecordSSLInterstitialCause(overridable, NO_SUBJECT_ALT_NAME); + if (HostNameHasKnownTLD(host_name)) { HostnameTokens host_name_tokens = Tokenize(host_name); if (IsWWWSubDomainMatch(request_url, cert)) - RecordSSLInterstitialCause(overridable, WWW_SUBDOMAIN_MATCH); + RecordSSLInterstitialCause(overridable, WWW_SUBDOMAIN_MATCH2); if (IsSubDomainOutsideWildcard(request_url, cert)) - RecordSSLInterstitialCause(overridable, SUBDOMAIN_OUTSIDE_WILDCARD); - std::vector<std::string> dns_names; - cert.GetDNSNames(&dns_names); - std::vector<HostnameTokens> dns_name_tokens = - GetTokenizedDNSNames(dns_names); + RecordSSLInterstitialCause(overridable, SUBDOMAIN_OUTSIDE_WILDCARD2); if (NameUnderAnyNames(host_name_tokens, dns_name_tokens)) - RecordSSLInterstitialCause(overridable, SUBDOMAIN_MATCH); + RecordSSLInterstitialCause(overridable, SUBDOMAIN_MATCH2); if (AnyNamesUnderName(dns_name_tokens, host_name_tokens)) - RecordSSLInterstitialCause(overridable, SUBDOMAIN_INVERSE_MATCH); + RecordSSLInterstitialCause(overridable, SUBDOMAIN_INVERSE_MATCH2); if (IsCertLikelyFromMultiTenantHosting(request_url, cert)) - RecordSSLInterstitialCause(overridable, LIKELY_MULTI_TENANT_HOSTING); + RecordSSLInterstitialCause(overridable, LIKELY_MULTI_TENANT_HOSTING2); if (IsCertLikelyFromSameDomain(request_url, cert)) - RecordSSLInterstitialCause(overridable, LIKELY_SAME_DOMAIN); + RecordSSLInterstitialCause(overridable, LIKELY_SAME_DOMAIN2); } else { RecordSSLInterstitialCause(overridable, HOST_NAME_NOT_KNOWN_TLD); } @@ -382,7 +367,7 @@ bool IsSubDomainOutsideWildcard(const GURL& request_url, std::string host_name = request_url.host(); HostnameTokens host_name_tokens = Tokenize(host_name); std::vector<std::string> dns_names; - cert.GetDNSNames(&dns_names); + cert.GetSubjectAltName(&dns_names, nullptr); bool result = false; // This method requires that the host name be longer than the dns name on @@ -410,7 +395,7 @@ bool IsCertLikelyFromMultiTenantHosting(const GURL& request_url, std::string host_name = request_url.host(); std::vector<std::string> dns_names; std::vector<std::string> dns_names_domain; - cert.GetDNSNames(&dns_names); + cert.GetSubjectAltName(&dns_names, nullptr); size_t dns_names_size = dns_names.size(); // If there is only 1 DNS name then it is definitely not a shared certificate. @@ -457,7 +442,9 @@ bool IsCertLikelyFromSameDomain(const GURL& request_url, const net::X509Certificate& cert) { std::string host_name = request_url.host(); std::vector<std::string> dns_names; - cert.GetDNSNames(&dns_names); + cert.GetSubjectAltName(&dns_names, nullptr); + if (dns_names.empty()) + return false; dns_names.push_back(host_name); std::vector<std::string> dns_names_domain; diff --git a/chromium/components/ssl_errors/error_classification.h b/chromium/components/ssl_errors/error_classification.h index b8c472df669..0dea46560cc 100644 --- a/chromium/components/ssl_errors/error_classification.h +++ b/chromium/components/ssl_errors/error_classification.h @@ -28,6 +28,33 @@ typedef std::vector<std::string> HostnameTokens; // Methods for identifying specific error causes. ------------------------------ +// These values are written to logs. New enum values can be added, but existing +// enums must never be renumbered or deleted and reused. +enum SSLInterstitialCause { + CLOCK_PAST = 0, + CLOCK_FUTURE = 1, + WWW_SUBDOMAIN_MATCH = 2, // Deprecated in M59. + SUBDOMAIN_MATCH = 3, // Deprecated in M59. + SUBDOMAIN_INVERSE_MATCH = 4, // Deprecated in M59. + SUBDOMAIN_OUTSIDE_WILDCARD = 5, // Deprecated in M59. + HOST_NAME_NOT_KNOWN_TLD = 6, + LIKELY_MULTI_TENANT_HOSTING = 7, // Deprecated in M59. + LOCALHOST = 8, + PRIVATE_URL = 9, + AUTHORITY_ERROR_CAPTIVE_PORTAL = 10, // Deprecated in M47. + SELF_SIGNED = 11, + EXPIRED_RECENTLY = 12, + LIKELY_SAME_DOMAIN = 13, // Deprecated in M59. + NO_SUBJECT_ALT_NAME = 14, + WWW_SUBDOMAIN_MATCH2 = 15, + SUBDOMAIN_MATCH2 = 16, + SUBDOMAIN_INVERSE_MATCH2 = 17, + SUBDOMAIN_OUTSIDE_WILDCARD2 = 18, + LIKELY_MULTI_TENANT_HOSTING2 = 19, + LIKELY_SAME_DOMAIN2 = 20, + SSL_INTERSTITIAL_CAUSE_MAX +}; + // What is known about the accuracy of system clock. Do not change or // reorder; these values are used in an UMA histogram. enum ClockState { @@ -110,14 +137,9 @@ bool IsCertLikelyFromMultiTenantHosting(const GURL& request_url, bool IsCertLikelyFromSameDomain(const GURL& request_url, const net::X509Certificate& cert); -// Returns true if the site's hostname differs from one of the DNS -// names in the certificate (CN or SANs) only by the presence or -// absence of the single-label prefix "www". E.g.: (The first domain -// is hostname and the second domain is a DNS name in the certificate) -// www.example.com ~ example.com -> true -// example.com ~ www.example.com -> true -// www.food.example.com ~ example.com -> false -// mail.example.com ~ example.com -> false +// Returns true if the site's hostname differs from one of the DNS names in +// |dns_names| only by the presence or absence of the single-label prefix "www". +// The matching name from the certificate is returned in |www_match_host_name|. bool GetWWWSubDomainMatch(const GURL& request_url, const std::vector<std::string>& dns_names, std::string* www_match_host_name); diff --git a/chromium/components/ssl_errors/error_classification_unittest.cc b/chromium/components/ssl_errors/error_classification_unittest.cc index 1099181a6f4..c4c2c45e9ef 100644 --- a/chromium/components/ssl_errors/error_classification_unittest.cc +++ b/chromium/components/ssl_errors/error_classification_unittest.cc @@ -26,11 +26,15 @@ #include "net/test/test_certificate_data.h" #include "net/test/test_data_directory.h" #include "net/url_request/url_request_test_util.h" +#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" +using testing::ElementsAre; + namespace { const char kNetworkTimeHistogram[] = "interstitial.ssl.clockstate.network3"; +const char kSslErrorCauseHistogram[] = "interstitial.ssl.cause.overridable"; static std::unique_ptr<net::test_server::HttpResponse> NetworkErrorResponseHandler(const net::test_server::HttpRequest& request) { @@ -53,112 +57,132 @@ class SSLErrorClassificationTest : public ::testing::Test { }; TEST_F(SSLErrorClassificationTest, TestNameMismatch) { - scoped_refptr<net::X509Certificate> google_cert( - net::X509Certificate::CreateFromBytes( - reinterpret_cast<const char*>(google_der), sizeof(google_der))); - ASSERT_TRUE(google_cert.get()); - std::vector<std::string> dns_names_google; - google_cert->GetDNSNames(&dns_names_google); - ASSERT_EQ(1u, dns_names_google.size()); // ["www.google.com"] - std::vector<std::string> hostname_tokens_google = - ssl_errors::Tokenize(dns_names_google[0]); - ASSERT_EQ(3u, hostname_tokens_google.size()); // ["www","google","com"] - std::vector<std::vector<std::string>> dns_name_tokens_google; - dns_name_tokens_google.push_back(hostname_tokens_google); - ASSERT_EQ(1u, dns_name_tokens_google.size()); // [["www","google","com"]] + scoped_refptr<net::X509Certificate> example_cert = net::ImportCertFromFile( + net::GetTestCertsDirectory(), "subjectAltName_www_example_com.pem"); + ASSERT_TRUE(example_cert); + std::vector<std::string> dns_names_example; + example_cert->GetSubjectAltName(&dns_names_example, nullptr); + ASSERT_THAT(dns_names_example, ElementsAre("www.example.com")); + std::vector<std::string> hostname_tokens_example = + ssl_errors::Tokenize(dns_names_example[0]); + ASSERT_THAT(hostname_tokens_example, ElementsAre("www", "example", "com")); + std::vector<std::vector<std::string>> dns_name_tokens_example; + dns_name_tokens_example.push_back(hostname_tokens_example); + ASSERT_EQ(1u, dns_name_tokens_example.size()); // [["www","example","com"]] + ASSERT_THAT(dns_name_tokens_example[0], ElementsAre("www", "example", "com")); { - GURL origin("https://google.com"); + GURL origin("https://example.com"); std::string www_host; std::vector<std::string> host_name_tokens = base::SplitString( origin.host(), ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); EXPECT_TRUE( - ssl_errors::GetWWWSubDomainMatch(origin, dns_names_google, &www_host)); - EXPECT_EQ("www.google.com", www_host); + ssl_errors::GetWWWSubDomainMatch(origin, dns_names_example, &www_host)); + EXPECT_EQ("www.example.com", www_host); EXPECT_FALSE(ssl_errors::NameUnderAnyNames(host_name_tokens, - dns_name_tokens_google)); - EXPECT_FALSE(ssl_errors::AnyNamesUnderName(dns_name_tokens_google, + dns_name_tokens_example)); + EXPECT_FALSE(ssl_errors::AnyNamesUnderName(dns_name_tokens_example, host_name_tokens)); - EXPECT_FALSE(ssl_errors::IsSubDomainOutsideWildcard(origin, *google_cert)); + EXPECT_FALSE(ssl_errors::IsSubDomainOutsideWildcard(origin, *example_cert)); EXPECT_FALSE( - ssl_errors::IsCertLikelyFromMultiTenantHosting(origin, *google_cert)); - EXPECT_TRUE(ssl_errors::IsCertLikelyFromSameDomain(origin, *google_cert)); + ssl_errors::IsCertLikelyFromMultiTenantHosting(origin, *example_cert)); + EXPECT_TRUE(ssl_errors::IsCertLikelyFromSameDomain(origin, *example_cert)); } { - GURL origin("https://foo.blah.google.com"); + GURL origin("https://foo.blah.example.com"); std::string www_host; std::vector<std::string> host_name_tokens = base::SplitString( origin.host(), ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); EXPECT_FALSE( - ssl_errors::GetWWWSubDomainMatch(origin, dns_names_google, &www_host)); + ssl_errors::GetWWWSubDomainMatch(origin, dns_names_example, &www_host)); EXPECT_FALSE(ssl_errors::NameUnderAnyNames(host_name_tokens, - dns_name_tokens_google)); - EXPECT_FALSE(ssl_errors::AnyNamesUnderName(dns_name_tokens_google, + dns_name_tokens_example)); + EXPECT_FALSE(ssl_errors::AnyNamesUnderName(dns_name_tokens_example, host_name_tokens)); - EXPECT_TRUE(ssl_errors::IsCertLikelyFromSameDomain(origin, *google_cert)); + EXPECT_TRUE(ssl_errors::IsCertLikelyFromSameDomain(origin, *example_cert)); } { - GURL origin("https://foo.www.google.com"); + GURL origin("https://foo.www.example.com"); std::string www_host; std::vector<std::string> host_name_tokens = base::SplitString( origin.host(), ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); EXPECT_FALSE( - ssl_errors::GetWWWSubDomainMatch(origin, dns_names_google, &www_host)); + ssl_errors::GetWWWSubDomainMatch(origin, dns_names_example, &www_host)); EXPECT_TRUE(ssl_errors::NameUnderAnyNames(host_name_tokens, - dns_name_tokens_google)); - EXPECT_FALSE(ssl_errors::AnyNamesUnderName(dns_name_tokens_google, + dns_name_tokens_example)); + EXPECT_FALSE(ssl_errors::AnyNamesUnderName(dns_name_tokens_example, host_name_tokens)); - EXPECT_TRUE(ssl_errors::IsCertLikelyFromSameDomain(origin, *google_cert)); + EXPECT_TRUE(ssl_errors::IsCertLikelyFromSameDomain(origin, *example_cert)); } { - GURL origin("https://www.google.com.foo"); + GURL origin("https://www.example.com.foo"); std::string www_host; std::vector<std::string> host_name_tokens = base::SplitString( origin.host(), ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); EXPECT_FALSE( - ssl_errors::GetWWWSubDomainMatch(origin, dns_names_google, &www_host)); + ssl_errors::GetWWWSubDomainMatch(origin, dns_names_example, &www_host)); EXPECT_FALSE(ssl_errors::NameUnderAnyNames(host_name_tokens, - dns_name_tokens_google)); - EXPECT_FALSE(ssl_errors::AnyNamesUnderName(dns_name_tokens_google, + dns_name_tokens_example)); + EXPECT_FALSE(ssl_errors::AnyNamesUnderName(dns_name_tokens_example, host_name_tokens)); - EXPECT_FALSE(ssl_errors::IsCertLikelyFromSameDomain(origin, *google_cert)); + EXPECT_FALSE(ssl_errors::IsCertLikelyFromSameDomain(origin, *example_cert)); } { - GURL origin("https://www.foogoogle.com."); + GURL origin("https://www.fooexample.com."); std::string www_host; std::vector<std::string> host_name_tokens = base::SplitString( origin.host(), ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); EXPECT_FALSE( - ssl_errors::GetWWWSubDomainMatch(origin, dns_names_google, &www_host)); + ssl_errors::GetWWWSubDomainMatch(origin, dns_names_example, &www_host)); EXPECT_FALSE(ssl_errors::NameUnderAnyNames(host_name_tokens, - dns_name_tokens_google)); - EXPECT_FALSE(ssl_errors::AnyNamesUnderName(dns_name_tokens_google, + dns_name_tokens_example)); + EXPECT_FALSE(ssl_errors::AnyNamesUnderName(dns_name_tokens_example, host_name_tokens)); - EXPECT_FALSE(ssl_errors::IsCertLikelyFromSameDomain(origin, *google_cert)); + EXPECT_FALSE(ssl_errors::IsCertLikelyFromSameDomain(origin, *example_cert)); + } + + // Ensure that a certificate with no SubjectAltName does not fall back to + // the Subject CN when evaluating hostnames. + { + scoped_refptr<net::X509Certificate> google_cert( + net::X509Certificate::CreateFromBytes( + reinterpret_cast<const char*>(google_der), sizeof(google_der))); + ASSERT_TRUE(google_cert); + + GURL origin("https://google.com"); + + base::HistogramTester histograms; + ssl_errors::RecordUMAStatistics(true, base::Time::NowFromSystemTime(), + origin, net::ERR_CERT_COMMON_NAME_INVALID, + *google_cert); + + // Verify that we recorded only NO_SUBJECT_ALT_NAME and no other causes. + histograms.ExpectUniqueSample(kSslErrorCauseHistogram, + ssl_errors::NO_SUBJECT_ALT_NAME, 1); } - scoped_refptr<net::X509Certificate> webkit_cert( - net::X509Certificate::CreateFromBytes( - reinterpret_cast<const char*>(webkit_der), sizeof(webkit_der))); - ASSERT_TRUE(webkit_cert.get()); - std::vector<std::string> dns_names_webkit; - webkit_cert->GetDNSNames(&dns_names_webkit); - ASSERT_EQ(2u, dns_names_webkit.size()); // ["*.webkit.org", "webkit.org"] - std::vector<std::string> hostname_tokens_webkit_0 = - ssl_errors::Tokenize(dns_names_webkit[0]); - ASSERT_EQ(3u, hostname_tokens_webkit_0.size()); // ["*", "webkit","org"] - std::vector<std::string> hostname_tokens_webkit_1 = - ssl_errors::Tokenize(dns_names_webkit[1]); - ASSERT_EQ(2u, hostname_tokens_webkit_1.size()); // ["webkit","org"] - std::vector<std::vector<std::string>> dns_name_tokens_webkit; - dns_name_tokens_webkit.push_back(hostname_tokens_webkit_0); - dns_name_tokens_webkit.push_back(hostname_tokens_webkit_1); - ASSERT_EQ(2u, dns_name_tokens_webkit.size()); { + scoped_refptr<net::X509Certificate> webkit_cert( + net::X509Certificate::CreateFromBytes( + reinterpret_cast<const char*>(webkit_der), sizeof(webkit_der))); + ASSERT_TRUE(webkit_cert); + std::vector<std::string> dns_names_webkit; + webkit_cert->GetSubjectAltName(&dns_names_webkit, nullptr); + ASSERT_THAT(dns_names_webkit, ElementsAre("*.webkit.org", "webkit.org")); + std::vector<std::string> hostname_tokens_webkit_0 = + ssl_errors::Tokenize(dns_names_webkit[0]); + ASSERT_THAT(hostname_tokens_webkit_0, ElementsAre("*", "webkit", "org")); + std::vector<std::string> hostname_tokens_webkit_1 = + ssl_errors::Tokenize(dns_names_webkit[1]); + ASSERT_THAT(hostname_tokens_webkit_1, ElementsAre("webkit", "org")); + std::vector<std::vector<std::string>> dns_name_tokens_webkit; + dns_name_tokens_webkit.push_back(hostname_tokens_webkit_0); + dns_name_tokens_webkit.push_back(hostname_tokens_webkit_1); + ASSERT_EQ(2u, dns_name_tokens_webkit.size()); GURL origin("https://a.b.webkit.org"); std::string www_host; std::vector<std::string> host_name_tokens = base::SplitString( diff --git a/chromium/components/ssl_errors/error_info.cc b/chromium/components/ssl_errors/error_info.cc index 7ef291ebe4b..ab7afccb05c 100644 --- a/chromium/components/ssl_errors/error_info.cc +++ b/chromium/components/ssl_errors/error_info.cc @@ -32,22 +32,30 @@ ErrorInfo ErrorInfo::CreateError(ErrorType error_type, base::string16 details, short_description; switch (error_type) { case CERT_COMMON_NAME_INVALID: { - // If the certificate contains multiple DNS names, we choose the most - // representative one -- either the DNS name that's also in the subject - // field, or the first one. If this heuristic turns out to be - // inadequate, we can consider choosing the DNS name that is the - // "closest match" to the host name in the request URL, or listing all - // the DNS names with an HTML <ul>. std::vector<std::string> dns_names; - cert->GetDNSNames(&dns_names); - DCHECK(!dns_names.empty()); + cert->GetSubjectAltName(&dns_names, nullptr); + size_t i = 0; - for (; i < dns_names.size(); ++i) { - if (dns_names[i] == cert->subject().common_name) - break; + if (dns_names.empty()) { + // The certificate had no DNS names, display an explanatory string. + // TODO(elawrence): Change the error messsage instead of just the + // placeholder string; see https://crbug.com/708268 + dns_names.push_back("[missing_subjectAltName]"); + } else { + // If the certificate contains multiple DNS names, we choose the most + // representative one -- either the DNS name that's also in the subject + // field, or the first one. If this heuristic turns out to be + // inadequate, we can consider choosing the DNS name that is the + // "closest match" to the host name in the request URL, or listing all + // the DNS names with an HTML <ul>. + for (; i < dns_names.size(); ++i) { + if (dns_names[i] == cert->subject().common_name) + break; + } + if (i == dns_names.size()) + i = 0; } - if (i == dns_names.size()) - i = 0; + details = l10n_util::GetStringFUTF16( IDS_CERT_ERROR_COMMON_NAME_INVALID_DETAILS, UTF8ToUTF16(request_url.host()), diff --git a/chromium/components/strings/components_strings_es.xtb b/chromium/components/strings/components_strings_es.xtb index 2096a445d92..262ea2fa385 100644 --- a/chromium/components/strings/components_strings_es.xtb +++ b/chromium/components/strings/components_strings_es.xtb @@ -89,7 +89,7 @@ <translation id="1787142507584202372">Las pestañas abiertas aparecen aquí</translation> <translation id="1791429645902722292">Google Smart Lock</translation> <translation id="1797835274315207060">Selecciona una dirección de envío para consultar los métodos de envío y los requisitos.</translation> -<translation id="1803678881841855883">La función de navegación segura de Google <ph name="BEGIN_LINK" />detectó software malicioso<ph name="END_LINK" /> recientemente en <ph name="SITE" />. En ocasiones, los sitios web que suelen ser seguros contienen software malicioso. Este contenido procede de <ph name="SUBRESOURCE_HOST" />, un conocido distribuidor de este tipo de software. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation> +<translation id="1803678881841855883">La función de Navegación Segura de Google <ph name="BEGIN_LINK" />detectó software malicioso<ph name="END_LINK" /> recientemente en <ph name="SITE" />. En ocasiones, los sitios web que suelen ser seguros contienen software malicioso. Este contenido procede de <ph name="SUBRESOURCE_HOST" />, un conocido distribuidor de este tipo de software. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation> <translation id="1806541873155184440">Añadida el <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation> <translation id="1821930232296380041">Parámetros de solicitud o solicitud no válidos</translation> <translation id="1826516787628120939">Comprobando</translation> @@ -157,7 +157,7 @@ <translation id="2386255080630008482">Se ha revocado el certificado de servidor.</translation> <translation id="2392959068659972793">Mostrar políticas sin valores establecidos</translation> <translation id="2396249848217231973">&Deshacer eliminación</translation> -<translation id="2460160116472764928">La función de navegación segura de Google <ph name="BEGIN_LINK" />detectó software malicioso<ph name="END_LINK" /> recientemente en <ph name="SITE" />. En ocasiones, los sitios web que suelen ser seguros contienen software malicioso. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation> +<translation id="2460160116472764928">La función de Navegación Segura de Google <ph name="BEGIN_LINK" />detectó software malicioso<ph name="END_LINK" /> recientemente en <ph name="SITE" />. En ocasiones, los sitios web que suelen ser seguros contienen software malicioso. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation> <translation id="2463739503403862330">Rellenar</translation> <translation id="2467694685043708798"><ph name="BEGIN_LINK" />Ejecutar Diagnósticos de red<ph name="END_LINK" /></translation> <translation id="2479410451996844060">La URL de búsqueda no es válida.</translation> @@ -369,7 +369,7 @@ <translation id="4269787794583293679">(Ningún nombre de usuario)</translation> <translation id="4275830172053184480">Reiniciar tu dispositivo</translation> <translation id="4280429058323657511">Vcto. <ph name="EXPIRATION_DATE_ABBR" /></translation> -<translation id="4295944351946828969">La función de navegación segura de Google <ph name="BEGIN_LINK" />encontró programas dañinos<ph name="END_LINK" /> recientemente en <ph name="SITE" />. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation> +<translation id="4295944351946828969">La función de Navegación Segura de Google <ph name="BEGIN_LINK" />encontró programas dañinos<ph name="END_LINK" /> recientemente en <ph name="SITE" />. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation> <translation id="4300246636397505754">Sugerencias de padres</translation> <translation id="4304224509867189079">Iniciar sesión</translation> <translation id="432290197980158659">El servidor ha mostrado un certificado que no coincide con lo que se esperaba. Algunos sitios web tienen un alto nivel de seguridad para garantizar tu protección y esperan ciertas características de los certificados. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation> @@ -745,7 +745,7 @@ <translation id="800218591365569300">Prueba a cerrar otros programas o pestañas para liberar memoria.</translation> <translation id="8012647001091218357">No hemos podido contactar con tus padres. Vuelve a intentarlo.</translation> <translation id="8025119109950072390">Es posible que los atacantes que se encuentren en este sitio web intenten engañarte para que realices una acción peligrosa, como instalar software o revelar tu información personal (por ejemplo, contraseñas, números de teléfono o tarjetas de crédito).</translation> -<translation id="803030522067524905">La función de navegación segura de Google detectó phishing recientemente en <ph name="SITE" />. Los sitios web de phishing imitan el aspecto de otros sitios web para engañarte. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation> +<translation id="803030522067524905">La función de Navegación Segura de Google detectó phishing recientemente en <ph name="SITE" />. Los sitios web de phishing imitan el aspecto de otros sitios web para engañarte. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation> <translation id="8034522405403831421">Esta página está escrita en <ph name="SOURCE_LANGUAGE" />. ¿Quieres traducirla al <ph name="TARGET_LANGUAGE" />?</translation> <translation id="8041089156583427627">Enviar</translation> <translation id="8088680233425245692">Se ha producido un error al ver el artículo.</translation> diff --git a/chromium/components/url_formatter/url_formatter.cc b/chromium/components/url_formatter/url_formatter.cc index a93bf1154c3..3d5740fd377 100644 --- a/chromium/components/url_formatter/url_formatter.cc +++ b/chromium/components/url_formatter/url_formatter.cc @@ -15,6 +15,7 @@ #include "base/strings/utf_offset_string_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/thread_local_storage.h" +#include "third_party/icu/source/common/unicode/schriter.h" #include "third_party/icu/source/common/unicode/uidna.h" #include "third_party/icu/source/common/unicode/uniset.h" #include "third_party/icu/source/common/unicode/uscript.h" @@ -33,6 +34,7 @@ base::string16 IDNToUnicodeWithAdjustments( base::OffsetAdjuster::Adjustments* adjustments); bool IDNToUnicodeOneComponent(const base::char16* comp, size_t comp_len, + bool is_tld_ascii, base::string16* out); class AppendComponentTransform { @@ -200,6 +202,13 @@ base::string16 IDNToUnicodeWithAdjustments( input16.reserve(host.length()); input16.insert(input16.end(), host.begin(), host.end()); + bool is_tld_ascii = true; + size_t last_dot = host.rfind('.'); + if (last_dot != base::StringPiece::npos && + host.substr(last_dot).starts_with(".xn--")) { + is_tld_ascii = false; + } + // Do each component of the host separately, since we enforce script matching // on a per-component basis. base::string16 out16; @@ -217,7 +226,7 @@ base::string16 IDNToUnicodeWithAdjustments( // Add the substring that we just found. converted_idn = IDNToUnicodeOneComponent(input16.data() + component_start, - component_length, &out16); + component_length, is_tld_ascii, &out16); } size_t new_component_length = out16.length() - new_component_start; @@ -241,17 +250,22 @@ class IDNSpoofChecker { public: IDNSpoofChecker(); - // Returns true if |label| is safe to display as Unicode. In the event of - // library failure, all IDN inputs will be treated as unsafe. - bool Check(base::StringPiece16 label); + // Returns true if |label| is safe to display as Unicode. When the TLD is + // ASCII, check if a label is entirely made of Cyrillic letters that look like + // Latin letters. In the event of library failure, all IDN inputs will be + // treated as unsafe. + bool Check(base::StringPiece16 label, bool is_tld_ascii); private: void SetAllowedUnicodeSet(UErrorCode* status); + bool IsMadeOfLatinAlikeCyrillic(const icu::UnicodeString& label_string); USpoofChecker* checker_; icu::UnicodeSet deviation_characters_; icu::UnicodeSet non_ascii_latin_letters_; icu::UnicodeSet kana_letters_exceptions_; + icu::UnicodeSet cyrillic_letters_; + icu::UnicodeSet cyrillic_letters_latin_alike_; DISALLOW_COPY_AND_ASSIGN(IDNSpoofChecker); }; @@ -314,10 +328,20 @@ IDNSpoofChecker::IDNSpoofChecker() { "[\\u3078-\\u307a\\u30d8-\\u30da\\u30fb\\u30fc]"), status); kana_letters_exceptions_.freeze(); + // These Cyrillic letters look like Latin. A domain label entirely made of + // these letters is blocked as a simpliified whole-script-spoofable. + cyrillic_letters_latin_alike_ = + icu::UnicodeSet(icu::UnicodeString("[асԁеһіјӏорԛѕԝхуъЬҽпгѵѡ]"), status); + cyrillic_letters_latin_alike_.freeze(); + + cyrillic_letters_ = + icu::UnicodeSet(UNICODE_STRING_SIMPLE("[[:Cyrl:]]"), status); + cyrillic_letters_.freeze(); + DCHECK(U_SUCCESS(status)); } -bool IDNSpoofChecker::Check(base::StringPiece16 label) { +bool IDNSpoofChecker::Check(base::StringPiece16 label, bool is_tld_ascii) { UErrorCode status = U_ZERO_ERROR; int32_t result = uspoof_check(checker_, label.data(), base::checked_cast<int32_t>(label.size()), @@ -345,17 +369,19 @@ bool IDNSpoofChecker::Check(base::StringPiece16 label) { return false; // If there's no script mixing, the input is regarded as safe without any - // extra check unless it contains Kana letter exceptions. Note that - // the following combinations of scripts are treated as a 'logical' single - // script. + // extra check unless it contains Kana letter exceptions or it's made entirely + // of Cyrillic letters that look like Latin letters. Note that the following + // combinations of scripts are treated as a 'logical' single script. // - Chinese: Han, Bopomofo, Common // - Japanese: Han, Hiragana, Katakana, Common // - Korean: Hangul, Han, Common result &= USPOOF_RESTRICTION_LEVEL_MASK; - if (result == USPOOF_ASCII || - (result == USPOOF_SINGLE_SCRIPT_RESTRICTIVE && - kana_letters_exceptions_.containsNone(label_string))) - return true; + if (result == USPOOF_ASCII) return true; + if (result == USPOOF_SINGLE_SCRIPT_RESTRICTIVE && + kana_letters_exceptions_.containsNone(label_string)) { + // Check Cyrillic confusable only for ASCII TLDs. + return !is_tld_ascii || !IsMadeOfLatinAlikeCyrillic(label_string); + } // Additional checks for |label| with multiple scripts, one of which is Latin. // Disallow non-ASCII Latin letters to mix with a non-Latin script. @@ -407,6 +433,25 @@ bool IDNSpoofChecker::Check(base::StringPiece16 label) { return !dangerous_pattern->find(); } +bool IDNSpoofChecker::IsMadeOfLatinAlikeCyrillic( + const icu::UnicodeString& label_string) { + // Collect all the Cyrillic letters in |label_string| and see if they're + // a subset of |cyrillic_letters_latin_alike_|. + // A shortcut of defining cyrillic_letters_latin_alike_ to include [0-9] and + // [_-] and checking if the set contains all letters of |label_string| + // would work in most cases, but not if a label has non-letters outside + // ASCII. + icu::UnicodeSet cyrillic_in_label; + icu::StringCharacterIterator it(label_string); + for (it.setToStart(); it.hasNext();) { + const UChar32 c = it.next32PostInc(); + if (cyrillic_letters_.contains(c)) + cyrillic_in_label.add(c); + } + return !cyrillic_in_label.isEmpty() && + cyrillic_letters_latin_alike_.containsAll(cyrillic_in_label); +} + void IDNSpoofChecker::SetAllowedUnicodeSet(UErrorCode* status) { if (U_FAILURE(*status)) return; @@ -481,8 +526,8 @@ void IDNSpoofChecker::SetAllowedUnicodeSet(UErrorCode* status) { // user. Note that this function does not deal with pure ASCII domain labels at // all even though it's possible to make up look-alike labels with ASCII // characters alone. -bool IsIDNComponentSafe(base::StringPiece16 label) { - return g_idn_spoof_checker.Get().Check(label); +bool IsIDNComponentSafe(base::StringPiece16 label, bool is_tld_ascii) { + return g_idn_spoof_checker.Get().Check(label, is_tld_ascii); } // A wrapper to use LazyInstance<>::Leaky with ICU's UIDNA, a C pointer to @@ -527,6 +572,7 @@ base::LazyInstance<UIDNAWrapper>::Leaky g_uidna = LAZY_INSTANCE_INITIALIZER; // Returns whether any conversion was performed. bool IDNToUnicodeOneComponent(const base::char16* comp, size_t comp_len, + bool is_tld_ascii, base::string16* out) { DCHECK(out); if (comp_len == 0) @@ -558,8 +604,9 @@ bool IDNToUnicodeOneComponent(const base::char16* comp, // can be safely displayed to the user. out->resize(original_length + output_length); if (IsIDNComponentSafe( - base::StringPiece16(out->data() + original_length, - base::checked_cast<size_t>(output_length)))) + base::StringPiece16(out->data() + original_length, + base::checked_cast<size_t>(output_length)), + is_tld_ascii)) return true; } diff --git a/chromium/components/url_formatter/url_formatter_unittest.cc b/chromium/components/url_formatter/url_formatter_unittest.cc index c0fe9509a6d..5b2646ce09c 100644 --- a/chromium/components/url_formatter/url_formatter_unittest.cc +++ b/chromium/components/url_formatter/url_formatter_unittest.cc @@ -32,6 +32,7 @@ struct IDNTestCase { const bool unicode_allowed; }; +// TODO(jshin): Replace L"..." with "..." in UTF-8 when it's easier to read. const IDNTestCase idn_cases[] = { // No IDN {"www.google.com", L"www.google.com", true}, @@ -209,6 +210,35 @@ const IDNTestCase idn_cases[] = { // U+30FB + Latin {"xn--abc-os4b.jp", L"\x30fb" L"abc.jp", false}, + // Cyrillic labels made of Latin-look-alike Cyrillic letters. + // ѕсоре.com with ѕсоре in Cyrillic + {"xn--e1argc3h.com", L"\x0455\x0441\x043e\x0440\x0435.com", false}, + // ѕсоре123.com with ѕсоре in Cyrillic. + {"xn--123-qdd8bmf3n.com", + L"\x0455\x0441\x043e\x0440\x0435" L"123.com", false}, + // ѕсоре-рау.com with ѕсоре and рау in Cyrillic. + {"xn----8sbn9akccw8m.com", + L"\x0455\x0441\x043e\x0440\x0435-\x0440\x0430\x0443.com", false}, + // ѕсоре·рау.com with scope and pay in Cyrillic and U+00B7 between them. + {"xn--uba29ona9akccw8m.com", + L"\x0455\x0441\x043e\x0440\x0435\u00b7\x0440\x0430\x0443.com", false}, + + // The same as above three, but in IDN TLD. + {"xn--e1argc3h.xn--p1ai", + L"\x0455\x0441\x043e\x0440\x0435.\x0440\x0444", true}, + {"xn--123-qdd8bmf3n.xn--p1ai", + L"\x0455\x0441\x043e\x0440\x0435" L"123.\x0440\x0444", true}, + {"xn--uba29ona9akccw8m.xn--p1ai", + L"\x0455\x0441\x043e\x0440\x0435\u00b7\x0440\x0430\x0443.\x0440\x0444", + true}, + + // ѕсоре-рау.한국 with ѕсоре and рау in Cyrillic. + {"xn----8sbn9akccw8m.xn--3e0b707e", + L"\x0455\x0441\x043e\x0440\x0435-\x0440\x0430\x0443.\xd55c\xad6d", true}, + + // музей (museum in Russian) has characters without a Latin-look-alike. + {"xn--e1adhj9a.com", L"\x043c\x0443\x0437\x0435\x0439.com", true}, + // Mixed digits: the first two will also fail mixed script test // Latin + ASCII digit + Deva digit {"xn--asc1deva-j0q.co.in", L"asc1deva\x0967.co.in", false}, diff --git a/chromium/components/user_manager/user_manager_base.cc b/chromium/components/user_manager/user_manager_base.cc index 054949fff92..5805a9ca35b 100644 --- a/chromium/components/user_manager/user_manager_base.cc +++ b/chromium/components/user_manager/user_manager_base.cc @@ -242,6 +242,7 @@ void UserManagerBase::SwitchActiveUser(const AccountId& account_id) { NotifyActiveUserHashChanged(active_user_->username_hash()); NotifyActiveUserChanged(active_user_); + CallUpdateLoginState(); } void UserManagerBase::SwitchToLastActiveUser() { @@ -508,17 +509,8 @@ void UserManagerBase::ParseUserList(const base::ListValue& users_list, bool UserManagerBase::IsCurrentUserOwner() const { DCHECK(task_runner_->RunsTasksOnCurrentThread()); - base::AutoLock lk(is_current_user_owner_lock_); - return is_current_user_owner_; -} - -void UserManagerBase::SetCurrentUserIsOwner(bool is_current_user_owner) { - DCHECK(task_runner_->RunsTasksOnCurrentThread()); - { - base::AutoLock lk(is_current_user_owner_lock_); - is_current_user_owner_ = is_current_user_owner; - } - CallUpdateLoginState(); + return !owner_account_id_.empty() && active_user_ && + active_user_->GetAccountId() == owner_account_id_; } bool UserManagerBase::IsCurrentUserNew() const { @@ -739,6 +731,7 @@ bool UserManagerBase::HasPendingBootstrap(const AccountId& account_id) const { void UserManagerBase::SetOwnerId(const AccountId& owner_account_id) { owner_account_id_ = owner_account_id; + CallUpdateLoginState(); } const AccountId& UserManagerBase::GetPendingUserSwitchID() const { @@ -1028,7 +1021,7 @@ void UserManagerBase::Initialize() { } void UserManagerBase::CallUpdateLoginState() { - UpdateLoginState(active_user_, primary_user_, is_current_user_owner_); + UpdateLoginState(active_user_, primary_user_, IsCurrentUserOwner()); } void UserManagerBase::SetLRUUser(User* user) { diff --git a/chromium/components/user_manager/user_manager_base.h b/chromium/components/user_manager/user_manager_base.h index b30015f0ecc..9e9fec63919 100644 --- a/chromium/components/user_manager/user_manager_base.h +++ b/chromium/components/user_manager/user_manager_base.h @@ -250,8 +250,6 @@ class USER_MANAGER_EXPORT UserManagerBase : public UserManager { // Getters/setters for private members. - virtual void SetCurrentUserIsOwner(bool is_current_user_owner); - virtual bool GetEphemeralUsersEnabled() const; virtual void SetEphemeralUsersEnabled(bool enabled); @@ -340,11 +338,6 @@ class USER_MANAGER_EXPORT UserManagerBase : public UserManager { // Indicates stage of loading user from prefs. UserLoadStage user_loading_stage_ = STAGE_NOT_LOADED; - // Cached flag of whether currently logged-in user is owner or not. - // May be accessed on different threads, requires locking. - bool is_current_user_owner_ = false; - mutable base::Lock is_current_user_owner_lock_; - // Cached flag of whether the currently logged-in user existed before this // login. bool is_current_user_new_ = false; |