import { readFile } from 'node:fs/promises' import { resolve } from 'node:path' import { fileURLToPath } from 'node:url' const ROOT = resolve(import.meta.dirname, '../..') const DEFAULT_GOOGLE_SERVICES_PATH = resolve( ROOT, 'apps/mobile-rn/android/app/google-services.json', ) const PRODUCTION_PACKAGE_NAME = 'com.d3ro.voice' const GOOGLE_TEST_ADMOB_PUBLISHER_ID = '3940256099942544' const FIREBASE_PROJECT_ID = /^[a-z][a-z0-9-]{4,28}[a-z0-9]$/ const FIREBASE_PROJECT_NUMBER = /^[1-9][0-9]{5,19}$/ const FIREBASE_MOBILESDK_APP_ID = /^1:([1-9][0-9]{5,19}):android:([0-9a-f]{16,64})$/ const ANDROID_PACKAGE_NAME = /^[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+$/i const GOOGLE_API_KEY = /^AIza[0-9A-Za-z_-]{20,96}$/ const ADMOB_APP_ID = /^ca-app-pub-([0-9]{16})~([0-9]{10})$/ const ADMOB_UNIT_ID = /^ca-app-pub-([0-9]{16})\/([0-9]{10})$/ const MAX_GOOGLE_SERVICES_BYTES = 1024 * 1024 function fail(code) { throw new Error(`mobile_release_config_invalid:${code}`) } function isRecord(value) { return value !== null && typeof value === 'object' && !Array.isArray(value) } function requireExactString(value, code) { if (typeof value !== 'string' || value.length === 0 || value !== value.trim()) fail(code) return value } function requireExpectedFirebaseIdentity(expected) { if (!isRecord(expected)) fail('firebase_expected_identity_missing') const projectId = requireExactString( expected.projectId, 'firebase_expected_project_id_missing', ) const projectNumber = requireExactString( expected.projectNumber, 'firebase_expected_project_number_missing', ) const mobileSdkAppId = requireExactString( expected.mobileSdkAppId, 'firebase_expected_mobilesdk_app_id_missing', ) if (!FIREBASE_PROJECT_ID.test(projectId)) fail('firebase_expected_project_id_format') if (!FIREBASE_PROJECT_NUMBER.test(projectNumber)) { fail('firebase_expected_project_number_format') } const appIdMatch = mobileSdkAppId.match(FIREBASE_MOBILESDK_APP_ID) if (!appIdMatch) fail('firebase_expected_mobilesdk_app_id_format') if (appIdMatch[1] !== projectNumber) { fail('firebase_expected_mobilesdk_app_id_project_number_mismatch') } return { projectId, projectNumber, mobileSdkAppId } } export function parseGoogleServicesSource(source) { if (typeof source !== 'string' || source.length === 0) fail('google_services_empty') if (Buffer.byteLength(source, 'utf8') > MAX_GOOGLE_SERVICES_BYTES) { fail('google_services_too_large') } try { return JSON.parse(source) } catch { fail('google_services_invalid_json') } } export function verifyFirebaseConfiguration(configuration, expectedIdentity) { const expected = requireExpectedFirebaseIdentity(expectedIdentity) if (!isRecord(configuration)) fail('google_services_root_invalid') if (configuration.configuration_version !== '1') { fail('google_services_configuration_version_invalid') } const projectInfo = configuration.project_info if (!isRecord(projectInfo)) fail('firebase_project_info_missing') const projectId = requireExactString(projectInfo.project_id, 'firebase_project_id_missing') const projectNumber = requireExactString( projectInfo.project_number, 'firebase_project_number_missing', ) if (!FIREBASE_PROJECT_ID.test(projectId)) fail('firebase_project_id_format') if (!FIREBASE_PROJECT_NUMBER.test(projectNumber)) fail('firebase_project_number_format') if (projectId !== expected.projectId) fail('firebase_project_id_mismatch') if (projectNumber !== expected.projectNumber) fail('firebase_project_number_mismatch') const clients = configuration.client if (!Array.isArray(clients) || clients.length === 0) fail('firebase_clients_missing') if (clients.length > 100) fail('firebase_client_count_excessive') const packages = new Set() const appIds = new Set() let productionClient for (const client of clients) { if (!isRecord(client)) fail('firebase_client_invalid') const clientInfo = client.client_info if (!isRecord(clientInfo)) fail('firebase_client_info_missing') const androidClientInfo = clientInfo.android_client_info if (!isRecord(androidClientInfo)) fail('firebase_android_client_info_missing') const packageName = requireExactString( androidClientInfo.package_name, 'firebase_client_package_missing', ) const mobileSdkAppId = requireExactString( clientInfo.mobilesdk_app_id, 'firebase_client_mobilesdk_app_id_missing', ) if (!ANDROID_PACKAGE_NAME.test(packageName)) fail('firebase_client_package_format') const appIdMatch = mobileSdkAppId.match(FIREBASE_MOBILESDK_APP_ID) if (!appIdMatch) fail('firebase_client_mobilesdk_app_id_format') if (appIdMatch[1] !== projectNumber) { fail('firebase_client_mobilesdk_app_id_project_number_mismatch') } if (packages.has(packageName)) fail('firebase_client_package_duplicate') if (appIds.has(mobileSdkAppId)) fail('firebase_client_mobilesdk_app_id_duplicate') packages.add(packageName) appIds.add(mobileSdkAppId) if (packageName === PRODUCTION_PACKAGE_NAME) productionClient = client } if (!productionClient) fail('firebase_production_client_missing') if (productionClient.client_info.mobilesdk_app_id !== expected.mobileSdkAppId) { fail('firebase_mobilesdk_app_id_mismatch') } const apiKeys = productionClient.api_key if (!Array.isArray(apiKeys) || apiKeys.length !== 1) { fail('firebase_production_api_key_must_be_unique') } if (!isRecord(apiKeys[0])) fail('firebase_production_api_key_invalid') const apiKey = requireExactString( apiKeys[0].current_key, 'firebase_production_api_key_missing', ) if (!GOOGLE_API_KEY.test(apiKey)) fail('firebase_production_api_key_format') return Object.freeze({ packageNameVerified: true, projectIdentityVerified: true, clientIdentityUnique: true, apiKeyUnique: true, }) } function parseAdMobId(value, expression, missingCode, formatCode) { const normalized = requireExactString(value, missingCode) const match = normalized.match(expression) if (!match) fail(formatCode) if (/^0+$/.test(match[1]) || /^0+$/.test(match[2])) fail(formatCode) return { value: normalized, publisherId: match[1] } } export function verifyAdMobConfiguration(configuration) { if (!isRecord(configuration)) fail('admob_configuration_missing') const app = parseAdMobId( configuration.appId, ADMOB_APP_ID, 'admob_app_id_missing', 'admob_app_id_format', ) const banner = parseAdMobId( configuration.bannerUnitId, ADMOB_UNIT_ID, 'admob_banner_unit_id_missing', 'admob_banner_unit_id_format', ) const rewarded = parseAdMobId( configuration.rewardedUnitId, ADMOB_UNIT_ID, 'admob_rewarded_unit_id_missing', 'admob_rewarded_unit_id_format', ) for (const entry of [app, banner, rewarded]) { if (entry.publisherId === GOOGLE_TEST_ADMOB_PUBLISHER_ID) { fail('admob_google_test_publisher_rejected') } } if (app.publisherId !== banner.publisherId || app.publisherId !== rewarded.publisherId) { fail('admob_publisher_mismatch') } if (banner.value === rewarded.value) fail('admob_unit_ids_must_be_unique') return Object.freeze({ productionFormatVerified: true, googleTestPublisherRejected: true, publisherConsistencyVerified: true, unitIdentityUnique: true, }) } function clone(value) { return structuredClone(value) } function expectFailure(label, action, expectedCode) { try { action() } catch (error) { const expectedMessage = `mobile_release_config_invalid:${expectedCode}` if (error instanceof Error && error.message === expectedMessage) return throw new Error(`mobile_release_config_self_test_unexpected:${label}`) } throw new Error(`mobile_release_config_self_test_missed:${label}`) } function makeFirebaseFixture() { return { configuration_version: '1', project_info: { project_number: '123456789012', project_id: 'd3ro-production', storage_bucket: 'd3ro-production.example.invalid', }, client: [ { client_info: { mobilesdk_app_id: '1:123456789012:android:0123456789abcdef', android_client_info: { package_name: PRODUCTION_PACKAGE_NAME }, }, api_key: [ { current_key: ['AI', 'zaFixtureKeyMaterial1234567890abcd'].join('') }, ], }, ], } } function runSelfTest() { const expected = { projectId: 'd3ro-production', projectNumber: '123456789012', mobileSdkAppId: '1:123456789012:android:0123456789abcdef', } const firebase = makeFirebaseFixture() const admob = { appId: 'ca-app-pub-1234567890123456~1234567890', bannerUnitId: 'ca-app-pub-1234567890123456/2345678901', rewardedUnitId: 'ca-app-pub-1234567890123456/3456789012', } verifyFirebaseConfiguration(firebase, expected) verifyAdMobConfiguration(admob) parseGoogleServicesSource(JSON.stringify(firebase)) const firebaseCases = [ ['invalid_json', () => parseGoogleServicesSource('{'), 'google_services_invalid_json'], ['root_array', () => verifyFirebaseConfiguration([], expected), 'google_services_root_invalid'], ['configuration_version', () => { const value = clone(firebase) value.configuration_version = '2' return verifyFirebaseConfiguration(value, expected) }, 'google_services_configuration_version_invalid'], ['project_id_mismatch', () => { const value = clone(firebase) value.project_info.project_id = 'different-production' return verifyFirebaseConfiguration(value, expected) }, 'firebase_project_id_mismatch'], ['project_number_mismatch', () => { const value = clone(firebase) value.project_info.project_number = '223456789012' return verifyFirebaseConfiguration(value, expected) }, 'firebase_project_number_mismatch'], ['missing_clients', () => { const value = clone(firebase) value.client = [] return verifyFirebaseConfiguration(value, expected) }, 'firebase_clients_missing'], ['duplicate_package', () => { const value = clone(firebase) const duplicate = clone(value.client[0]) duplicate.client_info.mobilesdk_app_id = '1:123456789012:android:fedcba9876543210' value.client.push(duplicate) return verifyFirebaseConfiguration(value, expected) }, 'firebase_client_package_duplicate'], ['duplicate_app_id', () => { const value = clone(firebase) const duplicate = clone(value.client[0]) duplicate.client_info.android_client_info.package_name = 'com.d3ro.voice.other' value.client.push(duplicate) return verifyFirebaseConfiguration(value, expected) }, 'firebase_client_mobilesdk_app_id_duplicate'], ['production_package_missing', () => { const value = clone(firebase) value.client[0].client_info.android_client_info.package_name = 'com.d3ro.voice.other' return verifyFirebaseConfiguration(value, expected) }, 'firebase_production_client_missing'], ['app_id_mismatch', () => { const value = clone(firebase) value.client[0].client_info.mobilesdk_app_id = '1:123456789012:android:fedcba9876543210' return verifyFirebaseConfiguration(value, expected) }, 'firebase_mobilesdk_app_id_mismatch'], ['app_id_project_number_mismatch', () => { const value = clone(firebase) value.client[0].client_info.mobilesdk_app_id = '1:223456789012:android:0123456789abcdef' return verifyFirebaseConfiguration(value, expected) }, 'firebase_client_mobilesdk_app_id_project_number_mismatch'], ['api_key_missing', () => { const value = clone(firebase) value.client[0].api_key = [] return verifyFirebaseConfiguration(value, expected) }, 'firebase_production_api_key_must_be_unique'], ['api_key_ambiguous', () => { const value = clone(firebase) value.client[0].api_key.push(clone(value.client[0].api_key[0])) return verifyFirebaseConfiguration(value, expected) }, 'firebase_production_api_key_must_be_unique'], ['expected_identity_missing', () => verifyFirebaseConfiguration(firebase, {}), 'firebase_expected_project_id_missing'], ['expected_app_id_project_number_mismatch', () => verifyFirebaseConfiguration(firebase, { ...expected, mobileSdkAppId: '1:223456789012:android:0123456789abcdef', }), 'firebase_expected_mobilesdk_app_id_project_number_mismatch'], ] for (const [label, action, expectedCode] of firebaseCases) { expectFailure(label, action, expectedCode) } const admobCases = [ ['app_format', { ...admob, appId: 'ca-app-pub-123~456' }, 'admob_app_id_format'], ['banner_format', { ...admob, bannerUnitId: 'ca-app-pub-1234567890123456~2345678901' }, 'admob_banner_unit_id_format'], ['rewarded_format', { ...admob, rewardedUnitId: 'ca-app-pub-1234567890123456/123' }, 'admob_rewarded_unit_id_format'], ['app_test_publisher', { appId: 'ca-app-pub-3940256099942544~3347511713', bannerUnitId: 'ca-app-pub-3940256099942544/6300978111', rewardedUnitId: 'ca-app-pub-3940256099942544/5224354917', }, 'admob_google_test_publisher_rejected'], ['banner_test_publisher', { ...admob, bannerUnitId: 'ca-app-pub-3940256099942544/6300978111', }, 'admob_google_test_publisher_rejected'], ['publisher_mismatch', { ...admob, rewardedUnitId: 'ca-app-pub-2234567890123456/3456789012', }, 'admob_publisher_mismatch'], ['unit_duplicate', { ...admob, rewardedUnitId: admob.bannerUnitId }, 'admob_unit_ids_must_be_unique'], ['whitespace', { ...admob, appId: `${admob.appId} ` }, 'admob_app_id_missing'], ['zero_identifier', { ...admob, bannerUnitId: 'ca-app-pub-1234567890123456/0000000000', }, 'admob_banner_unit_id_format'], ] for (const [label, configuration, expectedCode] of admobCases) { expectFailure(label, () => verifyAdMobConfiguration(configuration), expectedCode) } return { firebaseFailureCases: firebaseCases.length, adMobFailureCases: admobCases.length } } async function run() { if (process.argv.includes('--self-test')) { const result = runSelfTest() console.log(JSON.stringify({ selfTest: 'verified', ...result })) return } if (process.argv.length > 2) fail('unknown_argument') let source try { source = await readFile( process.env.D3RO_GOOGLE_SERVICES_JSON_FILE || DEFAULT_GOOGLE_SERVICES_PATH, 'utf8', ) } catch { fail('google_services_file_unreadable') } const firebase = verifyFirebaseConfiguration(parseGoogleServicesSource(source), { projectId: process.env.D3RO_FIREBASE_EXPECTED_PROJECT_ID, projectNumber: process.env.D3RO_FIREBASE_EXPECTED_PROJECT_NUMBER, mobileSdkAppId: process.env.D3RO_FIREBASE_EXPECTED_MOBILESDK_APP_ID, }) const adMob = verifyAdMobConfiguration({ appId: process.env.D3RO_ADMOB_APP_ID, bannerUnitId: process.env.D3RO_ADMOB_BANNER_UNIT_ID, rewardedUnitId: process.env.D3RO_ADMOB_REWARDED_UNIT_ID, }) console.log(JSON.stringify({ releaseConfiguration: 'verified', firebase, adMob, })) } const isMain = process.argv[1] && resolve(process.argv[1]) === resolve(fileURLToPath(import.meta.url)) if (isMain) { run().catch((error) => { console.error(error instanceof Error ? error.message : 'mobile_release_config_invalid:unknown') process.exitCode = 1 }) }