Skip to content

Commit 5d75c8e

Browse files
added cpp and c# api examples
1 parent e7c6b10 commit 5d75c8e

1 file changed

Lines changed: 126 additions & 4 deletions

File tree

specs/IFramePermissionRequested.md

Lines changed: 126 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,57 @@
11
# Background
2+
The WebView2 team has been asked to provide support for handling permission
3+
requests that come from iframes. These permission requests occur when content
4+
within the iframe are requesting access to priveleged resources. The permission
5+
request types that we support are: Microphone, Camera, Geolocation,
6+
Notifications, Other Sensors, and Clipboard Read.
27

8+
We currently have a `PermissionRequested` event on our `CoreWebView2` which is
9+
raised for any permission requests (either from webview or iframes). However,
10+
our customers do not have a way to determine whether the request has come from
11+
the webview or an iframe and handle these cases seperately. As such, we plan to
12+
expand our `CoreWebView2Frame` API to include the `PermissionRequested` event
13+
as well.
14+
15+
A current limitation of our `CoreWebView2Frame` API is that it only supports top
16+
level iframes. Any nested iframes will not have a `CoreWebView2Frame`
17+
associated with them.
18+
19+
In this document we describe the updated API. We'd appreciate your feedback.
320

421
# Description
22+
We propose extending `CoreWebView2Frame` to include the `PermissionRequested`
23+
event. This event will be raised whenever an iframe requests permission to
24+
priveleged resources.
25+
26+
Additionally, we propose extending `CoreWebView2PermissionRequestedEventArgs`
27+
to include a `Handled` property.
528

29+
To maintain backwards compatibility, by default we plan to raise
30+
`PermissionRequested` on both `CoreWebView2Frame` and `CoreWebView2`. The
31+
`CoreWebView2Frame` event handlers will be invoked first,
32+
before the `CoreWebView2` event handlers. If `Handled` is set true as part of
33+
the `CoreWebView2Frame` event handlers, then the `PermissionRequested` event
34+
will not be raised on the `CoreWebView2`, and its event handlers will not be
35+
invoked.
36+
37+
In the case of a nested frame requesting permission, we will raise the event
38+
off of the top level iframe. This is due to the previously mentioned limitation
39+
of not having `CoreWebView2Frame`'s for nested iframes.
640

741
# Examples
842
## C++: Regestering IFrame Permission Requested Handler
9-
1043
``` cpp
1144
wil::com_ptr<ICoreWebView2> m_webview;
45+
std::map<std::tuple<std::wstring, COREWEBVIEW2_PERMISSION_KIND, BOOL>, bool>
46+
m_cached_permissions;
1247

1348
EventRegistrationToken m_frameCreatedToken = {};
1449
EventRegistrationToken m_permissionRequestedToken = {};
1550

51+
// Example Use Case - an app may want to specify that all iframes should
52+
// create a message box to prompt the user for approval on a permission request.
53+
// The approval state could be cached so that future requests are automatically
54+
// handled if they have been requested previously.
1655
void RegisterIFramePermissionRequestedHandler()
1756
{
1857
webview4 = m_webview.try_query<ICoreWebView2_4>();
@@ -81,7 +120,6 @@ void RegisterIFramePermissionRequestedHandler()
81120
nullptr, message.c_str(), L"Permission Request",
82121
MB_YESNOCANCEL | MB_ICONWARNING);
83122

84-
85123
COREWEBVIEW2_PERMISSION_STATE state =
86124
COREWEBVIEW2_PERMISSION_STATE_DEFAULT;
87125

@@ -141,15 +179,99 @@ static void PutHandled(ICoreWebView2PermissionRequestedEventArgs* args)
141179
// PermissionRequested event off the CoreWebView2.
142180
wil::com_ptr<ICoreWebView2PermissionRequestedEventArgs2> args2;
143181
CHECK_FAILURE(args->QueryInterface(IID_PPV_ARGS(&args2)));
144-
if (args2) {
182+
if (args2)
183+
{
145184
CHECK_FAILURE(args2->put_Handled(true));
146185
}
147186
}
148187
```
149188
150-
## C#: TBD
189+
## C#: Regestering IFrame Permission Requested Handler
151190
```c#
191+
private WebView2 m_webview;
192+
Dictionary<Tuple<string, CoreWebView2PermissionKind, bool>, bool> m_cached_permissions;
193+
194+
// Example Use Case - an app may want to specify that all iframes should
195+
// create a message box to prompt the user for approval on a permission request.
196+
// The approval state could be cached so that future requests are automatically
197+
// handled if they have been requested previously.
198+
void RegisterIFramePermissionRequestedHandler()
199+
{
200+
m_webview.CoreWebView2.FrameCreated += (sender, CoreWebView2FrameCreatedEventArgs args) =>
201+
{
202+
args.Frame.PermissionRequested += (frameSender, CoreWebView2PermissionRequestedEventArgs permissionArgs) =>
203+
{
204+
var cached_key = new Tuple<string, CoreWebView2PermissionKind, bool>
205+
(permissionArgs.Uri, permissionArgs.Kind, permissionArgs.IsUserInitiated);
206+
207+
if (m_cached_permissions.ContainsKey(cached_key))
208+
{
209+
bool allow = m_cached_permissions[cached_key].Item2;
210+
if (allow)
211+
{
212+
permissionArgs.State = CoreWebView2PermissionKind.Allow;
213+
}
214+
else
215+
{
216+
permissionArgs.State = CoreWebView2PermissionKind.Deny;
217+
}
218+
219+
permissionArgs.Handled = true;
220+
return;
221+
}
222+
223+
string message = "An iframe has requested device permission for ";
224+
message += NameOfPermissionKind(permissionArgs.Kind);
225+
message += " to the website at ";
226+
message += permissionArgs.Uri;
227+
message += "\n\n";
228+
message += "Do you want to grant permission?\n"
229+
message +=
230+
(permissionArgs.UserInitiated
231+
? "This request came from a user gesture."
232+
: "This request did not come from a user gesture.");
233+
234+
var selection = MessageBox.Show(message, "iframe PermissionRequest", MessageBoxButton.YesNoCancel);
235+
if (selection == MessageBoxResult.Yes)
236+
{
237+
permissionArgs.State = CoreWebView2PermissionState.Allow;
238+
m_cached_permissions[cached_key] = false;
239+
}
240+
else if (selection == MessageBoxResult.No)
241+
{
242+
permissionArgs.State = CoreWebView2PermissionState.Deny;
243+
m_cached_permissions[cached_key] = true;
244+
}
245+
else
246+
{
247+
permissionArgs.State = CoreWebView2PermissionState.Default;
248+
}
249+
250+
permissionArgs.Handled = true;
251+
};
252+
};
253+
}
152254
255+
string NameOfPermissionKind(CoreWebView2PermissionKind kind)
256+
{
257+
switch (kind)
258+
{
259+
case CoreWebView2PermissionKind.Microphone:
260+
return "Microphone";
261+
case CoreWebView2PermissionKind.Camera:
262+
return "Camera";
263+
case CoreWebView2PermissionKind.Geolocation:
264+
return "Geolocation";
265+
case CoreWebView2PermissionKind.Notifications:
266+
return "Notifications";
267+
case CoreWebView2PermissionKind.OtherSensors:
268+
return "Generic Sensors";
269+
case CoreWebView2PermissionKind.ClipboardRead:
270+
return "Clipboard Read";
271+
default:
272+
return "Unknown resources";
273+
}
274+
}
153275
```
154276

155277
# API Details

0 commit comments

Comments
 (0)