Skip to content

Commit

Permalink
[iOS] WKContentView's paste configuration should only contain valid UTIs
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=267081
rdar://120446511

Reviewed by Aditya Keerthi.

We currently add `WebArchivePboardType` (whose raw value is `Apple Web Archive pasteboard type`) to
the list of acceptable UTIs when setting a `UIPasteConfiguration` on the content view. This can
cause a crash when attempting to show the edit menu in some third party apps (e.g. Gmail),
underneath UIKit code that assumes `-[UTType _typeWithIdentifier:allowUndeclared:]` will always
return a non-null value for each acceptable UTI.

UIKit is adding null checks in rdar://119912158 to handle this case gracefully, but we shouldn't be
adding these invalid UTIs in the first place. This patch splits `supportedRichTextPasteboardTypes`
into a separate `supportedRichTextPasteboardTypesForPasteConfiguration` helper that returns
`com.apple.webarchive` rather than `WebArchivePboardType`, and uses that when creating the paste
configuration; for compatibility with `-canPerformAction:withSender:`, we continue adding the legacy
`WebArchivePboardType` alongside the declared UTI in `supportedRichTextPasteboardTypes`.

Test: UIPasteboardTests.PasteConfigurationContainsValidUniformTypeIdentifiers

* Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView setUpInteraction]):
(-[WKContentView supportedPasteboardTypesForCurrentSelection]):
* Tools/TestWebKitAPI/Tests/ios/UIPasteboardTests.mm:

We use a regex here instead of checking `-[UTType _typeWithIdentifier:allowUndeclared:]`, since that
SPI method actually returns a non-null result in the iOS simulator (as opposed to a real device,
where it returns `nil`). To make the test agnostic to this difference, we check whether or not the
UTI is valid by following the syntax rules in "Uniform Type Identifier Concepts" (on
developer.apple.com):

```
You may use the Roman alphabet in upper and lower case (A–Z, a–z), the digits 0 through 9, the dot
(“.”), and the hyphen (“-”). […] Uniform type identifiers may also contain any of the Unicode
characters greater than U+007F.
```

Canonical link: https://commits.webkit.org/272655@main
  • Loading branch information
whsieh committed Jan 4, 2024
1 parent 6f1c962 commit 7d47c1f
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 6 deletions.
23 changes: 17 additions & 6 deletions Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Original file line number Diff line number Diff line change
Expand Up @@ -323,25 +323,36 @@ @interface WKContentView (UITextSelectionDisplayInteraction) <UITextSelectionDis
return supportedTypes.get().get();
}

static NSArray<NSString *> *supportedRichTextPasteboardTypes()
static NSArray<NSString *> *supportedRichTextPasteboardTypesForPasteConfiguration()
{
static NeverDestroyed supportedTypes = [] {
auto types = adoptNS([[NSMutableArray alloc] init]);
[types addObject:WebCore::WebArchivePboardType];
[types addObject:UTTypeWebArchive.identifier];
[types addObjectsFromArray:UIPasteboardTypeListImage];
[types addObjectsFromArray:supportedPlainTextPasteboardTypes()];
return types;
}();
return supportedTypes.get().get();
}

static NSArray<NSString *> *supportedRichTextPasteboardTypes()
{
static NeverDestroyed supportedTypes = [] {
auto types = adoptNS([[NSMutableArray alloc] init]);
[types addObject:WebCore::WebArchivePboardType];
[types addObjectsFromArray:supportedRichTextPasteboardTypesForPasteConfiguration()];
return types;
}();
return supportedTypes.get().get();
}

#if HAVE(UI_PASTE_CONFIGURATION)

static NSArray<NSString *> *supportedRichTextPasteboardTypesWithAttachments()
static NSArray<NSString *> *supportedRichTextPasteboardTypesWithAttachmentsForPasteConfiguration()
{
static NeverDestroyed supportedTypes = [] {
auto types = adoptNS([[NSMutableArray alloc] init]);
[types addObjectsFromArray:supportedRichTextPasteboardTypes()];
[types addObjectsFromArray:supportedRichTextPasteboardTypesForPasteConfiguration()];
[types addObjectsFromArray:WebCore::Pasteboard::supportedFileUploadPasteboardTypes()];
return types;
}();
Expand Down Expand Up @@ -1377,8 +1388,8 @@ - (void)setUpInteraction
#if HAVE(UI_PASTE_CONFIGURATION)
self.pasteConfiguration = adoptNS([[UIPasteConfiguration alloc] initWithAcceptableTypeIdentifiers:[&] {
if (_page->preferences().attachmentElementEnabled())
return WebKit::supportedRichTextPasteboardTypesWithAttachments();
return WebKit::supportedRichTextPasteboardTypes();
return WebKit::supportedRichTextPasteboardTypesWithAttachmentsForPasteConfiguration();
return WebKit::supportedRichTextPasteboardTypesForPasteConfiguration();
}()]).get();
#endif

Expand Down
30 changes: 30 additions & 0 deletions Tools/TestWebKitAPI/Tests/ios/UIPasteboardTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#import <UIKit/UIPasteboard.h>
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
#import <WebKit/WKPreferencesPrivate.h>
#import <WebKit/WKWebViewConfigurationPrivate.h>
#import <WebKit/WKWebViewPrivate.h>
#import <pal/ios/ManagedConfigurationSoftLink.h>

Expand Down Expand Up @@ -502,6 +503,35 @@ - (BOOL)isURLManaged:(NSURL *)url

#endif // PLATFORM(IOS) || PLATFORM(VISION)

#if HAVE(UI_PASTE_CONFIGURATION)

TEST(UIPasteboardTests, PasteConfigurationContainsValidUniformTypeIdentifiers)
{
RetainPtr regex = [NSRegularExpression regularExpressionWithPattern:@"^[A-Za-z0-9\\-.\\u0080-\\uFFFF]+$" options:0 error:nil];
auto verifyPasteConfigurationContainsValidUniformTypeIdentifiers = [regex](TestWKWebView *webView) {
[webView synchronouslyLoadTestPageNamed:@"simple"];
for (NSString *typeIdentifier in webView.textInputContentView.pasteConfiguration.acceptableTypeIdentifiers) {
for (NSString *component in [typeIdentifier componentsSeparatedByString:@"."]) {
BOOL numberOfMatches = [regex numberOfMatchesInString:component options:0 range:NSMakeRange(0, component.length)];
EXPECT_GT(numberOfMatches, 0);
if (!numberOfMatches)
NSLog(@"Failed: invalid UTI component '%@' in '%@'", component, typeIdentifier);
}
}
};

auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]);
verifyPasteConfigurationContainsValidUniformTypeIdentifiers(webView.get());

auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
[configuration _setAttachmentElementEnabled:YES];

auto webViewWithAttachmentElementEnabled = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 100, 100) configuration:configuration.get()]);
verifyPasteConfigurationContainsValidUniformTypeIdentifiers(webViewWithAttachmentElementEnabled.get());
}

#endif // HAVE(UI_PASTE_CONFIGURATION)

} // namespace TestWebKitAPI

#endif

0 comments on commit 7d47c1f

Please sign in to comment.