Skip to content

Commit d0d3040

Browse files
authored
fix(auth, web): fix null safety issue in typing JS Interop (#12250)
* fix(auth, web): fix null safety issue in typing JS Interop * more fix * more fixes * more null safety
1 parent e655ff3 commit d0d3040

File tree

7 files changed

+78
-60
lines changed

7 files changed

+78
-60
lines changed

packages/firebase_auth/firebase_auth/example/.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
/build/
3232

3333
# Web related
34-
lib/generated_plugin_registrant.dart
3534

3635
# Exceptions to above rules.
3736
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages

packages/firebase_auth/firebase_auth_web/lib/firebase_auth_web.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ class FirebaseAuthWeb extends FirebaseAuthPlatform {
307307

308308
@override
309309
String get languageCode {
310-
return delegate.languageCode;
310+
return delegate.languageCode ?? 'en';
311311
}
312312

313313
@override

packages/firebase_auth/firebase_auth_web/lib/src/interop/auth.dart

+53-33
Original file line numberDiff line numberDiff line change
@@ -122,33 +122,38 @@ class User extends UserInfo<auth_interop.UserJsImpl> {
122122
///
123123
/// It forces refresh regardless of token expiration if [forceRefresh]
124124
/// parameter is `true`.
125-
Future<String> getIdToken([bool forceRefresh = false]) =>
126-
jsObject.getIdToken(forceRefresh.toJS).toDart as Future<String>;
125+
Future<String> getIdToken([bool forceRefresh = false]) => jsObject
126+
.getIdToken(forceRefresh.toJS)
127+
.toDart
128+
.then((value) => value! as String);
127129

128130
/// Links the user account with the given credentials, and returns any
129131
/// available additional user information, such as user name.
130132
Future<UserCredential> linkWithCredential(
131133
auth_interop.OAuthCredential? credential) =>
132-
(auth_interop.linkWithCredential(jsObject, credential).toDart
133-
as Future<auth_interop.UserCredentialJsImpl>)
134-
.then(UserCredential.fromJsObject);
134+
auth_interop.linkWithCredential(jsObject, credential).toDart.then(
135+
(value) => UserCredential.fromJsObject(
136+
value! as auth_interop.UserCredentialJsImpl));
135137

136138
/// Links the user account with the given [phoneNumber] in E.164 format
137139
/// (e.g. +16505550101) and [applicationVerifier].
138140
Future<ConfirmationResult> linkWithPhoneNumber(
139141
String phoneNumber, ApplicationVerifier applicationVerifier) =>
140-
(auth_interop
141-
.linkWithPhoneNumber(
142-
jsObject, phoneNumber.toJS, applicationVerifier.jsObject)
143-
.toDart as Future<auth_interop.ConfirmationResultJsImpl>)
144-
.then(ConfirmationResult.fromJsObject);
142+
auth_interop
143+
.linkWithPhoneNumber(
144+
jsObject, phoneNumber.toJS, applicationVerifier.jsObject)
145+
.toDart
146+
.then((value) => ConfirmationResult.fromJsObject(
147+
value! as auth_interop.ConfirmationResultJsImpl));
145148

146149
/// Links the authenticated [provider] to the user account using
147150
/// a pop-up based OAuth flow.
148151
/// It returns the [UserCredential] information if linking is successful.
149-
Future<UserCredential> linkWithPopup(AuthProvider provider) =>
150-
auth_interop.linkWithPopup(jsObject, provider.jsObject).toDart
151-
as Future<UserCredential>;
152+
Future<UserCredential> linkWithPopup(AuthProvider provider) => auth_interop
153+
.linkWithPopup(jsObject, provider.jsObject)
154+
.toDart
155+
.then((value) => UserCredential.fromJsObject(
156+
value! as auth_interop.UserCredentialJsImpl));
152157

153158
/// Links the authenticated [provider] to the user account using
154159
/// a full-page redirect flow.
@@ -159,8 +164,11 @@ class User extends UserInfo<auth_interop.UserJsImpl> {
159164
/// available additional user information, such as user name.
160165
Future<UserCredential> reauthenticateWithCredential(
161166
auth_interop.OAuthCredential credential) =>
162-
auth_interop.reauthenticateWithCredential(jsObject, credential).toDart
163-
as Future<UserCredential>;
167+
auth_interop
168+
.reauthenticateWithCredential(jsObject, credential)
169+
.toDart
170+
.then((value) => UserCredential.fromJsObject(
171+
value! as auth_interop.UserCredentialJsImpl));
164172

165173
/// Re-authenticates a user using a fresh credential.
166174
/// Use before operations such as [updatePassword] that require tokens
@@ -172,14 +180,19 @@ class User extends UserInfo<auth_interop.UserJsImpl> {
172180
auth_interop
173181
.reauthenticateWithPhoneNumber(
174182
jsObject, phoneNumber.toJS, applicationVerifier.jsObject)
175-
.toDart as Future<ConfirmationResult>;
183+
.toDart
184+
.then((value) => ConfirmationResult.fromJsObject(
185+
value! as auth_interop.ConfirmationResultJsImpl));
176186

177187
/// Reauthenticates a user with the specified provider using
178188
/// a pop-up based OAuth flow.
179189
/// It returns the [UserCredential] information if reauthentication is successful.
180190
Future<UserCredential> reauthenticateWithPopup(AuthProvider provider) =>
181-
auth_interop.reauthenticateWithPopup(jsObject, provider.jsObject).toDart
182-
as Future<UserCredential>;
191+
auth_interop
192+
.reauthenticateWithPopup(jsObject, provider.jsObject)
193+
.toDart
194+
.then((value) => UserCredential.fromJsObject(
195+
value! as auth_interop.UserCredentialJsImpl));
183196

184197
/// Reauthenticates a user with the specified OAuth [provider] using
185198
/// a full-page redirect flow.
@@ -251,8 +264,8 @@ class User extends UserInfo<auth_interop.UserJsImpl> {
251264
? jsObject.getIdTokenResult()
252265
: jsObject.getIdTokenResult(forceRefresh.toJS);
253266

254-
return (promise.toDart as Future<auth_interop.IdTokenResultImpl>)
255-
.then(IdTokenResult._fromJsObject);
267+
return promise.toDart.then((value) =>
268+
IdTokenResult._fromJsObject(value! as auth_interop.IdTokenResultImpl));
256269
}
257270

258271
/// Returns a JSON-serializable representation of this object.
@@ -295,7 +308,7 @@ class IdTokenResult extends JsObjectWrapper<auth_interop.IdTokenResultImpl> {
295308
/// custom, phone, password, etc).
296309
///
297310
/// Note, this does not map to provider IDs.
298-
String get signInProvider => jsObject.signInProvider.toDart;
311+
String? get signInProvider => jsObject.signInProvider?.toDart;
299312

300313
/// The Firebase Auth ID token JWT string.
301314
String get token => jsObject.token.toDart;
@@ -330,7 +343,7 @@ class Auth extends JsObjectWrapper<auth_interop.AuthJsImpl> {
330343
/// SMS templates for phone authentication, reCAPTCHA verifier and OAuth
331344
/// popup/redirect operations provided the specified providers support
332345
/// localization with the language code specified.
333-
String get languageCode => jsObject.languageCode.toDart;
346+
String? get languageCode => jsObject.languageCode?.toDart;
334347

335348
set languageCode(String? s) {
336349
jsObject.languageCode = s?.toJS;
@@ -462,8 +475,10 @@ class Auth extends JsObjectWrapper<auth_interop.AuthJsImpl> {
462475
/// out-of-band mechanism.
463476
/// It returns [ActionCodeInfo], metadata about the code.
464477
Future<auth_interop.ActionCodeInfo> checkActionCode(String code) =>
465-
(auth_interop.checkActionCode(jsObject, code.toJS).toDart)
466-
as Future<auth_interop.ActionCodeInfo>;
478+
auth_interop
479+
.checkActionCode(jsObject, code.toJS)
480+
.toDart
481+
.then((value) => value! as auth_interop.ActionCodeInfo);
467482

468483
/// Completes password reset process with a [code] and a [newPassword].
469484
Future confirmPasswordReset(String code, String newPassword) => auth_interop
@@ -717,9 +732,10 @@ class Auth extends JsObjectWrapper<auth_interop.AuthJsImpl> {
717732
/// Verifies a password reset [code] sent to the user by email
718733
/// or other out-of-band mechanism.
719734
/// Returns the user's e-mail address if valid.
720-
Future<String> verifyPasswordResetCode(String code) =>
721-
auth_interop.verifyPasswordResetCode(jsObject, code.toJS).toDart
722-
as Future<String>;
735+
Future<String> verifyPasswordResetCode(String code) => auth_interop
736+
.verifyPasswordResetCode(jsObject, code.toJS)
737+
.toDart
738+
.then((value) => value! as String);
723739
}
724740

725741
/// Represents an auth provider.
@@ -1019,7 +1035,8 @@ class PhoneAuthProvider
10191035
dynamic phoneOptions, ApplicationVerifier applicationVerifier) =>
10201036
jsObject
10211037
.verifyPhoneNumber(phoneOptions, applicationVerifier.jsObject)
1022-
.toDart as Future<String>;
1038+
.toDart
1039+
.then((value) => value! as String);
10231040

10241041
/// Creates a phone auth credential given the verification ID
10251042
/// from [verifyPhoneNumber] and the [verificationCode] that was sent to the
@@ -1045,7 +1062,8 @@ abstract class ApplicationVerifier<
10451062
/// Executes the verification process.
10461063
/// Returns a Future containing string for a token that can be used to
10471064
/// assert the validity of a request.
1048-
Future<String> verify() => jsObject.verify().toDart as Future<String>;
1065+
Future<String> verify() =>
1066+
jsObject.verify().toDart.then((value) => value! as String);
10491067
}
10501068

10511069
/// reCAPTCHA verifier.
@@ -1101,7 +1119,8 @@ class RecaptchaVerifier
11011119

11021120
/// Renders the reCAPTCHA widget on the page.
11031121
/// Returns a Future that resolves with the reCAPTCHA widget ID.
1104-
Future<num> render() => jsObject.render().toDart as Future<num>;
1122+
Future<num> render() =>
1123+
jsObject.render().toDart.then((value) => value! as num);
11051124
}
11061125

11071126
/// A result from a phone number sign-in, link, or reauthenticate call.
@@ -1157,13 +1176,14 @@ class UserCredential
11571176
class AdditionalUserInfo
11581177
extends JsObjectWrapper<auth_interop.AdditionalUserInfoJsImpl> {
11591178
/// Returns the provider id.
1160-
String get providerId => jsObject.providerId.toDart;
1179+
String? get providerId => jsObject.providerId?.toDart;
11611180

11621181
/// Returns the profile.
1163-
Map<String, dynamic>? get profile => dartify(jsObject.profile);
1182+
Map<String, dynamic>? get profile =>
1183+
jsObject.profile != null ? dartify(jsObject.profile!) : null;
11641184

11651185
/// Returns the user name.
1166-
String get username => jsObject.username.toDart;
1186+
String? get username => jsObject.username?.toDart;
11671187

11681188
/// Returns whether a user is a new or returning user.
11691189
bool get isNewUser => jsObject.isNewUser.toDart;

packages/firebase_auth/firebase_auth_web/lib/src/interop/auth_interop.dart

+14-14
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,8 @@ abstract class AuthJsImpl {}
277277

278278
extension AuthJsImplExtension on AuthJsImpl {
279279
external AppJsImpl get app;
280-
external UserJsImpl get currentUser;
281-
external JSString get languageCode;
280+
external UserJsImpl? get currentUser;
281+
external JSString? get languageCode;
282282
external set languageCode(JSString? s);
283283
external AuthSettings get settings;
284284
external JSString? get tenantId;
@@ -306,7 +306,7 @@ extension IdTokenResultImplExtension on IdTokenResultImpl {
306306
external JSObject get claims;
307307
external JSString get expirationTime;
308308
external JSString get issuedAtTime;
309-
external JSString get signInProvider;
309+
external JSString? get signInProvider;
310310
external JSString get token;
311311
}
312312

@@ -415,17 +415,17 @@ class OAuthCredentialOptions {
415415

416416
extension OAuthCredentialOptionsExtension on OAuthCredentialOptions {
417417
/// The OAuth access token used to initialize the OAuthCredential.
418-
external JSString get accessToken;
419-
external set accessToken(JSString a);
418+
external JSString? get accessToken;
419+
external set accessToken(JSString? a);
420420

421421
/// The OAuth ID token used to initialize the OAuthCredential.
422-
external JSString get idToken;
423-
external set idToken(JSString i);
422+
external JSString? get idToken;
423+
external set idToken(JSString? i);
424424

425425
/// The raw nonce associated with the ID token. It is required when an ID token with a nonce field is provided.
426426
/// The SHA-256 hash of the raw nonce must match the nonce field in the ID token.
427-
external JSString get rawNonce;
428-
external set rawNonce(JSString r);
427+
external JSString? get rawNonce;
428+
external set rawNonce(JSString? r);
429429
}
430430

431431
@JS('AuthProvider')
@@ -677,8 +677,8 @@ extension AuthErrorCustomDataExtension on AuthErrorCustomData {
677677
class ActionCodeData {}
678678

679679
extension ActionCodeDataExtension on ActionCodeData {
680-
external JSString get email;
681-
external JSString get previousEmail;
680+
external JSString? get email;
681+
external JSString? get previousEmail;
682682
}
683683

684684
/// This is the interface that defines the required continue/state URL with
@@ -798,9 +798,9 @@ extension UserCredentialJsImplExtension on UserCredentialJsImpl {
798798
class AdditionalUserInfoJsImpl {}
799799

800800
extension AdditionalUserInfoJsImplExtension on AdditionalUserInfoJsImpl {
801-
external JSString get providerId;
802-
external JSObject get profile;
803-
external JSString get username;
801+
external JSString? get providerId;
802+
external JSObject? get profile;
803+
external JSString? get username;
804804
external JSBoolean get isNewUser;
805805
}
806806

packages/firebase_auth/firebase_auth_web/lib/src/utils/web_utils.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ ActionCodeInfo? convertWebActionCodeInfo(
132132
return ActionCodeInfo(
133133
operation: ActionCodeInfoOperation.passwordReset,
134134
data: ActionCodeInfoData(
135-
email: webActionCodeInfo.data.email.toDart,
136-
previousEmail: webActionCodeInfo.data.previousEmail.toDart,
135+
email: webActionCodeInfo.data.email?.toDart,
136+
previousEmail: webActionCodeInfo.data.previousEmail?.toDart,
137137
),
138138
);
139139
}

packages/firebase_core/firebase_core/example/.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
/build/
3232

3333
# Web related
34-
lib/generated_plugin_registrant.dart
3534

3635
# Exceptions to above rules.
3736
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages

packages/firebase_core/firebase_core_web/lib/src/interop/utils/es6_interop.dart

+8-8
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
@JS()
99
library firebase_interop.core.es6;
1010

11-
import 'dart:js_interop';
11+
import 'dart:js_interop' as js_interop;
1212

1313
import 'package:js/js.dart';
1414

@@ -20,17 +20,17 @@ class PromiseJsImpl<T> {
2020
external PromiseJsImpl then([Func1? onResolve, Func1? onReject]);
2121
}
2222

23-
@JS()
24-
@staticInterop
23+
@js_interop.JS()
24+
@js_interop.staticInterop
2525
class JSError {}
2626

2727
extension JSErrorExtension on JSError {
28-
external JSString? get name;
29-
external JSString? get message;
30-
external JSString? get code;
28+
external js_interop.JSString? get name;
29+
external js_interop.JSString? get message;
30+
external js_interop.JSString? get code;
3131

32-
external JSString? get stack;
32+
external js_interop.JSString? get stack;
3333

3434
// "customData" - see Firebase AuthError docs: https://firebase.google.com/docs/reference/js/auth.autherror
35-
external JSAny get customData;
35+
external js_interop.JSAny get customData;
3636
}

0 commit comments

Comments
 (0)