Commit 95dd490a authored by Sergey Poromov's avatar Sergey Poromov Committed by Commit Bot

DLP: Add check to video capture mode and interrupt it if needed.

Before capturing video in Capture Mode,
it should be checked whether the captured area is allowed
according to the currently set Data Leak Prevention rules.
Also, when video is being captured and confidential content
appears in the area, the capture should be stopped via a callback.

Bug: 1133324
Change-Id: I28ddd46b4c10760d3631d5b934ea06facec31df6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2438411
Commit-Queue: Sergey Poromov <poromov@chromium.org>
Reviewed-by: default avatarAhmed Fakhry <afakhry@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarNikita Podguzov <nikitapodguzov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#817695}
parent 3e5176bb
...@@ -284,6 +284,7 @@ void CaptureModeController::EndVideoRecording() { ...@@ -284,6 +284,7 @@ void CaptureModeController::EndVideoRecording() {
// with all the frames. // with all the frames.
is_recording_in_progress_ = false; is_recording_in_progress_ = false;
Shell::Get()->UpdateCursorCompositingEnabled(); Shell::Get()->UpdateCursorCompositingEnabled();
delegate_->StopObservingRestrictedContent();
} }
bool CaptureModeController::IsCaptureAllowed() const { bool CaptureModeController::IsCaptureAllowed() const {
...@@ -521,6 +522,11 @@ void CaptureModeController::OnVideoRecordCountDownFinished() { ...@@ -521,6 +522,11 @@ void CaptureModeController::OnVideoRecordCountDownFinished() {
// TODO(afakhry): Call into the recording service. // TODO(afakhry): Call into the recording service.
delegate_->StartObservingRestrictedContent(
capture_params->window, capture_params->bounds,
base::BindOnce(&CaptureModeController::EndVideoRecording,
weak_ptr_factory_.GetWeakPtr()));
ShowStopRecordingButton(capture_params->window->GetRootWindow()); ShowStopRecordingButton(capture_params->window->GetRootWindow());
} }
......
...@@ -29,4 +29,11 @@ bool TestCaptureModeDelegate::IsCaptureAllowed(const aura::Window* window, ...@@ -29,4 +29,11 @@ bool TestCaptureModeDelegate::IsCaptureAllowed(const aura::Window* window,
return true; return true;
} }
void TestCaptureModeDelegate::StartObservingRestrictedContent(
const aura::Window* window,
const gfx::Rect& bounds,
base::OnceClosure stop_callback) {}
void TestCaptureModeDelegate::StopObservingRestrictedContent() {}
} // namespace ash } // namespace ash
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define ASH_CAPTURE_MODE_TEST_CAPTURE_MODE_DELEGATE_H_ #define ASH_CAPTURE_MODE_TEST_CAPTURE_MODE_DELEGATE_H_
#include "ash/public/cpp/capture_mode_delegate.h" #include "ash/public/cpp/capture_mode_delegate.h"
#include "base/callback.h"
namespace ash { namespace ash {
...@@ -24,6 +25,11 @@ class TestCaptureModeDelegate : public CaptureModeDelegate { ...@@ -24,6 +25,11 @@ class TestCaptureModeDelegate : public CaptureModeDelegate {
bool IsCaptureAllowed(const aura::Window* window, bool IsCaptureAllowed(const aura::Window* window,
const gfx::Rect& bounds, const gfx::Rect& bounds,
bool for_video) const override; bool for_video) const override;
void StartObservingRestrictedContent(
const aura::Window* window,
const gfx::Rect& bounds,
base::OnceClosure stop_callback) override;
void StopObservingRestrictedContent() override;
}; };
} // namespace ash } // namespace ash
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define ASH_PUBLIC_CPP_CAPTURE_MODE_DELEGATE_H_ #define ASH_PUBLIC_CPP_CAPTURE_MODE_DELEGATE_H_
#include "ash/public/cpp/ash_public_export.h" #include "ash/public/cpp/ash_public_export.h"
#include "base/callback.h"
namespace aura { namespace aura {
class Window; class Window;
...@@ -49,6 +50,18 @@ class ASH_PUBLIC_EXPORT CaptureModeDelegate { ...@@ -49,6 +50,18 @@ class ASH_PUBLIC_EXPORT CaptureModeDelegate {
virtual bool IsCaptureAllowed(const aura::Window* window, virtual bool IsCaptureAllowed(const aura::Window* window,
const gfx::Rect& bounds, const gfx::Rect& bounds,
bool for_video) const = 0; bool for_video) const = 0;
// Called when a video capture for |window| and |bounds| area is started, so
// that Data Leak Prevention can start observing the area.
// |on_area_restricted_callback| will be called when the area becomes
// restricted so that the capture should be interrupted.
virtual void StartObservingRestrictedContent(
const aura::Window* window,
const gfx::Rect& bounds,
base::OnceClosure on_area_restricted_callback) = 0;
// Called when the running video capture is stopped.
virtual void StopObservingRestrictedContent() = 0;
}; };
} // namespace ash } // namespace ash
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h" #include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h"
#include "chrome/browser/ui/ash/screenshot_area.h"
#include "content/public/browser/visibility.h" #include "content/public/browser/visibility.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h" #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
...@@ -51,53 +50,12 @@ DlpContentRestrictionSet DlpContentManager::GetOnScreenPresentRestrictions() ...@@ -51,53 +50,12 @@ DlpContentRestrictionSet DlpContentManager::GetOnScreenPresentRestrictions()
bool DlpContentManager::IsScreenshotRestricted( bool DlpContentManager::IsScreenshotRestricted(
const ScreenshotArea& area) const { const ScreenshotArea& area) const {
// Fullscreen - restricted if any confidential data is visible. return IsAreaRestricted(area, DlpContentRestriction::kScreenshot);
if (area.type == ScreenshotType::kAllRootWindows) { }
return GetOnScreenPresentRestrictions().HasRestriction(
DlpContentRestriction::kScreenshot);
}
// Window - restricted if the window contains confidential data.
if (area.type == ScreenshotType::kWindow) {
DCHECK(area.window);
for (auto& entry : confidential_web_contents_) {
aura::Window* web_contents_window = entry.first->GetNativeView();
if (entry.second.HasRestriction(DlpContentRestriction::kScreenshot) &&
area.window->Contains(web_contents_window)) {
return true;
}
}
return false;
}
DCHECK_EQ(area.type, ScreenshotType::kPartialWindow);
DCHECK(area.rect);
DCHECK(area.window);
// Partial - restricted if any visible confidential WebContents intersects
// with the area.
for (auto& entry : confidential_web_contents_) {
if (entry.first->GetVisibility() != content::Visibility::VISIBLE ||
!entry.second.HasRestriction(DlpContentRestriction::kScreenshot)) {
continue;
}
aura::Window* web_contents_window = entry.first->GetNativeView();
aura::Window* root_window = web_contents_window->GetRootWindow();
// If no root window, then the WebContent shouldn't be visible.
if (!root_window)
continue;
// Not allowing if the area intersects with confidential WebContents,
// but the intersection doesn't belong to occluded area.
gfx::Rect intersection(*area.rect);
aura::Window::ConvertRectToTarget(area.window, root_window, &intersection);
intersection.Intersect(web_contents_window->GetBoundsInRootWindow());
if (!intersection.IsEmpty() &&
!web_contents_window->occluded_region_in_root().contains(
gfx::RectToSkIRect(intersection))) {
return true;
}
}
return false; bool DlpContentManager::IsVideoCaptureRestricted(
const ScreenshotArea& area) const {
return IsAreaRestricted(area, DlpContentRestriction::kVideoCapture);
} }
bool DlpContentManager::IsPrintingRestricted( bool DlpContentManager::IsPrintingRestricted(
...@@ -113,6 +71,21 @@ bool DlpContentManager::IsPrintingRestricted( ...@@ -113,6 +71,21 @@ bool DlpContentManager::IsPrintingRestricted(
.HasRestriction(DlpContentRestriction::kPrint); .HasRestriction(DlpContentRestriction::kPrint);
} }
void DlpContentManager::OnVideoCaptureStarted(const ScreenshotArea& area,
base::OnceClosure stop_callback) {
if (IsVideoCaptureRestricted(area)) {
std::move(stop_callback).Run();
return;
}
DCHECK(!running_video_capture_.has_value());
running_video_capture_.emplace(
std::make_pair(area, std::move(stop_callback)));
}
void DlpContentManager::OnVideoCaptureStopped() {
running_video_capture_.reset();
}
/* static */ /* static */
void DlpContentManager::SetDlpContentManagerForTesting( void DlpContentManager::SetDlpContentManagerForTesting(
DlpContentManager* dlp_content_manager) { DlpContentManager* dlp_content_manager) {
...@@ -140,6 +113,9 @@ void DlpContentManager::OnConfidentialityChanged( ...@@ -140,6 +113,9 @@ void DlpContentManager::OnConfidentialityChanged(
if (web_contents->GetVisibility() == content::Visibility::VISIBLE) { if (web_contents->GetVisibility() == content::Visibility::VISIBLE) {
MaybeChangeOnScreenRestrictions(); MaybeChangeOnScreenRestrictions();
} }
// TODO(crbug.com/1133324): Track the corresponding window position for
// video capture. It might appear that some confidential content will become
// visible in the video capture area and it should be stopped.
} }
} }
...@@ -201,6 +177,7 @@ void DlpContentManager::MaybeChangeOnScreenRestrictions() { ...@@ -201,6 +177,7 @@ void DlpContentManager::MaybeChangeOnScreenRestrictions() {
on_screen_restrictions_ = new_restriction_set; on_screen_restrictions_ = new_restriction_set;
OnScreenRestrictionsChanged(added_restrictions, removed_restrictions); OnScreenRestrictionsChanged(added_restrictions, removed_restrictions);
} }
CheckRunningVideoCapture();
} }
void DlpContentManager::OnScreenRestrictionsChanged( void DlpContentManager::OnScreenRestrictionsChanged(
...@@ -232,6 +209,68 @@ void DlpContentManager::MaybeRemovePrivacyScreenEnforcement() const { ...@@ -232,6 +209,68 @@ void DlpContentManager::MaybeRemovePrivacyScreenEnforcement() const {
} }
} }
bool DlpContentManager::IsAreaRestricted(
const ScreenshotArea& area,
DlpContentRestriction restriction) const {
// Fullscreen - restricted if any confidential data is visible.
if (area.type == ScreenshotType::kAllRootWindows) {
return GetOnScreenPresentRestrictions().HasRestriction(restriction);
}
// Window - restricted if the window contains confidential data.
if (area.type == ScreenshotType::kWindow) {
DCHECK(area.window);
for (auto& entry : confidential_web_contents_) {
aura::Window* web_contents_window = entry.first->GetNativeView();
if (entry.second.HasRestriction(restriction) &&
area.window->Contains(web_contents_window)) {
return true;
}
}
return false;
}
DCHECK_EQ(area.type, ScreenshotType::kPartialWindow);
DCHECK(area.rect);
DCHECK(area.window);
// Partial - restricted if any visible confidential WebContents intersects
// with the area.
for (auto& entry : confidential_web_contents_) {
if (entry.first->GetVisibility() != content::Visibility::VISIBLE ||
!entry.second.HasRestriction(restriction)) {
continue;
}
aura::Window* web_contents_window = entry.first->GetNativeView();
aura::Window* root_window = web_contents_window->GetRootWindow();
// If no root window, then the WebContent shouldn't be visible.
if (!root_window)
continue;
// Not allowing if the area intersects with confidential WebContents,
// but the intersection doesn't belong to occluded area.
gfx::Rect intersection(*area.rect);
aura::Window::ConvertRectToTarget(area.window, root_window, &intersection);
intersection.Intersect(web_contents_window->GetBoundsInRootWindow());
if (!intersection.IsEmpty() &&
!web_contents_window->occluded_region_in_root().contains(
gfx::RectToSkIRect(intersection))) {
return true;
}
}
return false;
}
void DlpContentManager::CheckRunningVideoCapture() {
if (!running_video_capture_.has_value())
return;
const auto& area = running_video_capture_->first;
auto& stop_callback = running_video_capture_->second;
if (IsAreaRestricted(area, DlpContentRestriction::kVideoCapture)) {
std::move(stop_callback).Run();
running_video_capture_.reset();
}
}
// static // static
base::TimeDelta DlpContentManager::GetPrivacyScreenOffDelayForTesting() { base::TimeDelta DlpContentManager::GetPrivacyScreenOffDelayForTesting() {
return kPrivacyScreenOffDelay; return kPrivacyScreenOffDelay;
......
...@@ -5,10 +5,13 @@ ...@@ -5,10 +5,13 @@
#ifndef CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CONTENT_MANAGER_H_ #ifndef CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CONTENT_MANAGER_H_
#define CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CONTENT_MANAGER_H_ #define CHROME_BROWSER_CHROMEOS_POLICY_DLP_DLP_CONTENT_MANAGER_H_
#include "base/callback.h"
#include "base/containers/flat_map.h" #include "base/containers/flat_map.h"
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "base/optional.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.h" #include "chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.h"
#include "chrome/browser/ui/ash/screenshot_area.h"
class GURL; class GURL;
struct ScreenshotArea; struct ScreenshotArea;
...@@ -41,9 +44,20 @@ class DlpContentManager { ...@@ -41,9 +44,20 @@ class DlpContentManager {
// Returns whether screenshots should be restricted. // Returns whether screenshots should be restricted.
virtual bool IsScreenshotRestricted(const ScreenshotArea& area) const; virtual bool IsScreenshotRestricted(const ScreenshotArea& area) const;
// Returns whether video capture should be restricted.
bool IsVideoCaptureRestricted(const ScreenshotArea& area) const;
// Returns whether printing should be restricted. // Returns whether printing should be restricted.
bool IsPrintingRestricted(content::WebContents* web_contents) const; bool IsPrintingRestricted(content::WebContents* web_contents) const;
// Called when video capturing for |area| is started.
// |stop_callback| will be called when restricted content will appear there.
void OnVideoCaptureStarted(const ScreenshotArea& area,
base::OnceClosure stop_callback);
// Called when video capturing is stopped.
void OnVideoCaptureStopped();
// The caller (test) should manage |dlp_content_manager| lifetime. // The caller (test) should manage |dlp_content_manager| lifetime.
// Reset doesn't delete the object. // Reset doesn't delete the object.
static void SetDlpContentManagerForTesting( static void SetDlpContentManagerForTesting(
...@@ -91,6 +105,14 @@ class DlpContentManager { ...@@ -91,6 +105,14 @@ class DlpContentManager {
// Removes PrivacyScreen enforcement after delay if it's still not enforced. // Removes PrivacyScreen enforcement after delay if it's still not enforced.
void MaybeRemovePrivacyScreenEnforcement() const; void MaybeRemovePrivacyScreenEnforcement() const;
// Returns whether |restriction| is currently enforced for |area|.
bool IsAreaRestricted(const ScreenshotArea& area,
DlpContentRestriction restriction) const;
// Checks and stops the running video capture if restricted content appeared
// in the corresponding areas.
void CheckRunningVideoCapture();
// Get the delay before switching privacy screen off. // Get the delay before switching privacy screen off.
static base::TimeDelta GetPrivacyScreenOffDelayForTesting(); static base::TimeDelta GetPrivacyScreenOffDelayForTesting();
...@@ -100,6 +122,10 @@ class DlpContentManager { ...@@ -100,6 +122,10 @@ class DlpContentManager {
// Set of restriction applied to the currently visible content. // Set of restriction applied to the currently visible content.
DlpContentRestrictionSet on_screen_restrictions_; DlpContentRestrictionSet on_screen_restrictions_;
// The currently running video capture are and callback to stop, if any.
base::Optional<std::pair<ScreenshotArea, base::OnceClosure>>
running_video_capture_;
}; };
} // namespace policy } // namespace policy
......
...@@ -19,6 +19,8 @@ enum DlpContentRestriction { ...@@ -19,6 +19,8 @@ enum DlpContentRestriction {
kPrivacyScreen = 1 << 1, kPrivacyScreen = 1 << 1,
// Do not allow printing. // Do not allow printing.
kPrint = 1 << 2, kPrint = 1 << 2,
// Do not allow video capturing of the content.
kVideoCapture = 1 << 3,
}; };
// Represents set of restrictions applied to on-screen content. // Represents set of restrictions applied to on-screen content.
......
...@@ -85,6 +85,18 @@ bool ChromeCaptureModeDelegate::IsCaptureAllowed(const aura::Window* window, ...@@ -85,6 +85,18 @@ bool ChromeCaptureModeDelegate::IsCaptureAllowed(const aura::Window* window,
policy::DlpContentManager* dlp_content_manager = policy::DlpContentManager* dlp_content_manager =
policy::DlpContentManager::Get(); policy::DlpContentManager::Get();
const ScreenshotArea area = ConvertToScreenshotArea(window, bounds); const ScreenshotArea area = ConvertToScreenshotArea(window, bounds);
// TODO(poromov): Implement check for video capture. return for_video ? !dlp_content_manager->IsVideoCaptureRestricted(area)
return for_video ? true : !dlp_content_manager->IsScreenshotRestricted(area); : !dlp_content_manager->IsScreenshotRestricted(area);
}
void ChromeCaptureModeDelegate::StartObservingRestrictedContent(
const aura::Window* window,
const gfx::Rect& bounds,
base::OnceClosure stop_callback) {
policy::DlpContentManager::Get()->OnVideoCaptureStarted(
ConvertToScreenshotArea(window, bounds), std::move(stop_callback));
}
void ChromeCaptureModeDelegate::StopObservingRestrictedContent() {
policy::DlpContentManager::Get()->OnVideoCaptureStopped();
} }
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CHROME_BROWSER_UI_ASH_CHROME_CAPTURE_MODE_DELEGATE_H_ #define CHROME_BROWSER_UI_ASH_CHROME_CAPTURE_MODE_DELEGATE_H_
#include "ash/public/cpp/capture_mode_delegate.h" #include "ash/public/cpp/capture_mode_delegate.h"
#include "base/callback.h"
// Implements the interface needed for the delegate of the Capture Mode feature // Implements the interface needed for the delegate of the Capture Mode feature
// in Chrome. // in Chrome.
...@@ -25,6 +26,11 @@ class ChromeCaptureModeDelegate : public ash::CaptureModeDelegate { ...@@ -25,6 +26,11 @@ class ChromeCaptureModeDelegate : public ash::CaptureModeDelegate {
bool IsCaptureAllowed(const aura::Window* window, bool IsCaptureAllowed(const aura::Window* window,
const gfx::Rect& bounds, const gfx::Rect& bounds,
bool for_video) const override; bool for_video) const override;
void StartObservingRestrictedContent(
const aura::Window* window,
const gfx::Rect& bounds,
base::OnceClosure stop_callback) override;
void StopObservingRestrictedContent() override;
}; };
#endif // CHROME_BROWSER_UI_ASH_CHROME_CAPTURE_MODE_DELEGATE_H_ #endif // CHROME_BROWSER_UI_ASH_CHROME_CAPTURE_MODE_DELEGATE_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment