Skip to content

Commit 49e9928

Browse files
[webview_flutter_wkwebview] Fixes crash where the native AuthenticationChallengeResponse could not be found for auth requests (flutter#8707)
This changes the return type of the auth callback method to a `List` instead of an `AuthenticationChallengeResponse`. `@ProxyApi` doesn't support tuples or data classes, so this was the simplest to switch to. Fixes flutter#162437
1 parent 9744c9d commit 49e9928

File tree

13 files changed

+227
-165
lines changed

13 files changed

+227
-165
lines changed

packages/webview_flutter/webview_flutter_wkwebview/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 3.18.3
2+
3+
* Fixes crash where the native `AuthenticationChallengeResponse` could not be found for auth
4+
requests.
5+
16
## 3.18.2
27

38
* Updates generated pigeon code to ensure the internal wrapper immediately sends constructor calls.

packages/webview_flutter/webview_flutter_wkwebview/darwin/Tests/NavigationDelegateProxyAPITests.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,9 @@ class NavigationDelegateProxyAPITests: XCTestCase {
131131

132132
XCTAssertEqual(api.didReceiveAuthenticationChallengeArgs, [webView, challenge])
133133
XCTAssertEqual(dispositionResult, .useCredential)
134-
XCTAssertNotNil(credentialResult)
134+
XCTAssertEqual(credentialResult?.user, "user1")
135+
XCTAssertEqual(credentialResult?.password, "password1")
136+
XCTAssertEqual(credentialResult?.persistence, URLCredential.Persistence.none)
135137
}
136138
}
137139

@@ -219,17 +221,17 @@ class TestNavigationDelegateApi: PigeonApiProtocolWKNavigationDelegate {
219221
challenge challengeArg: URLAuthenticationChallenge,
220222
completion: @escaping (
221223
Result<
222-
webview_flutter_wkwebview.AuthenticationChallengeResponse,
224+
[Any?],
223225
webview_flutter_wkwebview.PigeonError
224226
>
225227
) -> Void
226228
) {
227229
didReceiveAuthenticationChallengeArgs = [webViewArg, challengeArg]
228230
completion(
229-
.success(
230-
AuthenticationChallengeResponse(
231-
disposition: .useCredential,
232-
credential: URLCredential(user: "user", password: "password", persistence: .none))))
231+
.success([
232+
UrlSessionAuthChallengeDisposition.useCredential,
233+
["user": "user1", "password": "password1", "persistence": UrlCredentialPersistence.none],
234+
]))
233235
}
234236
}
235237

packages/webview_flutter/webview_flutter_wkwebview/darwin/webview_flutter_wkwebview/Sources/webview_flutter_wkwebview/NavigationDelegateProxyAPIDelegate.swift

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,46 @@ public class NavigationDelegateImpl: NSObject, WKNavigationDelegate {
230230
}
231231
#endif
232232

233+
func handleAuthChallengeSuccessResponse(_ response: [Any?]) -> (
234+
URLSession.AuthChallengeDisposition, URLCredential?
235+
) {
236+
let disposition = response[0] as! UrlSessionAuthChallengeDisposition
237+
var nativeDisposition: URLSession.AuthChallengeDisposition
238+
switch disposition {
239+
case .useCredential:
240+
nativeDisposition = .useCredential
241+
case .performDefaultHandling:
242+
nativeDisposition = .performDefaultHandling
243+
case .cancelAuthenticationChallenge:
244+
nativeDisposition = .cancelAuthenticationChallenge
245+
case .rejectProtectionSpace:
246+
nativeDisposition = .rejectProtectionSpace
247+
case .unknown:
248+
print(
249+
self.registrar.createUnknownEnumError(withEnum: disposition).localizedDescription)
250+
nativeDisposition = .cancelAuthenticationChallenge
251+
}
252+
let credentialMap = response[1] as? [AnyHashable?: AnyHashable?]
253+
var credential: URLCredential?
254+
if let credentialMap = credentialMap {
255+
let nativePersistence: URLCredential.Persistence
256+
switch credentialMap["persistence"] as! UrlCredentialPersistence {
257+
case .none:
258+
nativePersistence = .none
259+
case .forSession:
260+
nativePersistence = .forSession
261+
case .permanent:
262+
nativePersistence = .permanent
263+
case .synchronizable:
264+
nativePersistence = .synchronizable
265+
}
266+
credential = URLCredential(
267+
user: credentialMap["user"] as! String,
268+
password: credentialMap["password"] as! String, persistence: nativePersistence)
269+
}
270+
return (nativeDisposition, credential)
271+
}
272+
233273
#if compiler(>=6.0)
234274
public func webView(
235275
_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge,
@@ -244,7 +284,8 @@ public class NavigationDelegateImpl: NSObject, WKNavigationDelegate {
244284
DispatchQueue.main.async {
245285
switch result {
246286
case .success(let response):
247-
completionHandler(response.disposition, response.credential)
287+
let nativeValues = self.handleAuthChallengeSuccessResponse(response)
288+
completionHandler(nativeValues.0, nativeValues.1)
248289
case .failure(let error):
249290
completionHandler(.cancelAuthenticationChallenge, nil)
250291
onFailure("WKNavigationDelegate.didReceiveAuthenticationChallenge", error)
@@ -266,7 +307,8 @@ public class NavigationDelegateImpl: NSObject, WKNavigationDelegate {
266307
DispatchQueue.main.async {
267308
switch result {
268309
case .success(let response):
269-
completionHandler(response.disposition, response.credential)
310+
let nativeValues = self.handleAuthChallengeSuccessResponse(response)
311+
completionHandler(nativeValues.0, nativeValues.1)
270312
case .failure(let error):
271313
completionHandler(.cancelAuthenticationChallenge, nil)
272314
onFailure("WKNavigationDelegate.didReceiveAuthenticationChallenge", error)

packages/webview_flutter/webview_flutter_wkwebview/darwin/webview_flutter_wkwebview/Sources/webview_flutter_wkwebview/WebKitLibrary.g.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3992,10 +3992,13 @@ protocol PigeonApiProtocolWKNavigationDelegate {
39923992
pigeonInstance pigeonInstanceArg: WKNavigationDelegate, webView webViewArg: WKWebView,
39933993
completion: @escaping (Result<Void, PigeonError>) -> Void)
39943994
/// Asks the delegate to respond to an authentication challenge.
3995+
///
3996+
/// Returns a List with a `UrlSessionAuthChallengeDisposition` and a nullable
3997+
/// `URLCredential`.
39953998
func didReceiveAuthenticationChallenge(
39963999
pigeonInstance pigeonInstanceArg: WKNavigationDelegate, webView webViewArg: WKWebView,
39974000
challenge challengeArg: URLAuthenticationChallenge,
3998-
completion: @escaping (Result<AuthenticationChallengeResponse, PigeonError>) -> Void)
4001+
completion: @escaping (Result<[Any?], PigeonError>) -> Void)
39994002
}
40004003

40014004
final class PigeonApiWKNavigationDelegate: PigeonApiProtocolWKNavigationDelegate {
@@ -4333,10 +4336,13 @@ final class PigeonApiWKNavigationDelegate: PigeonApiProtocolWKNavigationDelegate
43334336
}
43344337

43354338
/// Asks the delegate to respond to an authentication challenge.
4339+
///
4340+
/// Returns a List with a `UrlSessionAuthChallengeDisposition` and a nullable
4341+
/// `URLCredential`.
43364342
func didReceiveAuthenticationChallenge(
43374343
pigeonInstance pigeonInstanceArg: WKNavigationDelegate, webView webViewArg: WKWebView,
43384344
challenge challengeArg: URLAuthenticationChallenge,
4339-
completion: @escaping (Result<AuthenticationChallengeResponse, PigeonError>) -> Void
4345+
completion: @escaping (Result<[Any?], PigeonError>) -> Void
43404346
) {
43414347
if pigeonRegistrar.ignoreCallsToDart {
43424348
completion(
@@ -4369,7 +4375,7 @@ final class PigeonApiWKNavigationDelegate: PigeonApiProtocolWKNavigationDelegate
43694375
code: "null-error",
43704376
message: "Flutter api returned null value for non-null return value.", details: "")))
43714377
} else {
4372-
let result = listResponse[0] as! AuthenticationChallengeResponse
4378+
let result = listResponse[0] as! [Any?]
43734379
completion(.success(result))
43744380
}
43754381
}

packages/webview_flutter/webview_flutter_wkwebview/lib/src/common/web_kit.g.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4326,6 +4326,9 @@ class WKNavigationDelegate extends NSObject {
43264326

43274327
/// Asks the delegate to respond to an authentication challenge.
43284328
///
4329+
/// Returns a List with a `UrlSessionAuthChallengeDisposition` and a nullable
4330+
/// `URLCredential`.
4331+
///
43294332
/// For the associated Native object to be automatically garbage collected,
43304333
/// it is required that the implementation of this `Function` doesn't have a
43314334
/// strong reference to the encapsulating class instance. When this `Function`
@@ -4343,7 +4346,7 @@ class WKNavigationDelegate extends NSObject {
43434346
///
43444347
/// Alternatively, [PigeonInstanceManager.removeWeakReference] can be used to
43454348
/// release the associated Native object manually.
4346-
final Future<AuthenticationChallengeResponse> Function(
4349+
final Future<List<Object?>> Function(
43474350
WKNavigationDelegate pigeon_instance,
43484351
WKWebView webView,
43494352
URLAuthenticationChallenge challenge,
@@ -4387,7 +4390,7 @@ class WKNavigationDelegate extends NSObject {
43874390
WKNavigationDelegate pigeon_instance,
43884391
WKWebView webView,
43894392
)? webViewWebContentProcessDidTerminate,
4390-
Future<AuthenticationChallengeResponse> Function(
4393+
Future<List<Object?>> Function(
43914394
WKNavigationDelegate pigeon_instance,
43924395
WKWebView webView,
43934396
URLAuthenticationChallenge challenge,
@@ -4693,7 +4696,7 @@ class WKNavigationDelegate extends NSObject {
46934696
assert(arg_challenge != null,
46944697
'Argument for dev.flutter.pigeon.webview_flutter_wkwebview.WKNavigationDelegate.didReceiveAuthenticationChallenge was null, expected non-null URLAuthenticationChallenge.');
46954698
try {
4696-
final AuthenticationChallengeResponse output =
4699+
final List<Object?> output =
46974700
await (didReceiveAuthenticationChallenge ??
46984701
arg_pigeon_instance!.didReceiveAuthenticationChallenge)
46994702
.call(arg_pigeon_instance!, arg_webView!, arg_challenge!);

packages/webview_flutter/webview_flutter_wkwebview/lib/src/legacy/web_kit_webview_widget.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,10 @@ class WebKitWebViewPlatformController extends WebViewPlatformController {
193193
return NavigationResponsePolicy.allow;
194194
},
195195
didReceiveAuthenticationChallenge: (_, __, ___) async {
196-
return AuthenticationChallengeResponse(
197-
disposition:
198-
UrlSessionAuthChallengeDisposition.performDefaultHandling,
199-
);
196+
return <Object?>[
197+
UrlSessionAuthChallengeDisposition.performDefaultHandling,
198+
null,
199+
];
200200
},
201201
);
202202
},
@@ -751,7 +751,7 @@ class WebViewWidgetProxy {
751751
WKWebView webView,
752752
WKNavigationResponse navigationResponse,
753753
) decidePolicyForNavigationResponse,
754-
required Future<AuthenticationChallengeResponse> Function(
754+
required Future<List<Object?>> Function(
755755
WKNavigationDelegate,
756756
WKWebView webView,
757757
URLAuthenticationChallenge challenge,

packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_proxy.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class WebKitProxy {
102102
WKNavigationDelegate,
103103
WKWebView,
104104
)? webViewWebContentProcessDidTerminate,
105-
required Future<AuthenticationChallengeResponse> Function(
105+
required Future<List<Object?>> Function(
106106
WKNavigationDelegate,
107107
WKWebView,
108108
URLAuthenticationChallenge,

packages/webview_flutter/webview_flutter_wkwebview/lib/src/webkit_webview_controller.dart

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,43 +1213,44 @@ class WebKitNavigationDelegate extends PlatformNavigationDelegate {
12131213
final String host = protectionSpace.host;
12141214
final String? realm = protectionSpace.realm;
12151215

1216-
final Completer<AuthenticationChallengeResponse> responseCompleter =
1217-
Completer<AuthenticationChallengeResponse>();
1216+
final Completer<List<Object?>> responseCompleter =
1217+
Completer<List<Object?>>();
12181218

12191219
callback(
12201220
HttpAuthRequest(
12211221
host: host,
12221222
realm: realm,
12231223
onProceed: (WebViewCredential credential) {
1224-
final AuthenticationChallengeResponse response =
1225-
proxy.newAuthenticationChallengeResponse(
1226-
disposition: UrlSessionAuthChallengeDisposition.useCredential,
1227-
credential: URLCredential.withUser(
1228-
user: credential.user,
1229-
password: credential.password,
1230-
persistence: UrlCredentialPersistence.forSession,
1231-
),
1224+
responseCompleter.complete(
1225+
<Object?>[
1226+
UrlSessionAuthChallengeDisposition.useCredential,
1227+
<String, Object?>{
1228+
'user': credential.user,
1229+
'password': credential.password,
1230+
'persistence': UrlCredentialPersistence.forSession,
1231+
},
1232+
],
12321233
);
1233-
responseCompleter.complete(response);
12341234
},
12351235
onCancel: () {
1236-
final AuthenticationChallengeResponse response =
1237-
proxy.newAuthenticationChallengeResponse(
1238-
disposition: UrlSessionAuthChallengeDisposition
1239-
.cancelAuthenticationChallenge,
1236+
responseCompleter.complete(
1237+
<Object?>[
1238+
UrlSessionAuthChallengeDisposition
1239+
.cancelAuthenticationChallenge,
1240+
null,
1241+
],
12401242
);
1241-
responseCompleter.complete(response);
12421243
},
12431244
),
12441245
);
12451246

12461247
return responseCompleter.future;
12471248
}
12481249

1249-
return AuthenticationChallengeResponse(
1250-
disposition:
1251-
UrlSessionAuthChallengeDisposition.performDefaultHandling,
1252-
);
1250+
return <Object?>[
1251+
UrlSessionAuthChallengeDisposition.performDefaultHandling,
1252+
null,
1253+
];
12531254
},
12541255
);
12551256
}

packages/webview_flutter/webview_flutter_wkwebview/pigeons/web_kit.dart

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -745,9 +745,22 @@ abstract class WKNavigationDelegate extends NSObject {
745745
/// Tells the delegate that the web view’s content process was terminated.
746746
void Function(WKWebView webView)? webViewWebContentProcessDidTerminate;
747747

748+
// TODO(bparrishMines): This method should return an
749+
// `AuthenticationChallengeResponse` once the cause of
750+
// https://github.com/flutter/flutter/issues/162437 can be found and fixed.
748751
/// Asks the delegate to respond to an authentication challenge.
752+
///
753+
/// This return value expects a List with:
754+
///
755+
/// 1. `UrlSessionAuthChallengeDisposition`
756+
/// 2. A nullable map to instantiate a `URLCredential`. The map structure is
757+
/// [
758+
/// "user": "<nonnull String username>",
759+
/// "password": "<nonnull String user password>",
760+
/// "persistence": <nonnull enum value of `UrlCredentialPersistence`>,
761+
/// ]
749762
@async
750-
late AuthenticationChallengeResponse Function(
763+
late List<Object?> Function(
751764
WKWebView webView,
752765
URLAuthenticationChallenge challenge,
753766
) didReceiveAuthenticationChallenge;

packages/webview_flutter/webview_flutter_wkwebview/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: webview_flutter_wkwebview
22
description: A Flutter plugin that provides a WebView widget based on Apple's WKWebView control.
33
repository: https://github.com/flutter/packages/tree/main/packages/webview_flutter/webview_flutter_wkwebview
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+webview%22
5-
version: 3.18.2
5+
version: 3.18.3
66

77
environment:
88
sdk: ^3.5.0

0 commit comments

Comments
 (0)