// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/crosapi/dlp_ash.h"
#include "ash/shell.h"
#include "base/check.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "chrome/browser/ash/crosapi/crosapi_ash.h"
#include "chrome/browser/ash/crosapi/crosapi_manager.h"
#include "chrome/browser/ash/crosapi/screen_manager_ash.h"
#include "chrome/browser/ash/crosapi/window_util.h"
#include "chrome/browser/ash/policy/dlp/dlp_content_manager_ash.h"
#include "chrome/browser/ash/policy/dlp/dlp_files_controller_ash_utils.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_content_restriction_set.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_files_utils.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_rules_manager.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "content/public/browser/browser_thread.h"
namespace crosapi {
namespace {
policy::DlpRulesManager::Level ConvertMojoToDlpRulesManagerLevel(
crosapi::mojom::DlpRestrictionLevel level) {
switch (level) {
case crosapi::mojom::DlpRestrictionLevel::kReport:
return policy::DlpRulesManager::Level::kReport;
case crosapi::mojom::DlpRestrictionLevel::kWarn:
return policy::DlpRulesManager::Level::kWarn;
case crosapi::mojom::DlpRestrictionLevel::kBlock:
return policy::DlpRulesManager::Level::kBlock;
case crosapi::mojom::DlpRestrictionLevel::kAllow:
return policy::DlpRulesManager::Level::kAllow;
case crosapi::mojom::DlpRestrictionLevel::kNotSet:
return policy::DlpRulesManager::Level::kNotSet;
}
}
policy::DlpContentRestrictionSet ConvertMojoToDlpContentRestrictionSet(
const mojom::DlpRestrictionSetPtr& restrictions) {
policy::DlpContentRestrictionSet result;
result.SetRestriction(
policy::DlpContentRestriction::kScreenshot,
ConvertMojoToDlpRulesManagerLevel(restrictions->screenshot->level),
restrictions->screenshot->url);
result.SetRestriction(
policy::DlpContentRestriction::kPrivacyScreen,
ConvertMojoToDlpRulesManagerLevel(restrictions->privacy_screen->level),
restrictions->privacy_screen->url);
result.SetRestriction(
policy::DlpContentRestriction::kPrint,
ConvertMojoToDlpRulesManagerLevel(restrictions->print->level),
restrictions->print->url);
result.SetRestriction(
policy::DlpContentRestriction::kScreenShare,
ConvertMojoToDlpRulesManagerLevel(restrictions->screen_share->level),
restrictions->screen_share->url);
return result;
}
policy::dlp::FileAction ConvertMojoToDlpFileAction(mojom::FileAction action) {
switch (action) {
case crosapi::mojom::FileAction::kUnknown:
return policy::dlp::FileAction::kUnknown;
case crosapi::mojom::FileAction::kDownload:
return policy::dlp::FileAction::kDownload;
case crosapi::mojom::FileAction::kTransfer:
return policy::dlp::FileAction::kTransfer;
case crosapi::mojom::FileAction::kUpload:
return policy::dlp::FileAction::kUpload;
case crosapi::mojom::FileAction::kCopy:
return policy::dlp::FileAction::kCopy;
case crosapi::mojom::FileAction::kMove:
return policy::dlp::FileAction::kMove;
case crosapi::mojom::FileAction::kOpen:
return policy::dlp::FileAction::kOpen;
case crosapi::mojom::FileAction::kShare:
return policy::dlp::FileAction::kShare;
}
}
content::DesktopMediaID AreaToDesktopMediaID(
const mojom::ScreenShareAreaPtr& area) {
// Fullscreen share.
if (!area->window_id.has_value() && area->snapshot_source_id == 0) {
return content::DesktopMediaID::RegisterNativeWindow(
content::DesktopMediaID::TYPE_SCREEN,
ash::Shell::GetPrimaryRootWindow());
}
aura::Window* window = nullptr;
if (area->window_id.has_value()) {
window = GetShellSurfaceWindow(area->window_id.value());
} else if (area->snapshot_source_id != 0) {
window = crosapi::CrosapiManager::Get()
->crosapi_ash()
->screen_manager_ash()
->GetWindowById(area->snapshot_source_id);
}
if (!window)
return content::DesktopMediaID();
return content::DesktopMediaID::RegisterNativeWindow(
content::DesktopMediaID::TYPE_WINDOW, window);
}
} // namespace
DlpAsh::DlpAsh() {
receivers_.set_disconnect_handler(base::BindRepeating(
&DlpAsh::OnDisconnect, weak_ptr_factory_.GetWeakPtr()));
}
DlpAsh::~DlpAsh() = default;
void DlpAsh::BindReceiver(mojo::PendingReceiver<mojom::Dlp> receiver) {
receivers_.Add(this, std::move(receiver));
}
void DlpAsh::DlpRestrictionsUpdated(const std::string& window_id,
mojom::DlpRestrictionSetPtr restrictions) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
policy::DlpContentManagerAsh* dlp_content_manager =
policy::DlpContentManagerAsh::Get();
DCHECK(dlp_content_manager);
dlp_content_manager->OnWindowRestrictionChanged(
receivers_.current_receiver(), window_id,
ConvertMojoToDlpContentRestrictionSet(restrictions));
}
void DlpAsh::CheckScreenShareRestriction(
mojom::ScreenShareAreaPtr area,
const std::u16string& application_title,
CheckScreenShareRestrictionCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const content::DesktopMediaID media_id = AreaToDesktopMediaID(area);
if (media_id.is_null()) {
std::move(callback).Run(/*allowed=*/true);
return;
}
policy::DlpContentManagerAsh* dlp_content_manager =
policy::DlpContentManagerAsh::Get();
DCHECK(dlp_content_manager);
dlp_content_manager->CheckScreenShareRestriction(media_id, application_title,
std::move(callback));
}
void DlpAsh::OnScreenShareStarted(
const std::string& label,
mojom::ScreenShareAreaPtr area,
const ::std::u16string& application_title,
::mojo::PendingRemote<mojom::StateChangeDelegate> delegate) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const content::DesktopMediaID media_id = AreaToDesktopMediaID(area);
if (media_id.is_null())
return;
mojo::RemoteSetElementId id =
screen_share_remote_delegates_.Add(std::move(delegate));
base::RepeatingCallback stop_callback = base::BindRepeating(
&DlpAsh::StopScreenShare, weak_ptr_factory_.GetWeakPtr(), id);
base::RepeatingCallback state_change_callback = base::BindRepeating(
&DlpAsh::ChangeScreenShareState, weak_ptr_factory_.GetWeakPtr(), id);
policy::DlpContentManagerAsh* dlp_content_manager =
policy::DlpContentManagerAsh::Get();
DCHECK(dlp_content_manager);
// Source change callback should not be called for screen or window shares
// that are controlled over crosapi.
dlp_content_manager->OnScreenShareStarted(
label, {media_id}, application_title, std::move(stop_callback),
std::move(state_change_callback), /*source_callback=*/base::DoNothing());
}
void DlpAsh::OnScreenShareStopped(const std::string& label,
mojom::ScreenShareAreaPtr area) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const content::DesktopMediaID media_id = AreaToDesktopMediaID(area);
if (media_id.is_null())
return;
policy::DlpContentManagerAsh* dlp_content_manager =
policy::DlpContentManagerAsh::Get();
DCHECK(dlp_content_manager);
dlp_content_manager->OnScreenShareStopped(label, media_id);
}
void DlpAsh::ShowBlockedFiles(std::optional<uint64_t> task_id,
const std::vector<base::FilePath>& blocked_files,
mojom::FileAction action) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Profile* profile = ProfileManager::GetPrimaryUserProfile();
DCHECK(profile);
::policy::files_controller_ash_utils::ShowDlpBlockedFiles(
profile, task_id, blocked_files, ConvertMojoToDlpFileAction(action));
}
void DlpAsh::ChangeScreenShareState(
mojo::RemoteSetElementId id,
const content::DesktopMediaID& media_id,
blink::mojom::MediaStreamStateChange new_state) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!screen_share_remote_delegates_.Contains(id))
return;
switch (new_state) {
case blink::mojom::MediaStreamStateChange::PAUSE:
screen_share_remote_delegates_.Get(id)->OnPause();
break;
case blink::mojom::MediaStreamStateChange::PLAY:
screen_share_remote_delegates_.Get(id)->OnResume();
break;
}
}
void DlpAsh::StopScreenShare(mojo::RemoteSetElementId id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!screen_share_remote_delegates_.Contains(id))
return;
screen_share_remote_delegates_.Get(id)->OnStop();
}
void DlpAsh::OnDisconnect() {
policy::DlpContentManagerAsh* dlp_content_manager =
policy::DlpContentManagerAsh::Get();
if (!dlp_content_manager) {
return;
}
dlp_content_manager->CleanPendingRestrictions(receivers_.current_receiver());
}
} // namespace crosapi