Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing

exports[`Config Plugin iOS Tests - urlTypes adds url types to the Info.plist 1`] = `
exports[`Config Plugin iOS Tests - urlTypes adds url types to the Info.plist (with REVERSED_CLIENT_ID and GOOGLE_APP_ID) 1`] = `
{
"CFBundleURLTypes": [
{
"CFBundleURLSchemes": [
"com.googleusercontent.apps.SomeRandomClientIdString",
],
},
{
"CFBundleURLSchemes": [
"app-1234-1234-ios-1234",
],
},
],
}
`;

exports[`Config Plugin iOS Tests - urlTypes adds encoded app ID url scheme when only GOOGLE_APP_ID is present (no REVERSED_CLIENT_ID) 1`] = `
{
"CFBundleURLTypes": [
{
"CFBundleURLSchemes": [
"app-1-123456789012-ios-1234567890abcdef",
],
},
],
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>API_KEY</key>
<string>SomeRandomApiKeyString</string>
<key>GCM_SENDER_ID</key>
<string>SomeRandomGcmSenderIdNumber</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.example.app</string>
<key>PROJECT_ID</key>
<string>example</string>
<key>STORAGE_BUCKET</key>
<string>example.appspot.com</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:123456789012:ios:1234567890abcdef</string>
<key>DATABASE_URL</key>
<string>https://example.firebaseio.com</string>
</dict>
</plist>
24 changes: 22 additions & 2 deletions packages/auth/plugin/__tests__/iosPlugin_urlTypes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,13 @@ describe('Config Plugin iOS Tests - urlTypes', () => {
},
});
expect(consoleWarnSpy).toHaveBeenCalledWith(
'[@react-native-firebase/auth] REVERSED_CLIENT_ID field not found in GoogleServices-Info.plist. Google Sign-In requires this is - if you need Google Sign-In, enable it and re-download your plist file',
'[@react-native-firebase/auth] REVERSED_CLIENT_ID not found in GoogleService-Info.plist. This is required for Google Sign-In — if you need it, enable Google Sign-In in the Firebase console and re-download your plist. Phone auth reCAPTCHA will still work via the Encoded App ID scheme.',
);
expect(consoleWarnSpy).toHaveBeenCalledTimes(1);
consoleWarnSpy.mockRestore();
});

it('adds url types to the Info.plist', async () => {
it('adds url types to the Info.plist (with REVERSED_CLIENT_ID and GOOGLE_APP_ID)', async () => {
const result = setUrlTypesForCaptcha({
config: {
name: 'TestName',
Expand All @@ -73,4 +74,23 @@ describe('Config Plugin iOS Tests - urlTypes', () => {
});
expect(result.modResults).toMatchSnapshot();
});

it('adds encoded app ID url scheme when only GOOGLE_APP_ID is present (no REVERSED_CLIENT_ID)', async () => {
const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});
const result = setUrlTypesForCaptcha({
config: {
name: 'TestName',
slug: 'TestSlug',
modRequest: { projectRoot: path.join(__dirname, 'fixtures') } as any,
modResults: {},
modRawConfig: { name: 'TestName', slug: 'TestSlug' },
ios: { googleServicesFile: 'TestGoogleService-Info.no-reversed-client-id.plist' },
},
});
expect(consoleWarnSpy).toHaveBeenCalledWith(
'[@react-native-firebase/auth] REVERSED_CLIENT_ID not found in GoogleService-Info.plist. This is required for Google Sign-In — if you need it, enable Google Sign-In in the Firebase console and re-download your plist. Phone auth reCAPTCHA will still work via the Encoded App ID scheme.',
);
expect(result.modResults).toMatchSnapshot();
consoleWarnSpy.mockRestore();
});
});
31 changes: 30 additions & 1 deletion packages/auth/plugin/src/ios/urlTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,23 @@ function reversedClientIDExists(googleServiceFilePath: string): boolean {
}
}

// Derives the Encoded App ID from GOOGLE_APP_ID for reCAPTCHA URL scheme registration.
// Firebase requires this scheme for phone auth / SMS MFA reCAPTCHA fallback on iOS.
// See: https://firebase.google.com/docs/auth/ios/multi-factor#using_recaptcha_verification
// Transformation: "1:123456789012:ios:abc123" -> "app-1-123456789012-ios-abc123"
function getEncodedAppId(googleServiceFilePath: string): string {
try {
const googleServicePlist = fs.readFileSync(googleServiceFilePath, 'utf8');
const googleServiceJson = plist.parse(googleServicePlist) as { GOOGLE_APP_ID: string };
const GOOGLE_APP_ID = googleServiceJson.GOOGLE_APP_ID;
return 'app-' + GOOGLE_APP_ID.replace(/:/g, '-');
} catch {
throw new Error(
'[@react-native-firebase/auth] Failed to parse your GoogleService-Info.plist. Are you sure it is a valid Info.Plist file with a GOOGLE_APP_ID field?',
);
}
}

// add phone auth support by configuring recaptcha
// https://github.com/invertase/react-native-firebase/pull/6167
function addUriScheme(
Expand Down Expand Up @@ -97,9 +114,21 @@ export function setUrlTypesForCaptcha({
} else {
// eslint-disable-next-line no-console
console.warn(
'[@react-native-firebase/auth] REVERSED_CLIENT_ID field not found in GoogleServices-Info.plist. Google Sign-In requires this is - if you need Google Sign-In, enable it and re-download your plist file',
'[@react-native-firebase/auth] REVERSED_CLIENT_ID not found in GoogleService-Info.plist. This is required for Google Sign-In — if you need it, enable Google Sign-In in the Firebase console and re-download your plist. Phone auth reCAPTCHA will still work via the Encoded App ID scheme.',
);
}

// Always add the Encoded App ID derived from GOOGLE_APP_ID for phone auth reCAPTCHA fallback.
// Firebase requires this URL scheme on iOS when APNs is unavailable (e.g. Simulator).
// GOOGLE_APP_ID is always present in a valid GoogleService-Info.plist, so no warning needed here.
// See: https://firebase.google.com/docs/auth/ios/multi-factor#using_recaptcha_verification
try {
const encodedAppId = getEncodedAppId(googleServiceFilePath);
addUriScheme(config, encodedAppId);
} catch {
// silently skip — a missing GOOGLE_APP_ID means the plist is malformed;
// the file-existence and parse checks above will have already surfaced the real problem.
}

return config;
}
Loading