| // Copyright (c) 2012 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 "chrome/browser/extensions/api/webstore_private/webstore_private_api.h" |
| |
| #include <stddef.h> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/base64.h" |
| #include "base/bind.h" |
| #include "base/lazy_instance.h" |
| #include "base/macros.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/values.h" |
| #include "base/version.h" |
| #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/extensions/crx_installer.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/extensions/extension_util.h" |
| #include "chrome/browser/extensions/install_tracker.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h" |
| #include "chrome/browser/safe_browsing/safe_browsing_service.h" |
| #include "chrome/browser/signin/identity_manager_factory.h" |
| #include "chrome/browser/ui/app_list/app_list_util.h" |
| #include "chrome/common/extensions/extension_constants.h" |
| #include "chrome/common/pref_names.h" |
| #include "components/crx_file/id_util.h" |
| #include "components/prefs/pref_service.h" |
| #include "content/public/browser/gpu_feature_checker.h" |
| #include "content/public/browser/storage_partition.h" |
| #include "content/public/browser/web_contents.h" |
| #include "extensions/browser/extension_function_constants.h" |
| #include "extensions/browser/extension_registry.h" |
| #include "extensions/browser/extension_system.h" |
| #include "extensions/common/extension.h" |
| #include "net/base/load_flags.h" |
| #include "net/url_request/url_request.h" |
| #include "services/identity/public/cpp/identity_manager.h" |
| #include "url/gurl.h" |
| |
| #if BUILDFLAG(ENABLE_SUPERVISED_USERS) |
| #include "chrome/browser/supervised_user/supervised_user_service.h" |
| #include "chrome/browser/supervised_user/supervised_user_service_factory.h" |
| #endif |
| |
| using safe_browsing::SafeBrowsingNavigationObserverManager; |
| |
| namespace extensions { |
| |
| namespace BeginInstallWithManifest3 = |
| api::webstore_private::BeginInstallWithManifest3; |
| namespace CompleteInstall = api::webstore_private::CompleteInstall; |
| namespace GetBrowserLogin = api::webstore_private::GetBrowserLogin; |
| namespace GetEphemeralAppsEnabled = |
| api::webstore_private::GetEphemeralAppsEnabled; |
| namespace GetIsLauncherEnabled = api::webstore_private::GetIsLauncherEnabled; |
| namespace GetStoreLogin = api::webstore_private::GetStoreLogin; |
| namespace GetWebGLStatus = api::webstore_private::GetWebGLStatus; |
| namespace IsPendingCustodianApproval = |
| api::webstore_private::IsPendingCustodianApproval; |
| namespace IsInIncognitoMode = api::webstore_private::IsInIncognitoMode; |
| namespace LaunchEphemeralApp = api::webstore_private::LaunchEphemeralApp; |
| namespace SetStoreLogin = api::webstore_private::SetStoreLogin; |
| |
| namespace { |
| |
| // Holds the Approvals between the time we prompt and start the installs. |
| class PendingApprovals { |
| public: |
| PendingApprovals(); |
| ~PendingApprovals(); |
| |
| void PushApproval(std::unique_ptr<WebstoreInstaller::Approval> approval); |
| std::unique_ptr<WebstoreInstaller::Approval> PopApproval( |
| Profile* profile, |
| const std::string& id); |
| |
| private: |
| using ApprovalList = |
| std::vector<std::unique_ptr<WebstoreInstaller::Approval>>; |
| |
| ApprovalList approvals_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PendingApprovals); |
| }; |
| |
| PendingApprovals::PendingApprovals() {} |
| PendingApprovals::~PendingApprovals() {} |
| |
| void PendingApprovals::PushApproval( |
| std::unique_ptr<WebstoreInstaller::Approval> approval) { |
| approvals_.push_back(std::move(approval)); |
| } |
| |
| std::unique_ptr<WebstoreInstaller::Approval> PendingApprovals::PopApproval( |
| Profile* profile, |
| const std::string& id) { |
| for (auto iter = approvals_.begin(); iter != approvals_.end(); ++iter) { |
| if (iter->get()->extension_id == id && |
| profile->IsSameProfile(iter->get()->profile)) { |
| std::unique_ptr<WebstoreInstaller::Approval> approval = std::move(*iter); |
| approvals_.erase(iter); |
| return approval; |
| } |
| } |
| return std::unique_ptr<WebstoreInstaller::Approval>(); |
| } |
| |
| api::webstore_private::Result WebstoreInstallHelperResultToApiResult( |
| WebstoreInstallHelper::Delegate::InstallHelperResultCode result) { |
| switch (result) { |
| case WebstoreInstallHelper::Delegate::UNKNOWN_ERROR: |
| return api::webstore_private::RESULT_UNKNOWN_ERROR; |
| case WebstoreInstallHelper::Delegate::ICON_ERROR: |
| return api::webstore_private::RESULT_ICON_ERROR; |
| case WebstoreInstallHelper::Delegate::MANIFEST_ERROR: |
| return api::webstore_private::RESULT_MANIFEST_ERROR; |
| } |
| NOTREACHED(); |
| return api::webstore_private::RESULT_NONE; |
| } |
| |
| static base::LazyInstance<PendingApprovals>::DestructorAtExit |
| g_pending_approvals = LAZY_INSTANCE_INITIALIZER; |
| |
| // A preference set by the web store to indicate login information for |
| // purchased apps. |
| const char kWebstoreLogin[] = "extensions.webstore_login"; |
| |
| // Error messages that can be returned by the API. |
| const char kAlreadyInstalledError[] = "This item is already installed"; |
| const char kWebstoreInvalidIconUrlError[] = "Invalid icon url"; |
| const char kWebstoreInvalidIdError[] = "Invalid id"; |
| const char kWebstoreInvalidManifestError[] = "Invalid manifest"; |
| const char kNoPreviousBeginInstallWithManifestError[] = |
| "* does not match a previous call to beginInstallWithManifest3"; |
| const char kWebstoreUserCancelledError[] = "User cancelled install"; |
| const char kIncognitoError[] = |
| "Apps cannot be installed in guest/incognito mode"; |
| const char kEphemeralAppLaunchingNotSupported[] = |
| "Ephemeral launching of apps is no longer supported."; |
| |
| // The number of user gestures to trace back for the referrer chain. |
| const int kExtensionReferrerUserGestureLimit = 2; |
| |
| WebstoreInstaller::Delegate* test_webstore_installer_delegate = nullptr; |
| |
| // We allow the web store to set a string containing login information when a |
| // purchase is made, so that when a user logs into sync with a different |
| // account we can recognize the situation. The Get function returns the login if |
| // there was previously stored data, or an empty string otherwise. The Set will |
| // overwrite any previous login. |
| std::string GetWebstoreLogin(Profile* profile) { |
| if (profile->GetPrefs()->HasPrefPath(kWebstoreLogin)) |
| return profile->GetPrefs()->GetString(kWebstoreLogin); |
| return std::string(); |
| } |
| |
| void SetWebstoreLogin(Profile* profile, const std::string& login) { |
| profile->GetPrefs()->SetString(kWebstoreLogin, login); |
| } |
| |
| void RecordWebstoreExtensionInstallResult(bool success) { |
| UMA_HISTOGRAM_BOOLEAN("Webstore.ExtensionInstallResult", success); |
| } |
| |
| } // namespace |
| |
| // static |
| void WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting( |
| WebstoreInstaller::Delegate* delegate) { |
| test_webstore_installer_delegate = delegate; |
| } |
| |
| // static |
| std::unique_ptr<WebstoreInstaller::Approval> |
| WebstorePrivateApi::PopApprovalForTesting(Profile* profile, |
| const std::string& extension_id) { |
| return g_pending_approvals.Get().PopApproval(profile, extension_id); |
| } |
| |
| WebstorePrivateBeginInstallWithManifest3Function:: |
| WebstorePrivateBeginInstallWithManifest3Function() : chrome_details_(this) { |
| } |
| |
| WebstorePrivateBeginInstallWithManifest3Function:: |
| ~WebstorePrivateBeginInstallWithManifest3Function() { |
| } |
| |
| ExtensionFunction::ResponseAction |
| WebstorePrivateBeginInstallWithManifest3Function::Run() { |
| params_ = Params::Create(*args_); |
| EXTENSION_FUNCTION_VALIDATE(params_); |
| |
| if (!crx_file::id_util::IdIsValid(details().id)) { |
| return RespondNow(BuildResponse(api::webstore_private::RESULT_INVALID_ID, |
| kWebstoreInvalidIdError)); |
| } |
| |
| GURL icon_url; |
| if (details().icon_url) { |
| icon_url = source_url().Resolve(*details().icon_url); |
| if (!icon_url.is_valid()) { |
| return RespondNow( |
| BuildResponse(api::webstore_private::RESULT_INVALID_ICON_URL, |
| kWebstoreInvalidIconUrlError)); |
| } |
| } |
| |
| InstallTracker* tracker = InstallTracker::Get(browser_context()); |
| DCHECK(tracker); |
| bool is_installed = |
| extensions::ExtensionRegistry::Get(browser_context())->GetExtensionById( |
| details().id, extensions::ExtensionRegistry::EVERYTHING) != nullptr; |
| if (is_installed || tracker->GetActiveInstall(details().id)) { |
| return RespondNow(BuildResponse( |
| api::webstore_private::RESULT_ALREADY_INSTALLED, |
| kAlreadyInstalledError)); |
| } |
| ActiveInstallData install_data(details().id); |
| scoped_active_install_.reset(new ScopedActiveInstall(tracker, install_data)); |
| |
| network::mojom::URLLoaderFactory* loader_factory = nullptr; |
| if (!icon_url.is_empty()) { |
| loader_factory = |
| content::BrowserContext::GetDefaultStoragePartition(browser_context()) |
| ->GetURLLoaderFactoryForBrowserProcess() |
| .get(); |
| } |
| |
| scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper( |
| this, details().id, details().manifest, icon_url); |
| |
| // The helper will call us back via OnWebstoreParseSuccess or |
| // OnWebstoreParseFailure. |
| helper->Start(loader_factory); |
| |
| // Matched with a Release in OnWebstoreParseSuccess/OnWebstoreParseFailure. |
| AddRef(); |
| |
| // The response is sent asynchronously in OnWebstoreParseSuccess/ |
| // OnWebstoreParseFailure. |
| return RespondLater(); |
| } |
| |
| void WebstorePrivateBeginInstallWithManifest3Function::OnWebstoreParseSuccess( |
| const std::string& id, |
| const SkBitmap& icon, |
| std::unique_ptr<base::DictionaryValue> parsed_manifest) { |
| CHECK_EQ(details().id, id); |
| CHECK(parsed_manifest); |
| parsed_manifest_ = std::move(parsed_manifest); |
| icon_ = icon; |
| |
| std::string localized_name = |
| details().localized_name ? *details().localized_name : std::string(); |
| |
| std::string error; |
| dummy_extension_ = ExtensionInstallPrompt::GetLocalizedExtensionForDisplay( |
| parsed_manifest_.get(), |
| Extension::FROM_WEBSTORE, |
| id, |
| localized_name, |
| std::string(), |
| &error); |
| |
| if (!dummy_extension_.get()) { |
| OnWebstoreParseFailure(details().id, |
| WebstoreInstallHelper::Delegate::MANIFEST_ERROR, |
| kWebstoreInvalidManifestError); |
| return; |
| } |
| |
| // Check the management policy before the installation process begins. |
| Profile* profile = chrome_details_.GetProfile(); |
| base::string16 policy_error; |
| bool allow = |
| ExtensionSystem::Get(profile)->management_policy()->UserMayInstall( |
| dummy_extension_.get(), &policy_error); |
| if (!allow) { |
| bool blocked_for_child = false; |
| #if BUILDFLAG(ENABLE_SUPERVISED_USERS) |
| // If the installation was blocked because the user is a child, we send a |
| // different error code so that the Web Store can adjust the UI accordingly. |
| // In that case, the CWS will not show the |policy_error|. |
| if (profile->IsChild()) { |
| SupervisedUserService* service = |
| SupervisedUserServiceFactory::GetForProfile(profile); |
| // Hack: Check that the message matches to make sure installation was |
| // actually blocked due to the user being a child, as opposed to, say, |
| // device policy. |
| if (policy_error == service->GetExtensionsLockedMessage()) |
| blocked_for_child = true; |
| } |
| #endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) |
| api::webstore_private::Result code = |
| blocked_for_child |
| ? api::webstore_private::RESULT_BLOCKED_FOR_CHILD_ACCOUNT |
| : api::webstore_private::RESULT_BLOCKED_BY_POLICY; |
| Respond(BuildResponse(code, base::UTF16ToUTF8(policy_error))); |
| // Matches the AddRef in Run(). |
| Release(); |
| return; |
| } |
| |
| content::WebContents* web_contents = GetSenderWebContents(); |
| if (!web_contents) { |
| // The browser window has gone away. |
| Respond(BuildResponse(api::webstore_private::RESULT_USER_CANCELLED, |
| kWebstoreUserCancelledError)); |
| // Matches the AddRef in Run(). |
| Release(); |
| return; |
| } |
| install_prompt_.reset(new ExtensionInstallPrompt(web_contents)); |
| install_prompt_->ShowDialog( |
| base::Bind(&WebstorePrivateBeginInstallWithManifest3Function:: |
| OnInstallPromptDone, |
| this), |
| dummy_extension_.get(), &icon_, |
| ExtensionInstallPrompt::GetDefaultShowDialogCallback()); |
| // Control flow finishes up in OnInstallPromptDone. |
| } |
| |
| void WebstorePrivateBeginInstallWithManifest3Function::OnWebstoreParseFailure( |
| const std::string& id, |
| WebstoreInstallHelper::Delegate::InstallHelperResultCode result, |
| const std::string& error_message) { |
| CHECK_EQ(details().id, id); |
| |
| Respond(BuildResponse(WebstoreInstallHelperResultToApiResult(result), |
| error_message)); |
| |
| // Matches the AddRef in Run(). |
| Release(); |
| } |
| |
| void WebstorePrivateBeginInstallWithManifest3Function::OnInstallPromptDone( |
| ExtensionInstallPrompt::Result result) { |
| if (result == ExtensionInstallPrompt::Result::ACCEPTED) { |
| HandleInstallProceed(); |
| } else { |
| HandleInstallAbort(result == ExtensionInstallPrompt::Result::USER_CANCELED); |
| } |
| |
| // Matches the AddRef in Run(). |
| Release(); |
| } |
| |
| void WebstorePrivateBeginInstallWithManifest3Function::HandleInstallProceed() { |
| // This gets cleared in CrxInstaller::ConfirmInstall(). TODO(asargent) - in |
| // the future we may also want to add time-based expiration, where a whitelist |
| // entry is only valid for some number of minutes. |
| std::unique_ptr<WebstoreInstaller::Approval> approval( |
| WebstoreInstaller::Approval::CreateWithNoInstallPrompt( |
| chrome_details_.GetProfile(), details().id, |
| std::move(parsed_manifest_), false)); |
| approval->use_app_installed_bubble = !!details().app_install_bubble; |
| // If we are enabling the launcher, we should not show the app list in order |
| // to train the user to open it themselves at least once. |
| approval->skip_post_install_ui = !!details().enable_launcher; |
| approval->dummy_extension = dummy_extension_.get(); |
| approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_); |
| if (details().authuser) |
| approval->authuser = *details().authuser; |
| g_pending_approvals.Get().PushApproval(std::move(approval)); |
| |
| DCHECK(scoped_active_install_.get()); |
| scoped_active_install_->CancelDeregister(); |
| |
| // The Permissions_Install histogram is recorded from the ExtensionService |
| // for all extension installs, so we only need to record the web store |
| // specific histogram here. |
| ExtensionService::RecordPermissionMessagesHistogram( |
| dummy_extension_.get(), "WebStoreInstall"); |
| |
| Respond(BuildResponse(api::webstore_private::RESULT_SUCCESS, std::string())); |
| } |
| |
| void WebstorePrivateBeginInstallWithManifest3Function::HandleInstallAbort( |
| bool user_initiated) { |
| // The web store install histograms are a subset of the install histograms. |
| // We need to record both histograms here since CrxInstaller::InstallUIAbort |
| // is never called for web store install cancellations. |
| std::string histogram_name = user_initiated ? "WebStoreInstallCancel" |
| : "WebStoreInstallAbort"; |
| ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_.get(), |
| histogram_name.c_str()); |
| |
| histogram_name = user_initiated ? "InstallCancel" : "InstallAbort"; |
| ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_.get(), |
| histogram_name.c_str()); |
| |
| Respond(BuildResponse(api::webstore_private::RESULT_USER_CANCELLED, |
| kWebstoreUserCancelledError)); |
| } |
| |
| ExtensionFunction::ResponseValue |
| WebstorePrivateBeginInstallWithManifest3Function::BuildResponse( |
| api::webstore_private::Result result, const std::string& error) { |
| if (result != api::webstore_private::RESULT_SUCCESS) |
| return ErrorWithArguments(CreateResults(result), error); |
| |
| // The web store expects an empty string on success, so don't use |
| // RESULT_SUCCESS here. |
| return ArgumentList( |
| CreateResults(api::webstore_private::RESULT_EMPTY_STRING)); |
| } |
| |
| std::unique_ptr<base::ListValue> |
| WebstorePrivateBeginInstallWithManifest3Function::CreateResults( |
| api::webstore_private::Result result) const { |
| return BeginInstallWithManifest3::Results::Create(result); |
| } |
| |
| WebstorePrivateCompleteInstallFunction:: |
| WebstorePrivateCompleteInstallFunction() : chrome_details_(this) {} |
| |
| WebstorePrivateCompleteInstallFunction:: |
| ~WebstorePrivateCompleteInstallFunction() {} |
| |
| ExtensionFunction::ResponseAction |
| WebstorePrivateCompleteInstallFunction::Run() { |
| std::unique_ptr<CompleteInstall::Params> params( |
| CompleteInstall::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| if (chrome_details_.GetProfile()->IsGuestSession() || |
| chrome_details_.GetProfile()->IsOffTheRecord()) { |
| return RespondNow(Error(kIncognitoError)); |
| } |
| |
| if (!crx_file::id_util::IdIsValid(params->expected_id)) |
| return RespondNow(Error(kWebstoreInvalidIdError)); |
| |
| approval_ = g_pending_approvals.Get().PopApproval( |
| chrome_details_.GetProfile(), params->expected_id); |
| if (!approval_) { |
| return RespondNow(Error(kNoPreviousBeginInstallWithManifestError, |
| params->expected_id)); |
| } |
| |
| content::WebContents* web_contents = GetSenderWebContents(); |
| if (!web_contents) { |
| return RespondNow( |
| Error(function_constants::kCouldNotFindSenderWebContents)); |
| } |
| |
| scoped_active_install_.reset(new ScopedActiveInstall( |
| InstallTracker::Get(browser_context()), params->expected_id)); |
| |
| // Balanced in OnExtensionInstallSuccess() or OnExtensionInstallFailure(). |
| AddRef(); |
| |
| // The extension will install through the normal extension install flow, but |
| // the whitelist entry will bypass the normal permissions install dialog. |
| scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller( |
| chrome_details_.GetProfile(), this, web_contents, params->expected_id, |
| std::move(approval_), WebstoreInstaller::INSTALL_SOURCE_OTHER); |
| installer->Start(); |
| |
| return RespondLater(); |
| } |
| |
| void WebstorePrivateCompleteInstallFunction::OnExtensionInstallSuccess( |
| const std::string& id) { |
| OnInstallSuccess(id); |
| VLOG(1) << "Install success, sending response"; |
| Respond(NoArguments()); |
| |
| RecordWebstoreExtensionInstallResult(true); |
| |
| // Matches the AddRef in Run(). |
| Release(); |
| } |
| |
| void WebstorePrivateCompleteInstallFunction::OnExtensionInstallFailure( |
| const std::string& id, |
| const std::string& error, |
| WebstoreInstaller::FailureReason reason) { |
| if (test_webstore_installer_delegate) { |
| test_webstore_installer_delegate->OnExtensionInstallFailure( |
| id, error, reason); |
| } |
| |
| VLOG(1) << "Install failed, sending response"; |
| Respond(Error(error)); |
| |
| RecordWebstoreExtensionInstallResult(false); |
| |
| // Matches the AddRef in Run(). |
| Release(); |
| } |
| |
| void WebstorePrivateCompleteInstallFunction::OnInstallSuccess( |
| const std::string& id) { |
| if (test_webstore_installer_delegate) |
| test_webstore_installer_delegate->OnExtensionInstallSuccess(id); |
| } |
| |
| WebstorePrivateEnableAppLauncherFunction:: |
| WebstorePrivateEnableAppLauncherFunction() : chrome_details_(this) {} |
| |
| WebstorePrivateEnableAppLauncherFunction:: |
| ~WebstorePrivateEnableAppLauncherFunction() {} |
| |
| ExtensionFunction::ResponseAction |
| WebstorePrivateEnableAppLauncherFunction::Run() { |
| // TODO(crbug.com/822900): Check if this API is still in use and whether we |
| // can remove it. |
| return RespondNow(NoArguments()); |
| } |
| |
| WebstorePrivateGetBrowserLoginFunction:: |
| WebstorePrivateGetBrowserLoginFunction() : chrome_details_(this) {} |
| |
| WebstorePrivateGetBrowserLoginFunction:: |
| ~WebstorePrivateGetBrowserLoginFunction() {} |
| |
| ExtensionFunction::ResponseAction |
| WebstorePrivateGetBrowserLoginFunction::Run() { |
| GetBrowserLogin::Results::Info info; |
| info.login = IdentityManagerFactory::GetForProfile( |
| chrome_details_.GetProfile()->GetOriginalProfile()) |
| ->GetPrimaryAccountInfo() |
| .email; |
| return RespondNow(ArgumentList(GetBrowserLogin::Results::Create(info))); |
| } |
| |
| WebstorePrivateGetStoreLoginFunction:: |
| WebstorePrivateGetStoreLoginFunction() : chrome_details_(this) {} |
| |
| WebstorePrivateGetStoreLoginFunction:: |
| ~WebstorePrivateGetStoreLoginFunction() {} |
| |
| ExtensionFunction::ResponseAction WebstorePrivateGetStoreLoginFunction::Run() { |
| return RespondNow(ArgumentList(GetStoreLogin::Results::Create( |
| GetWebstoreLogin(chrome_details_.GetProfile())))); |
| } |
| |
| WebstorePrivateSetStoreLoginFunction:: |
| WebstorePrivateSetStoreLoginFunction() : chrome_details_(this) {} |
| |
| WebstorePrivateSetStoreLoginFunction:: |
| ~WebstorePrivateSetStoreLoginFunction() {} |
| |
| ExtensionFunction::ResponseAction WebstorePrivateSetStoreLoginFunction::Run() { |
| std::unique_ptr<SetStoreLogin::Params> params( |
| SetStoreLogin::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| SetWebstoreLogin(chrome_details_.GetProfile(), params->login); |
| return RespondNow(NoArguments()); |
| } |
| |
| WebstorePrivateGetWebGLStatusFunction::WebstorePrivateGetWebGLStatusFunction() |
| : feature_checker_(content::GpuFeatureChecker::Create( |
| gpu::GPU_FEATURE_TYPE_ACCELERATED_WEBGL, |
| base::Bind(&WebstorePrivateGetWebGLStatusFunction::OnFeatureCheck, |
| base::Unretained(this)))) {} |
| |
| WebstorePrivateGetWebGLStatusFunction:: |
| ~WebstorePrivateGetWebGLStatusFunction() {} |
| |
| ExtensionFunction::ResponseAction WebstorePrivateGetWebGLStatusFunction::Run() { |
| feature_checker_->CheckGpuFeatureAvailability(); |
| return RespondLater(); |
| } |
| |
| void WebstorePrivateGetWebGLStatusFunction::OnFeatureCheck( |
| bool feature_allowed) { |
| Respond(ArgumentList( |
| GetWebGLStatus::Results::Create(api::webstore_private::ParseWebGlStatus( |
| feature_allowed ? "webgl_allowed" : "webgl_blocked")))); |
| } |
| |
| WebstorePrivateGetIsLauncherEnabledFunction:: |
| WebstorePrivateGetIsLauncherEnabledFunction() {} |
| |
| WebstorePrivateGetIsLauncherEnabledFunction:: |
| ~WebstorePrivateGetIsLauncherEnabledFunction() {} |
| |
| ExtensionFunction::ResponseAction |
| WebstorePrivateGetIsLauncherEnabledFunction::Run() { |
| return RespondNow(ArgumentList( |
| GetIsLauncherEnabled::Results::Create(IsAppLauncherEnabled()))); |
| } |
| |
| WebstorePrivateIsInIncognitoModeFunction:: |
| WebstorePrivateIsInIncognitoModeFunction() : chrome_details_(this) {} |
| |
| WebstorePrivateIsInIncognitoModeFunction:: |
| ~WebstorePrivateIsInIncognitoModeFunction() {} |
| |
| ExtensionFunction::ResponseAction |
| WebstorePrivateIsInIncognitoModeFunction::Run() { |
| Profile* profile = chrome_details_.GetProfile(); |
| return RespondNow(ArgumentList(IsInIncognitoMode::Results::Create( |
| profile != profile->GetOriginalProfile()))); |
| } |
| |
| WebstorePrivateLaunchEphemeralAppFunction:: |
| WebstorePrivateLaunchEphemeralAppFunction() : chrome_details_(this) {} |
| |
| WebstorePrivateLaunchEphemeralAppFunction:: |
| ~WebstorePrivateLaunchEphemeralAppFunction() {} |
| |
| ExtensionFunction::ResponseAction |
| WebstorePrivateLaunchEphemeralAppFunction::Run() { |
| // Just fail as this is no longer supported. |
| return RespondNow(Error(kEphemeralAppLaunchingNotSupported)); |
| } |
| |
| WebstorePrivateGetEphemeralAppsEnabledFunction:: |
| WebstorePrivateGetEphemeralAppsEnabledFunction() {} |
| |
| WebstorePrivateGetEphemeralAppsEnabledFunction:: |
| ~WebstorePrivateGetEphemeralAppsEnabledFunction() {} |
| |
| ExtensionFunction::ResponseAction |
| WebstorePrivateGetEphemeralAppsEnabledFunction::Run() { |
| return RespondNow(ArgumentList(GetEphemeralAppsEnabled::Results::Create( |
| false))); |
| } |
| |
| WebstorePrivateIsPendingCustodianApprovalFunction:: |
| WebstorePrivateIsPendingCustodianApprovalFunction() |
| : chrome_details_(this) {} |
| |
| WebstorePrivateIsPendingCustodianApprovalFunction:: |
| ~WebstorePrivateIsPendingCustodianApprovalFunction() {} |
| |
| ExtensionFunction::ResponseAction |
| WebstorePrivateIsPendingCustodianApprovalFunction::Run() { |
| std::unique_ptr<IsPendingCustodianApproval::Params> params( |
| IsPendingCustodianApproval::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params); |
| |
| Profile* profile = chrome_details_.GetProfile(); |
| |
| if (!profile->IsSupervised()) { |
| return RespondNow(BuildResponse(false)); |
| } |
| |
| ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context()); |
| |
| const Extension* extension = |
| registry->GetExtensionById(params->id, ExtensionRegistry::EVERYTHING); |
| if (!extension) { |
| return RespondNow(BuildResponse(false)); |
| } |
| |
| ExtensionPrefs* extensions_prefs = ExtensionPrefs::Get(browser_context()); |
| |
| if (extensions_prefs->HasDisableReason( |
| params->id, disable_reason::DISABLE_PERMISSIONS_INCREASE)) { |
| return RespondNow(BuildResponse(true)); |
| } |
| |
| bool is_pending_approval = extensions_prefs->HasDisableReason( |
| params->id, disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED); |
| |
| return RespondNow(BuildResponse(is_pending_approval)); |
| } |
| |
| ExtensionFunction::ResponseValue |
| WebstorePrivateIsPendingCustodianApprovalFunction::BuildResponse(bool result) { |
| return OneArgument(std::make_unique<base::Value>(result)); |
| } |
| |
| WebstorePrivateGetReferrerChainFunction:: |
| WebstorePrivateGetReferrerChainFunction() |
| : chrome_details_(this) {} |
| |
| WebstorePrivateGetReferrerChainFunction:: |
| ~WebstorePrivateGetReferrerChainFunction() {} |
| |
| ExtensionFunction::ResponseAction |
| WebstorePrivateGetReferrerChainFunction::Run() { |
| Profile* profile = chrome_details_.GetProfile(); |
| if (!SafeBrowsingNavigationObserverManager::IsEnabledAndReady(profile)) |
| return RespondNow(ArgumentList( |
| api::webstore_private::GetReferrerChain::Results::Create(""))); |
| |
| content::WebContents* web_contents = GetSenderWebContents(); |
| if (!web_contents) { |
| return RespondNow(ErrorWithArguments( |
| api::webstore_private::GetReferrerChain::Results::Create(""), |
| kWebstoreUserCancelledError)); |
| } |
| |
| scoped_refptr<SafeBrowsingNavigationObserverManager> |
| navigation_observer_manager = g_browser_process->safe_browsing_service() |
| ->navigation_observer_manager(); |
| |
| safe_browsing::ReferrerChain referrer_chain; |
| SafeBrowsingNavigationObserverManager::AttributionResult result = |
| navigation_observer_manager->IdentifyReferrerChainByWebContents( |
| web_contents, kExtensionReferrerUserGestureLimit, &referrer_chain); |
| |
| // If the referrer chain is incomplete we'll append the most recent |
| // navigations to referrer chain for diagnostic purposes. This only happens if |
| // the user is not in incognito mode and has opted into extended reporting or |
| // Scout reporting. Otherwise, |CountOfRecentNavigationsToAppend| returns 0. |
| int recent_navigations_to_collect = |
| SafeBrowsingNavigationObserverManager::CountOfRecentNavigationsToAppend( |
| *profile, result); |
| if (recent_navigations_to_collect > 0) { |
| navigation_observer_manager->AppendRecentNavigations( |
| recent_navigations_to_collect, &referrer_chain); |
| } |
| |
| safe_browsing::ExtensionWebStoreInstallRequest request; |
| request.mutable_referrer_chain()->Swap(&referrer_chain); |
| request.mutable_referrer_chain_options()->set_recent_navigations_to_collect( |
| recent_navigations_to_collect); |
| |
| std::string serialized_referrer_proto = request.SerializeAsString(); |
| // Base64 encode the proto to avoid issues with base::Value rejecting strings |
| // which are not valid UTF8. |
| base::Base64Encode(serialized_referrer_proto, &serialized_referrer_proto); |
| return RespondNow( |
| ArgumentList(api::webstore_private::GetReferrerChain::Results::Create( |
| serialized_referrer_proto))); |
| } |
| |
| } // namespace extensions |