Skip to content

Commit faba9a2

Browse files
finished api section
1 parent 5d75c8e commit faba9a2

1 file changed

Lines changed: 106 additions & 86 deletions

File tree

specs/IFramePermissionRequested.md

Lines changed: 106 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,40 @@
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
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
44
within the iframe are requesting access to priveleged resources. The permission
5-
request types that we support are: Microphone, Camera, Geolocation,
5+
request types that we support are: Microphone, Camera, Geolocation,
66
Notifications, Other Sensors, and Clipboard Read.
77

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.
8+
We currently have a [PermissionRequested](https://docs.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2permissionrequestedeventargs?view=webview2-1.0.1020.30)
9+
event on our `CoreWebView2` which is raised for any permission requests
10+
(either from webview or iframes). However, our customers do not have a way to
11+
determine whether the request has come from the webview or an iframe and
12+
handle these cases seperately. As such, we plan to expand our
13+
`CoreWebView2Frame` API to include the `PermissionRequested` event.
1414

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.
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.
1818

1919
In this document we describe the updated API. We'd appreciate your feedback.
2020

2121
# Description
2222
We propose extending `CoreWebView2Frame` to include the `PermissionRequested`
23-
event. This event will be raised whenever an iframe requests permission to
24-
priveleged resources.
23+
event. This event will be raised whenever an iframe requests permission to
24+
priveleged resources.
2525

2626
Additionally, we propose extending `CoreWebView2PermissionRequestedEventArgs`
2727
to include a `Handled` property.
2828

2929
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,
30+
`PermissionRequested` on both `CoreWebView2Frame` and `CoreWebView2`. The
31+
`CoreWebView2Frame` event handlers will be invoked first,
3232
before the `CoreWebView2` event handlers. If `Handled` is set true as part of
3333
the `CoreWebView2Frame` event handlers, then the `PermissionRequested` event
3434
will not be raised on the `CoreWebView2`, and its event handlers will not be
3535
invoked.
3636

37-
In the case of a nested frame requesting permission, we will raise the event
37+
In the case of a nested iframe requesting permission, we will raise the event
3838
off of the top level iframe. This is due to the previously mentioned limitation
3939
of not having `CoreWebView2Frame`'s for nested iframes.
4040

@@ -43,20 +43,23 @@ of not having `CoreWebView2Frame`'s for nested iframes.
4343
``` cpp
4444
wil::com_ptr<ICoreWebView2> m_webview;
4545
std::map<std::tuple<std::wstring, COREWEBVIEW2_PERMISSION_KIND, BOOL>, bool>
46-
m_cached_permissions;
46+
m_cachedPermissions;
4747

4848
EventRegistrationToken m_frameCreatedToken = {};
4949
EventRegistrationToken m_permissionRequestedToken = {};
5050

5151
// Example Use Case - an app may want to specify that all iframes should
5252
// create a message box to prompt the user for approval on a permission request.
5353
// The approval state could be cached so that future requests are automatically
54-
// handled if they have been requested previously.
54+
// handled if they have been requested previously.
5555
void RegisterIFramePermissionRequestedHandler()
5656
{
5757
webview4 = m_webview.try_query<ICoreWebView2_4>();
5858
if (webview4)
5959
{
60+
// Note that FrameCreated will only ever be raised for top level iframes.
61+
// However, any permission requests from nested iframes will be raised
62+
// from the top level frame.
6063
CHECK_FAILURE(webview4->add_FrameCreated(
6164
Callback<ICoreWebView2FrameCreatedEventHandler>(
6265
[this](ICoreWebView2* sender, ICoreWebView2FrameCreatedEventArgs* args) -> HRESULT {
@@ -79,15 +82,15 @@ void RegisterIFramePermissionRequestedHandler()
7982
CHECK_FAILURE(args->get_IsUserInitiated(&userInitiated));
8083
CHECK_FAILURE(args->get_Uri(&uri));
8184

82-
auto cached_key = std::tuple<
85+
auto cachedKey = std::tuple<
8386
std::wstring, COREWEBVIEW2_PERMISSION_KIND, BOOL>(
8487
std::wstring(uri.get()), kind, userInitiated);
8588

86-
auto cached_permission =
87-
m_cached_permissions.find(cached_key);
88-
if (cached_permission != m_cached_permissions.end())
89+
auto cachedPermission =
90+
m_cachedPermissions.find(cachedKey);
91+
if (cachedPermission != m_cachedPermissions.end())
8992
{
90-
bool allow = cached_permission->second;
93+
bool allow = cachedPermission->second;
9194
if (allow)
9295
{
9396
CHECK_FAILURE(args->put_State(
@@ -105,7 +108,7 @@ void RegisterIFramePermissionRequestedHandler()
105108

106109
std::wstring message =
107110
L"An iframe has requested device permission for ";
108-
message += SettingsComponent::NameOfPermissionKind(kind);
111+
message += NameOfPermissionKind(kind);
109112
message += L" to the website at ";
110113
message += uri.get();
111114
message += L"?\n\n";
@@ -125,12 +128,12 @@ void RegisterIFramePermissionRequestedHandler()
125128

126129
if (response == IDYES)
127130
{
128-
m_cached_permissions[cached_key] = true;
131+
m_cachedPermissions[cachedKey] = true;
129132
state = COREWEBVIEW2_PERMISSION_STATE_ALLOW;
130133
}
131134
else if (response == IDNO)
132135
{
133-
m_cached_permissions[cached_key] = false;
136+
m_cachedPermissions[cachedKey] = false;
134137
state = COREWEBVIEW2_PERMISSION_STATE_DENY;
135138
}
136139

@@ -141,7 +144,6 @@ void RegisterIFramePermissionRequestedHandler()
141144
}).Get(),
142145
&m_PermissionRequestedToken));
143146
}
144-
145147
return S_OK;
146148
}).Get(),
147149
&m_FrameCreatedToken));
@@ -152,20 +154,20 @@ static PCWSTR NameOfPermissionKind(COREWEBVIEW2_PERMISSION_KIND kind)
152154
{
153155
switch (kind)
154156
{
155-
case COREWEBVIEW2_PERMISSION_KIND_MICROPHONE:
156-
return L"Microphone";
157-
case COREWEBVIEW2_PERMISSION_KIND_CAMERA:
158-
return L"Camera";
159-
case COREWEBVIEW2_PERMISSION_KIND_GEOLOCATION:
160-
return L"Geolocation";
161-
case COREWEBVIEW2_PERMISSION_KIND_NOTIFICATIONS:
162-
return L"Notifications";
163-
case COREWEBVIEW2_PERMISSION_KIND_OTHER_SENSORS:
164-
return L"Generic Sensors";
165-
case COREWEBVIEW2_PERMISSION_KIND_CLIPBOARD_READ:
166-
return L"Clipboard Read";
167-
default:
168-
return L"Unknown resources";
157+
case COREWEBVIEW2_PERMISSION_KIND_MICROPHONE:
158+
return L"Microphone";
159+
case COREWEBVIEW2_PERMISSION_KIND_CAMERA:
160+
return L"Camera";
161+
case COREWEBVIEW2_PERMISSION_KIND_GEOLOCATION:
162+
return L"Geolocation";
163+
case COREWEBVIEW2_PERMISSION_KIND_NOTIFICATIONS:
164+
return L"Notifications";
165+
case COREWEBVIEW2_PERMISSION_KIND_OTHER_SENSORS:
166+
return L"Generic Sensors";
167+
case COREWEBVIEW2_PERMISSION_KIND_CLIPBOARD_READ:
168+
return L"Clipboard Read";
169+
default:
170+
return L"Unknown resources";
169171
}
170172
}
171173

@@ -179,7 +181,7 @@ static void PutHandled(ICoreWebView2PermissionRequestedEventArgs* args)
179181
// PermissionRequested event off the CoreWebView2.
180182
wil::com_ptr<ICoreWebView2PermissionRequestedEventArgs2> args2;
181183
CHECK_FAILURE(args->QueryInterface(IID_PPV_ARGS(&args2)));
182-
if (args2)
184+
if (args2)
183185
{
184186
CHECK_FAILURE(args2->put_Handled(true));
185187
}
@@ -189,60 +191,55 @@ static void PutHandled(ICoreWebView2PermissionRequestedEventArgs* args)
189191
## C#: Regestering IFrame Permission Requested Handler
190192
```c#
191193
private WebView2 m_webview;
192-
Dictionary<Tuple<string, CoreWebView2PermissionKind, bool>, bool> m_cached_permissions;
194+
Dictionary<Tuple<string, CoreWebView2PermissionKind, bool>, bool> m_cachedPermissions;
193195
194196
// Example Use Case - an app may want to specify that all iframes should
195197
// create a message box to prompt the user for approval on a permission request.
196198
// The approval state could be cached so that future requests are automatically
197-
// handled if they have been requested previously.
199+
// handled if they have been requested previously.
198200
void RegisterIFramePermissionRequestedHandler()
199201
{
200-
m_webview.CoreWebView2.FrameCreated += (sender, CoreWebView2FrameCreatedEventArgs args) =>
202+
m_webview.CoreWebView2.FrameCreated += (sender, frameCreatedArgs) =>
201203
{
202-
args.Frame.PermissionRequested += (frameSender, CoreWebView2PermissionRequestedEventArgs permissionArgs) =>
204+
frameCreatedArgs.Frame.PermissionRequested += (frameSender, permissionArgs) =>
203205
{
204-
var cached_key = new Tuple<string, CoreWebView2PermissionKind, bool>
205-
(permissionArgs.Uri, permissionArgs.Kind, permissionArgs.IsUserInitiated);
206+
var cachedKey = Tuple.Create(permissionArgs.Uri,
207+
permissionArgs.PermissionKind, permissionArgs.IsUserInitiated);
206208
207-
if (m_cached_permissions.ContainsKey(cached_key))
209+
if (m_cachedPermissions.ContainsKey(cachedKey))
208210
{
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-
}
211+
bool allow = m_cachedPermissions[cachedKey];
212+
permissionArgs.State = allow ? CoreWebView2PermissionState.Allow
213+
: CoreWebView2PermissionState.Deny;
218214
219215
permissionArgs.Handled = true;
220216
return;
221-
}
222-
217+
}
218+
223219
string message = "An iframe has requested device permission for ";
224-
message += NameOfPermissionKind(permissionArgs.Kind);
220+
message += NameOfPermissionKind(permissionArgs.PermissionKind);
225221
message += " to the website at ";
226222
message += permissionArgs.Uri;
227223
message += "\n\n";
228-
message += "Do you want to grant permission?\n"
224+
message += "Do you want to grant permission?\n";
229225
message +=
230-
(permissionArgs.UserInitiated
231-
? "This request came from a user gesture."
232-
: "This request did not come from a user gesture.");
226+
(permissionArgs.IsUserInitiated
227+
? "This request came from a user gesture."
228+
: "This request did not come from a user gesture.");
233229
234-
var selection = MessageBox.Show(message, "iframe PermissionRequest", MessageBoxButton.YesNoCancel);
235-
if (selection == MessageBoxResult.Yes)
230+
var selection = MessageBox.Show(message, "iframe PermissionRequest",
231+
MessageBoxButton.YesNoCancel);
232+
if (selection == MessageBoxResult.Yes)
236233
{
237234
permissionArgs.State = CoreWebView2PermissionState.Allow;
238-
m_cached_permissions[cached_key] = false;
235+
m_cachedPermissions[cachedKey] = true;
239236
}
240-
else if (selection == MessageBoxResult.No)
237+
else if (selection == MessageBoxResult.No)
241238
{
242239
permissionArgs.State = CoreWebView2PermissionState.Deny;
243-
m_cached_permissions[cached_key] = true;
240+
m_cachedPermissions[cachedKey] = false;
244241
}
245-
else
242+
else
246243
{
247244
permissionArgs.State = CoreWebView2PermissionState.Default;
248245
}
@@ -256,20 +253,20 @@ string NameOfPermissionKind(CoreWebView2PermissionKind kind)
256253
{
257254
switch (kind)
258255
{
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";
256+
case CoreWebView2PermissionKind.Microphone:
257+
return "Microphone";
258+
case CoreWebView2PermissionKind.Camera:
259+
return "Camera";
260+
case CoreWebView2PermissionKind.Geolocation:
261+
return "Geolocation";
262+
case CoreWebView2PermissionKind.Notifications:
263+
return "Notifications";
264+
case CoreWebView2PermissionKind.OtherSensors:
265+
return "Generic Sensors";
266+
case CoreWebView2PermissionKind.ClipboardRead:
267+
return "Clipboard Read";
268+
default:
269+
return "Unknown resources";
273270
}
274271
}
275272
```
@@ -339,5 +336,28 @@ interface ICoreWebView2PermissionRequestedEventArgs2: ICoreWebView2PermissionReq
339336

340337
## C#
341338
```c#
339+
namespace Microsoft.Web.WebView2.Core
340+
{
341+
runtimeclass CoreWebView2PermissionRequestedEventArgs
342+
{
343+
344+
[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2PermissionRequestedEventArgs2")]
345+
{
346+
// ICoreWebView2PermissionRequestedEventArgs2 members
347+
[doc_string("The host may set this flag to `TRUE` to prevent the `PermissionRequested` event from firing on the CoreWebView2 as well.\nBy default, both the `PermissionRequested` on the CoreWebView2Frame and CoreWebView2 will be fired.")]
348+
Boolean Handled { get; set; };
349+
}
342350

351+
}
352+
353+
runtimeclass CoreWebView2Frame
354+
{
355+
[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2Frame2")]
356+
{
357+
// ICoreWebView2Frame2 members
358+
[doc_string("PermissionRequested is raised when content in an IFrame requests permission to access some priveleged resources.\nIf a deferral is not taken on the event args, the subsequent scripts are blocked until the event handler returns. If a deferral is taken, the scripts are blocked until the deferral is completed.")]
359+
event Windows.Foundation.TypedEventHandler<CoreWebView2Frame, CoreWebView2PermissionRequestedEventArgs> PermissionRequested;
360+
}
361+
362+
}
343363
```

0 commit comments

Comments
 (0)