Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4506)

Unified Diff: chrome/browser/extensions/api/page_capture/page_capture_api.cc

Issue 2552203007: Public Sessions - prompt the user for pageCapture requests (Closed)
Patch Set: Unused variable Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/api/page_capture/page_capture_api.cc
diff --git a/chrome/browser/extensions/api/page_capture/page_capture_api.cc b/chrome/browser/extensions/api/page_capture/page_capture_api.cc
index 1e7c549d533f94e0f6f1c53a883d9c5680c85049..7de2d1086ba134effe59134f0b39f29d5cb41a07 100644
--- a/chrome/browser/extensions/api/page_capture/page_capture_api.cc
+++ b/chrome/browser/extensions/api/page_capture/page_capture_api.cc
@@ -5,13 +5,17 @@
#include "chrome/browser/extensions/api/page_capture/page_capture_api.h"
#include <limits>
-#include <memory>
+#include <utility>
#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/files/file_util.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+#include "chromeos/login/login_state.h"
+#include "components/prefs/scoped_user_pref_update.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
@@ -21,6 +25,9 @@
#include "content/public/browser/web_contents.h"
#include "content/public/common/mhtml_generation_params.h"
#include "extensions/common/extension_messages.h"
+#include "extensions/common/permissions/manifest_permission_set.h"
+#include "extensions/common/permissions/permission_set.h"
+#include "extensions/common/url_pattern_set.h"
using content::BrowserThread;
using content::ChildProcessSecurityPolicy;
@@ -37,6 +44,18 @@ const char kMHTMLGenerationFailedError[] = "Failed to generate MHTML.";
const char kTemporaryFileError[] = "Failed to create a temporary file.";
const char kTabClosedError[] = "Cannot find the tab for this request.";
+#if defined(OS_CHROMEOS)
+const char kUserDenied[] = "User denied request.";
+#endif
+
+bool IsPublicSession() {
+#if defined(OS_CHROMEOS)
+ if (chromeos::LoginState::IsInitialized())
+ return chromeos::LoginState::Get()->IsPublicSessionUser();
+#endif
+ return false;
+}
+
} // namespace
static PageCaptureSaveAsMHTMLFunction::TestDelegate* test_delegate_ = NULL;
@@ -63,6 +82,17 @@ bool PageCaptureSaveAsMHTMLFunction::RunAsync() {
AddRef(); // Balanced in ReturnFailure/ReturnSuccess()
+ // In Public Sessions, extensions (and apps) are force-installed by admin
+ // policy so the user does not get a chance to review the permissions for
+ // these extensions. This is not acceptable from a security/privacy
+ // standpoint, so when an extension uses the PageCapture API for the first
+ // time, we show the user a dialog where they can choose whether to allow the
+ // extension access to the API.
+ if (IsPublicSession()) {
+ HandlePermission();
+ return true;
+ }
+
BrowserThread::PostTask(
BrowserThread::FILE, FROM_HERE,
base::Bind(&PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile, this));
@@ -200,3 +230,98 @@ WebContents* PageCaptureSaveAsMHTMLFunction::GetWebContents() {
}
return web_contents;
}
+
+void PageCaptureSaveAsMHTMLFunction::HandlePermission() {
+#if defined(OS_CHROMEOS)
+ auto user_choice = UserChoiceGet();
+ if (user_choice == PermissionState::ALLOWED ||
+ user_choice == PermissionState::DENIED) {
+ ChainRunAsync();
+ return;
+ }
+ if (user_choice == PermissionState::NOT_PROMPTED) {
+ ShowPermissionPrompt();
+ }
+ // It's possible that several PageCapture requests come before user resolves
+ // the permission dialog, so setup a callback that gets called when pref
+ // changes (dialog is resolved).
+ pref_change_registrar_.reset(new PrefChangeRegistrar);
+ pref_change_registrar_->Init(GetPrefs());
+ // base::Unretained is safe here because PrefChangeRegistrar will unregister
+ // callback on destruction of this.
Devlin 2016/12/12 20:09:37 What if this object outlives the Prefs?
Ivan Šandrk 2016/12/13 16:32:47 Prefs are destoyed during logout. This object eith
+ pref_change_registrar_->Add(prefs::kPublicSessionPermissionsUserChoiceCache,
+ base::Bind(&PageCaptureSaveAsMHTMLFunction::ChainRunAsync,
+ base::Unretained(this)));
+#endif // defined(OS_CHROMEOS)
+}
+
+#if defined(OS_CHROMEOS)
+void PageCaptureSaveAsMHTMLFunction::ShowPermissionPrompt() {
+ extensions::APIPermissionSet new_apis;
+ new_apis.insert(extensions::APIPermission::kPageCapture);
+ auto permission_set = base::MakeUnique<extensions::PermissionSet>(
+ new_apis, extensions::ManifestPermissionSet(),
+ extensions::URLPatternSet(), extensions::URLPatternSet());
+
+ prompt_ = base::MakeUnique<ExtensionInstallPrompt>(GetWebContents());
Devlin 2016/12/12 20:09:37 GetWebContents() can return null here, which would
Ivan Šandrk 2016/12/13 16:32:47 Good catch. Replaced it with GetAssociatedWebConte
Devlin 2016/12/13 21:51:29 GetAssociatedWebContents() isn't particularly appr
Ivan Šandrk 2017/01/04 17:09:59 I'd personally show the permission dialog anyway,
+ prompt_->ShowDialog(
+ base::Bind(&PageCaptureSaveAsMHTMLFunction::ResolvePermissionPrompt,
+ this),
+ extension(),
+ nullptr, // Uses the extension icon.
+ base::MakeUnique<ExtensionInstallPrompt::Prompt>(
+ ExtensionInstallPrompt::PERMISSIONS_PROMPT),
+ std::move(permission_set),
+ ExtensionInstallPrompt::GetDefaultShowDialogCallback());
+
+ UserChoiceSet(PermissionState::SHOWN_PROMPT);
+}
+
+void PageCaptureSaveAsMHTMLFunction::ResolvePermissionPrompt(
+ ExtensionInstallPrompt::Result prompt_result) {
+ // Dispose of the prompt as it's not needed anymore.
+ prompt_.reset();
+
+ bool allowed = prompt_result == ExtensionInstallPrompt::Result::ACCEPTED;
+ UserChoiceSet(allowed ? PermissionState::ALLOWED : PermissionState::DENIED);
+}
+
+void PageCaptureSaveAsMHTMLFunction::ChainRunAsync() {
+ auto user_choice = UserChoiceGet();
+ // Permission was allowed/denied for some other extension, continue sleeping.
+ if (user_choice == PermissionState::SHOWN_PROMPT) {
+ return;
+ }
+
+ if (user_choice == PermissionState::DENIED) {
+ ReturnFailure(kUserDenied);
+ } else {
+ DCHECK(user_choice == PermissionState::ALLOWED);
+ BrowserThread::PostTask(
+ BrowserThread::FILE, FROM_HERE,
+ base::Bind(&PageCaptureSaveAsMHTMLFunction::CreateTemporaryFile, this));
+ }
+}
+
+PrefService* PageCaptureSaveAsMHTMLFunction::GetPrefs() {
+ return GetProfile()->GetOffTheRecordPrefs();
+}
+
+void PageCaptureSaveAsMHTMLFunction::UserChoiceSet(PermissionState value) {
+ DictionaryPrefUpdate update(GetPrefs(),
+ prefs::kPublicSessionPermissionsUserChoiceCache);
+ update->SetInteger(extension()->id(), value);
+}
+
+PageCaptureSaveAsMHTMLFunction::PermissionState
+PageCaptureSaveAsMHTMLFunction::UserChoiceGet() {
+ auto dictionary = GetPrefs()->GetDictionary(
+ prefs::kPublicSessionPermissionsUserChoiceCache);
+ int value;
+ if (!dictionary->GetInteger(extension()->id(), &value)) {
+ value = PermissionState::NOT_PROMPTED;
+ UserChoiceSet(static_cast<PermissionState>(value));
+ }
+ return static_cast<PermissionState>(value);
+}
+#endif // defined(OS_CHROMEOS)

Powered by Google App Engine
This is Rietveld 408576698