Skip to content

Commit af8423b

Browse files
Merge pull request #4494 from MicrosoftEdge/api-filetypepolicy
File Type Policy API
2 parents c9db958 + b19c17b commit af8423b

File tree

1 file changed

+277
-0
lines changed

1 file changed

+277
-0
lines changed

specs/FileTypePolicy.md

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
File Type Policy API
2+
===
3+
4+
# Background
5+
When saving a file with the standard SaveFilePicker (window.showSaveFilePicker),
6+
the user might receive a security alert, as the second prompt to confirm the unsafe file type.
7+
It's because the browser applies the [file type policies](https://learn.microsoft.com/en-us/deployedge/microsoft-edge-security-downloads-interruptions#file-types-requiring-a-gesture)
8+
to protect end users. However, in an app that is using WebView2, when end users try
9+
to save a file with a certain file extension, they usually can trust the
10+
host App, domain and file extension. So, we provide the App developers the
11+
File Type Policy API to manage the file type policies dynamically.
12+
13+
We'd appreciate your feedback.
14+
15+
# Description
16+
17+
We proposed the `CoreWebView2.SaveFileSecurityCheckStarting` event. As a developer, you can register a handler on
18+
this event to get the file path, file extension and document origin URI information. Then you can apply your own
19+
rules to allow save the file without a default file type policy security warning UI;
20+
to cancel the saving; and even to create your own UI to manage runtime
21+
file type policies.
22+
23+
# Examples
24+
## Win32 C++
25+
This example will register the event with two custom rules.
26+
- Suppressing file type policy, security dialog, and
27+
allows saving ".eml" files directly; when the URI is trusted.
28+
- Showing customized warning UI when saving ".iso" files.
29+
It allows to block the saving directly.
30+
```c++
31+
void ScenarioFileTypePolicy::AddCustomFileTypePolicies()
32+
{
33+
wil::com_ptr<ICoreWebView2> m_webview;
34+
EventRegistrationToken m_saveFileSecurityCheckStartingToken = {};
35+
auto m_webview2_23 = m_webView.try_query<ICoreWebView2_23>();
36+
// Register a handler for the `SaveFileSecurityCheckStarting` event.
37+
m_webView2_23->add_saveFileSecurityCheckStarting(
38+
Callback<ICoreWebView2SaveFileSecurityCheckStartingEventHandler>(
39+
[this](
40+
ICoreWebView2* sender,
41+
ICoreWebView2SaveFileSecurityCheckStartingEventArgs* args) -> HRESULT
42+
{
43+
// Get the file extension for file to be saved.
44+
wil::unique_cotaskmem_string extension;
45+
CHECK_FAILURE(args->get_FileExtension(&extension));
46+
// Get the document origin URI of file to be saved.
47+
wil::unique_cotaskmem_string uri;
48+
CHECK_FAILURE(args->get_DocumentOriginUri(&uri));
49+
// Convert the file extension value to lower case for
50+
// the case-insensitive comparison.
51+
std::wstring extension_lower = extension.get();
52+
std::transform(
53+
extension_lower.begin(), extension_lower.end(),
54+
extension_lower.begin(), ::towlower);
55+
// Set the `SuppressDefaultPolicy` property to skip the
56+
// default file type policy checking and a possible security
57+
// alert dialog for ".eml" file, when it's from a trusted URI.
58+
// This will consent to save the file.
59+
//
60+
// 'IsTrustedUri' should be your own helper method
61+
// to determine whether the URI is trusted.
62+
if (wcscmp(extension_lower.c_str(), L".eml") == 0 && IsTrustedUri(uri))
63+
{
64+
CHECK_FAILURE(args->put_SuppressDefaultPolicy(TRUE));
65+
}
66+
// Show customized warning UI for ".iso" file with
67+
// the deferral.
68+
if (wcscmp(extension_lower.c_str(), L".iso") == 0)
69+
{
70+
wil::com_ptr<ICoreWebView2Deferral> deferral;
71+
CHECK_FAILURE(args->GetDeferral(&deferral));
72+
73+
// 'm_appWindow' should be your main app window.
74+
m_appWindow->RunAsync(
75+
[args = wil::make_com_ptr(args), deferral]()
76+
{
77+
// Set the `CancelSave` property to cancel the saving
78+
// for ".iso" file directly. Save action will be aborted.
79+
//
80+
// You can let end users make decision on their save
81+
// action with your customized warning UI.
82+
// 'IsCancelledFromCustomizedWarningUI' should be
83+
// your helper method that retrieves result from the UI.
84+
if (IsCancelledFromCustomizedWarningUI())
85+
{
86+
CHECK_FAILURE(args->put_CancelSave(TRUE));
87+
}
88+
CHECK_FAILURE(deferral->Complete());
89+
});
90+
}
91+
return S_OK;
92+
})
93+
.Get(),
94+
&m_saveFileSecurityCheckStartingToken);
95+
}
96+
```
97+
98+
## .Net/ WinRT
99+
This example will register the event with two custom rules.
100+
- Suppressing file type policy, security dialog, and
101+
allows saving ".eml" files directly; when the URI is trusted.
102+
- Showing customized warning UI when saving ".iso" files.
103+
It allows to block the saving directly.
104+
```c#
105+
void AddCustomFileTypePolicies()
106+
{
107+
// Register a handler for the `SaveFileSecurityCheckStarting` event.
108+
webView.CoreWebView2.SaveFileSecurityCheckStarting += (sender, args) =>
109+
{
110+
if (string.Equals(args.FileExtension, ".eml", StringComparison.OrdinalIgnoreCase)
111+
&& IsTrustedUri(args.DocumentOriginUri))
112+
{
113+
// Set the `SuppressDefaultPolicy` property to skip the
114+
// default file type policy checking and a possible security
115+
// alert dialog for ".eml" file, when it's from a trusted URI.
116+
// This will consent to save the file.
117+
//
118+
// 'IsTrustedUri' should be your own helper method
119+
// to determine whether the URI is trusted.
120+
args.SuppressDefaultPolicy = true;
121+
}
122+
if (string.Equals(args.FileExtension, ".iso", StringComparison.OrdinalIgnoreCase))
123+
{
124+
CoreWebView2Deferral deferral = args.GetDeferral();
125+
System.Threading.SynchronizationContext.Current.Post((_) =>
126+
{
127+
using (deferral)
128+
{
129+
if (IsCancelledFromCustomizedWarningUI())
130+
{
131+
// Set the `CancelSave` property to cancel the saving
132+
// for ".iso" file directly. Save action will be aborted.
133+
//
134+
// You can let end users make decision on their save
135+
// action with your customized warning UI.
136+
// 'IsCancelledFromCustomizedWarningUI' should be
137+
// your helper method that retrieves result from the UI.
138+
args.CancelSave = true;
139+
}
140+
}
141+
}, null);
142+
}
143+
};
144+
}
145+
```
146+
147+
# API Details
148+
## Win32 C++
149+
```c++
150+
interface ICoreWebView2_23 : ICoreWebView2_22 {
151+
/// Adds an event handler for the `SaveFileSecurityCheckStarting` event.
152+
/// If the default save file picker is used to save a file, for
153+
/// example, client using the File System API `showSaveFilePicker`;
154+
/// this event will be raised during system FileTypePolicy
155+
/// checking the dangerous file extension list.
156+
///
157+
/// Developers can specify their own logic for determining whether
158+
/// to allow a particular type of file to be saved from the document origin URI.
159+
/// Developers can also determine the save decision based on other criteria.
160+
/// Here are two properties in `ICoreWebView2SaveFileSecurityCheckStartingEventArgs`
161+
/// to manage the decision, `CancelSave` and `SuppressDefaultPolicy`.
162+
///
163+
/// Table of Properties' value and result:
164+
///
165+
/// | CancelSave | SuppressDefaultPolicy | Result
166+
/// | ---------- | ------ | ---------------------
167+
/// | False | False | Perform the default policy check. It may show the
168+
/// | | | security warning UI if the file extension is
169+
/// | | | dangerous.
170+
/// | ---------- | ------ | ---------------------
171+
/// | False | True | Skip the default policy check and the possible
172+
/// | | | security warning. Start saving or downloading.
173+
/// | ---------- | ------ | ---------------------
174+
/// | True | Any | Skip the default policy check and the possible
175+
/// | | | security warning. Abort save or download.
176+
HRESULT add_SaveFileSecurityCheckStarting(
177+
[in] ICoreWebView2SaveFileSecurityCheckStartingEventHandler* eventHandler,
178+
[out] EventRegistrationToken* token);
179+
180+
/// Removes an event handler previously added with `add_SaveFileSecurityCheckStarting`.
181+
HRESULT remove_SaveFileSecurityCheckStarting(
182+
[in] EventRegistrationToken token);
183+
}
184+
185+
186+
/// The event args for `SaveFileSecurityCheckStarting` event.
187+
interface ICoreWebView2SaveFileSecurityCheckStartingEventArgs : IUnknown {
188+
/// Gets the `CancelSave` property.
189+
[propget] HRESULT CancelSave([out, retval] BOOL* value);
190+
191+
/// Set whether to cancel the upcoming save/download. `TRUE` means the action
192+
/// will be cancelled before validations in default policy.
193+
///
194+
/// The default value is `FALSE`.
195+
[propput] HRESULT CancelSave([in] BOOL value);
196+
197+
/// Get the extension of file to be saved.
198+
///
199+
/// The file extension is the extension portion of the FilePath,
200+
/// preserving original case.
201+
///
202+
/// Only final extension with period "." will be provided. For example,
203+
/// "*.tar.gz" is a double extension, where the ".gz" will be its
204+
/// final extension.
205+
///
206+
/// File extension can be empty, if the file name has no extension
207+
/// at all.
208+
[propget] HRESULT FileExtension([out, retval] LPWSTR* value);
209+
210+
/// Get the full path of file to be saved. This includes the
211+
/// file name and extension.
212+
///
213+
/// This method doesn't provide path validation, the returned
214+
/// string may longer than MAX_PATH.
215+
[propget] HRESULT FilePath([out, retval] LPWSTR* value);
216+
217+
/// Gets the `SuppressDefaultPolicy` property.
218+
[propget] HRESULT SuppressDefaultPolicy([out, retval] BOOL* value);
219+
220+
/// Set if the default policy checking and security warning will be
221+
/// suppressed. `TRUE` means it will be suppressed.
222+
///
223+
/// The default value is `FALSE`.
224+
[propput] HRESULT SuppressDefaultPolicy([in] BOOL value);
225+
226+
/// The document origin URI of this file save operation.
227+
[propget] HRESULT DocumentOriginUri([out, retval] LPWSTR* value);
228+
229+
/// Returns an `ICoreWebView2Deferral` object. Use this operation to complete
230+
/// the SaveFileSecurityCheckStartingEvent.
231+
///
232+
/// The default policy checking and any default UI will be blocked temporarily,
233+
/// saving file to local won't start, until the deferral is completed.
234+
HRESULT GetDeferral(
235+
[out, retval] ICoreWebView2Deferral** value
236+
);
237+
}
238+
239+
/// Receives `SaveFileSecurityCheckStarting` events.
240+
interface ICoreWebView2SaveFileSecurityCheckStartingEventHandler : IUnknown {
241+
/// Provides the event args for the corresponding event.
242+
HRESULT Invoke(
243+
[in] ICoreWebView2* sender,
244+
[in] ICoreWebView2SaveFileSecurityCheckStartingEventArgs* args);
245+
}
246+
```
247+
248+
## .Net/ WinRT
249+
```c# (but really MIDL3)
250+
namespace Microsoft.Web.WebView2.Core
251+
{
252+
253+
runtimeclass CoreWebView2SaveFileSecurityCheckStartingEventArgs;
254+
runtimeclass CoreWebView2;
255+
256+
runtimeclass CoreWebView2SaveFileSecurityCheckStartingEventArgs
257+
{
258+
Boolean CancelSave { get; set; };
259+
String FileExtension { get; };
260+
String FilePath { get; };
261+
Boolean SuppressDefaultPolicy { get; set; };
262+
String DocumentOriginUri { get; };
263+
Windows.Foundation.Deferral GetDeferral();
264+
};
265+
266+
runtimeclass CoreWebView2
267+
{
268+
// ...
269+
270+
[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2_23")]
271+
{
272+
event Windows.Foundation.TypedEventHandler
273+
<CoreWebView2, CoreWebView2SaveFileSecurityCheckStartingEventArgs> SaveFileSecurityCheckStarting;
274+
}
275+
};
276+
}
277+
```

0 commit comments

Comments
 (0)