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

Side by Side Diff: chrome/browser/chromeos/extensions/public_session_permission_helper.cc

Issue 2552203007: Public Sessions - prompt the user for pageCapture requests (Closed)
Patch Set: Const ref for passing PermissionIDSet around Created 3 years, 10 months 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/extensions/public_session_permission_helper.h"
6
7 #include <algorithm>
8 #include <map>
9 #include <memory>
10 #include <utility>
11 #include <vector>
12
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/lazy_instance.h"
16 #include "base/macros.h"
17 #include "base/memory/ptr_util.h"
18 #include "chrome/browser/extensions/extension_install_prompt.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/web_contents.h"
21 #include "extensions/common/extension.h"
22 #include "extensions/common/extension_id.h"
23 #include "extensions/common/permissions/manifest_permission_set.h"
24 #include "extensions/common/permissions/permission_set.h"
25 #include "extensions/common/url_pattern_set.h"
26
27 namespace extensions {
28 namespace permission_helper {
29
30 namespace {
31
32 base::LazyInstance<std::unique_ptr<ExtensionInstallPrompt>>::Leaky
33 g_extension_install_prompt_for_testing = LAZY_INSTANCE_INITIALIZER;
34
35 std::unique_ptr<ExtensionInstallPrompt> CreateExtensionInstallPrompt(
36 content::WebContents* web_contents) {
37 if (g_extension_install_prompt_for_testing.Get()) {
Andrew T Wilson (Slow) 2017/02/10 13:47:51 I'm not a huge fan of this pattern, especially sin
Ivan Šandrk 2017/02/10 16:46:18 I've tried using a factory approach. Seems good?
38 std::unique_ptr<ExtensionInstallPrompt> prompt =
39 std::move(g_extension_install_prompt_for_testing.Get());
40 g_extension_install_prompt_for_testing = LAZY_INSTANCE_INITIALIZER;
41 return prompt;
42 }
43 return base::MakeUnique<ExtensionInstallPrompt>(web_contents);
44 }
45
46 // This class is the internal implementation of HandlePermissionRequest(). It
47 // contains the actual prompt showing and resolving logic, and it caches the
48 // user choices.
49 class PublicSessionPermissionHelper {
50 public:
51 PublicSessionPermissionHelper();
52 PublicSessionPermissionHelper(PublicSessionPermissionHelper&& other);
53 ~PublicSessionPermissionHelper();
54
55 void HandlePermissionRequestImpl(const Extension& extension,
56 const PermissionIDSet& requested_permissions,
57 content::WebContents* web_contents,
58 const RequestResolvedCallback& callback);
59
60 private:
61 void ResolvePermissionPrompt(
62 const ExtensionInstallPrompt* prompt,
63 const PermissionIDSet& unprompted_permissions,
64 ExtensionInstallPrompt::Result prompt_result);
65
66 PermissionIDSet FilterAllowedPermissions(
67 const PermissionIDSet& permissions);
68
69 struct RequestCallback {
70 RequestCallback(const RequestResolvedCallback& callback,
71 const PermissionIDSet& permission_list);
72 RequestCallback(const RequestCallback& other);
73 ~RequestCallback();
74 RequestResolvedCallback callback;
75 PermissionIDSet permission_list;
76 };
77 using RequestCallbackList = std::vector<RequestCallback>;
78
79 std::set<std::unique_ptr<ExtensionInstallPrompt>> prompts_;
80 PermissionIDSet prompted_permission_set_;
81 PermissionIDSet allowed_permission_set_;
82 PermissionIDSet denied_permission_set_;
83 RequestCallbackList callbacks_;
84
85 DISALLOW_COPY_AND_ASSIGN(PublicSessionPermissionHelper);
86 };
87
88 PublicSessionPermissionHelper::PublicSessionPermissionHelper() {}
89
90 PublicSessionPermissionHelper::PublicSessionPermissionHelper(
91 PublicSessionPermissionHelper&& other) = default;
92
93 PublicSessionPermissionHelper::~PublicSessionPermissionHelper() {}
94
95 void PublicSessionPermissionHelper::HandlePermissionRequestImpl(
96 const Extension& extension,
97 const PermissionIDSet& requested_permissions,
98 content::WebContents* web_contents,
99 const RequestResolvedCallback& callback) {
100 CHECK(web_contents);
101
102 PermissionIDSet unresolved_permissions = PermissionIDSet::Difference(
103 requested_permissions, allowed_permission_set_);
104 unresolved_permissions = PermissionIDSet::Difference(
105 unresolved_permissions, denied_permission_set_);
106 if (unresolved_permissions.empty()) {
107 // All requested permissions are already resolved.
108 callback.Run(FilterAllowedPermissions(requested_permissions));
109 return;
110 }
111
112 // Since not all permissions are resolved yet, queue the callback to be called
113 // when all of them are resolved.
114 callbacks_.push_back(RequestCallback(callback, requested_permissions));
115
116 PermissionIDSet unprompted_permissions = PermissionIDSet::Difference(
117 unresolved_permissions, prompted_permission_set_);
118 if (unprompted_permissions.empty()) {
119 // Some permissions aren't resolved yet, but they are currently being
120 // prompted for, so no need to show a prompt.
121 return;
122 }
123
124 // Some permissions need prompting, setup the prompt and show it.
125 APIPermissionSet new_apis;
126 for (const auto& permission : unprompted_permissions) {
127 prompted_permission_set_.insert(permission.id());
128 new_apis.insert(permission.id());
129 }
130 auto permission_set = base::MakeUnique<PermissionSet>(
131 new_apis, ManifestPermissionSet(), URLPatternSet(), URLPatternSet());
132 auto prompt = CreateExtensionInstallPrompt(web_contents);
133 // This Unretained is safe because the lifetime of this object is until
134 // process exit.
135 prompt->ShowDialog(
136 base::Bind(&PublicSessionPermissionHelper::ResolvePermissionPrompt,
137 base::Unretained(this), prompt.get(),
138 std::move(unprompted_permissions)),
139 &extension,
140 nullptr, // Use the extension icon.
141 base::MakeUnique<ExtensionInstallPrompt::Prompt>(
142 ExtensionInstallPrompt::PERMISSIONS_PROMPT),
143 std::move(permission_set),
144 ExtensionInstallPrompt::GetDefaultShowDialogCallback());
145 prompts_.insert(std::move(prompt));
146 }
147
148 void PublicSessionPermissionHelper::ResolvePermissionPrompt(
149 const ExtensionInstallPrompt* prompt,
150 const PermissionIDSet& unprompted_permissions,
151 ExtensionInstallPrompt::Result prompt_result) {
152 const bool allowed =
153 prompt_result == ExtensionInstallPrompt::Result::ACCEPTED;
154 for (const auto& permission : unprompted_permissions) {
155 prompted_permission_set_.erase(permission.id());
156 if (allowed)
157 allowed_permission_set_.insert(permission.id());
158 else
159 denied_permission_set_.insert(permission.id());
160 }
161
162 // Here a list of callbacks to be invoked is created first from callbacks_,
163 // then those callbacks are invoked later because a callback can change
164 // callbacks_ while we're traversing them.
165 RequestCallbackList callbacks_to_invoke;
166 for (auto callback = callbacks_.begin(); callback != callbacks_.end(); ) {
167 if (prompted_permission_set_.ContainsAnyID(callback->permission_list)) {
168 // The request is still waiting on other permissions to be resolved - wait
169 // until all of them are resolved before calling the callback.
170 callback++;
171 continue;
172 }
173 callbacks_to_invoke.push_back(std::move(*callback));
174 callback = callbacks_.erase(callback);
175 }
176 for (auto callback = callbacks_to_invoke.begin();
177 callback != callbacks_to_invoke.end(); callback++) {
178 callback->callback.Run(FilterAllowedPermissions(callback->permission_list));
179 }
180
181 // Dispose of the prompt as it's not needed anymore.
182 auto iter = std::find_if(
183 prompts_.begin(), prompts_.end(),
184 [prompt](const std::unique_ptr<ExtensionInstallPrompt>& check) {
185 return check.get() == prompt;
186 });
187 DCHECK(iter != prompts_.end());
188 prompts_.erase(iter);
189 }
190
191 PermissionIDSet PublicSessionPermissionHelper::FilterAllowedPermissions(
192 const PermissionIDSet& permissions) {
193 PermissionIDSet allowed_permissions;
194 for (auto iter = permissions.begin(); iter != permissions.end(); iter++) {
195 if (allowed_permission_set_.ContainsID(*iter)) {
196 allowed_permissions.insert(iter->id());
197 }
198 }
199 return allowed_permissions;
200 }
201
202 PublicSessionPermissionHelper::RequestCallback::RequestCallback(
203 const RequestResolvedCallback& callback,
204 const PermissionIDSet& permission_list)
205 : callback(callback),
206 permission_list(permission_list) {}
207
208 PublicSessionPermissionHelper::RequestCallback::RequestCallback(
209 const RequestCallback& other) = default;
210
211 PublicSessionPermissionHelper::RequestCallback::~RequestCallback() {}
212
213 base::LazyInstance<std::map<ExtensionId, PublicSessionPermissionHelper>>::Leaky
214 g_helpers = LAZY_INSTANCE_INITIALIZER;
215
216 } // namespace
217
218 void HandlePermissionRequest(const Extension& extension,
219 const PermissionIDSet& requested_permissions,
220 content::WebContents* web_contents,
221 const RequestResolvedCallback& callback) {
222 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
223 return g_helpers.Get()[extension.id()].HandlePermissionRequestImpl(
224 extension, requested_permissions, web_contents, callback);
225 }
226
227 void ResetPermissionsForTesting() {
228 g_helpers = LAZY_INSTANCE_INITIALIZER;
229 }
230
231 void SetExtensionInstallPromptForTesting(
232 ExtensionInstallPrompt* extension_install_prompt) {
233 g_extension_install_prompt_for_testing.Get() =
234 base::WrapUnique<ExtensionInstallPrompt>(extension_install_prompt);
235 }
236
237 } // namespace permission_helper
238 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698