I am developing a Progressive Web App using Firebase Hosting, Authentication and Functions. For local testing i use the Firebase emulators and iOS / Android Simulators.
The app is hosted using Webpack devServer over SSL. To be able to use SSL locally a RootCA, private and public keys are created and configured in de Webpack devServer configuration.
devServer: {
watchFiles: ['src/**/*.tsx', 'src/**/*.scss'],
historyApiFallback: true,
host: '0.0.0.0',
allowedHosts: [
'localhost',
'theme.myapp.nl',
'theme-a.myapp.nl',
'theme-b.myapp.nl'
],
hot: false,
liveReload: false,
port: 8800,
server: {
type: 'https',
options: {
key: fs.readFileSync('./ssl/my_app.key'),
cert: fs.readFileSync('./ssl/my_app.crt'),
ca: fs.readFileSync('./ssl/RootCA.pem')
}
}
}
To allow the Android Studio emulated devices to open an URL over https using a self signed certificate a script is used to prepare the emulator.
export android_emulator_base=~/Library/Android/sdk/emulator
export android_platformtools_base=~/Library/Android/sdk/platform-tools
# stdout_log <text>
function stdout_log {
echo $(date +%H:%M:%S) :: $@
}
PS3="Select Android emulator: "
select emulator in $($android_emulator_base/emulator -list-avds | tr '\n' ' '); do
stdout_log "You selected $emulator"
stdout_log "Starting emulator"
$($android_emulator_base/emulator -avd $emulator -writable-system) &
$android_platformtools_base/adb wait-for-device
$android_platformtools_base/adb root
$android_platformtools_base/adb wait-for-device
stdout_log "Emulator started"
stdout_log "Remounting emulator"
wait_for_completion $android_platformtools_base/adb remount
$android_platformtools_base/adb wait-for-device
stdout_log "Emulator remounted"
stdout_log "Pull hosts file"
$android_platformtools_base/adb pull /system/etc/hosts ~/Downloads/hosts
$android_platformtools_base/adb wait-for-device
stdout_log "Hosts file pulled"
stdout_log "Creating new hosts file"
echo "127.0.0.1 localhost" >~/Downloads/hosts_new
echo "::1 ip6-localhost" >>~/Downloads/hosts_new
echo '10.0.2.2 theme.myapp.nl theme-a.myapp.nl theme-b.myapp.nl' >>~/Downloads/hosts_new
stdout_log "Uploading new hosts file"
cat ~/Downloads/hosts_new
$android_platformtools_base/adb push ~/Downloads/hosts_new /system/etc/hosts
$android_platformtools_base/adb wait-for-device
stdout_log "hosts file uploaded"
stdout_log "Installing CA Certificates"
$android_platformtools_base/adb shell avbctl disable-verification
$android_platformtools_base/adb wait-for-device
hashed_name=$(openssl x509 -inform PEM -subject_hash_old -in ../RootCA.crt | head -1).0
cp ../RootCA.crt ./$hashed_name
$android_platformtools_base/adb push $hashed_name /system/etc/security/cacerts
$android_platformtools_base/adb shell chmod 664 /system/etc/security/cacerts/$hashed_name
# https://httptoolkit.com/blog/chrome-android-certificate-transparency/
SKPI_FINGERPRINT=$(openssl x509 -in $hashed_name -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64)
echo "chrome --ignore-certificate-errors-spki-list=$SKPI_FINGERPRINT" >./fingerprint.0
$android_platformtools_base/adb push fingerprint.0 /data/local/chrome-command-line
$android_platformtools_base/adb shell chmod 555 /data/local/chrome-command-line/fingerprint.0
$android_platformtools_base/adb push fingerprint.0 /data/local/android-webview-command-line
$android_platformtools_base/adb shell chmod 555 /data/local/android-webview-command-linefingerprint.0
$android_platformtools_base/adb push fingerprint.0 /data/local/webview-command-line
$android_platformtools_base/adb shell chmod 555 /data/local/webview-command-line/fingerprint.0
$android_platformtools_base/adb push fingerprint.0 /data/local/content-shell-command-line
$android_platformtools_base/adb shell chmod 555 /data/local/content-shell-command-line/fingerprint.0
$android_platformtools_base/adb push fingerprint.0 /data/local/tmp/chrome-command-line
$android_platformtools_base/adb shell chmod 555 /data/local/tmp/chrome-command-line/fingerprint.0
$android_platformtools_base/adb push fingerprint.0 /data/local/tmp/android-webview-command-line
$android_platformtools_base/adb shell chmod 555 /data/local/tmp/android-webview-command-line/fingerprint.0
$android_platformtools_base/adb push fingerprint.0 /data/local/tmp/webview-command-line
$android_platformtools_base/adb shell chmod 555 /data/local/tmp/webview-command-line/fingerprint.0
$android_platformtools_base/adb push fingerprint.0 /data/local/tmp/content-shell-command-line
$android_platformtools_base/adb shell chmod 555 /data/local/tmp/content-shell-command-line/fingerprint.0
stdout_log "Rebooting device"
$android_platformtools_base/adb reboot
stdout_log "Rebooting initiated, wait till reboot completed"
$android_platformtools_base/adb wait-for-device
stdout_log "Rebooting completed"
break
done
for iOS emulators this is less complex
xcrun simctl keychain booted add-root-cert ./RootCA.pem
This enables me to load de PWA in the browser of the emulated iOS or Android device over HTTPS.
As said, i also use Firebase Functions which are made available in the hosted React application through a Firebase Functions Service.
import firebaseConfig from '../firebase-config'
import {connectFunctionsEmulator, httpsCallable} from 'firebase/functions'
import React from 'react'
const functions = firebaseConfig.functions
if (firebaseConfig.useEmulator) {
connectFunctionsEmulator(functions, 'localhost', 5001)
}
type GetThemeDataReq = {
themeId: string
}
type GetThemeDataResp = ThemeData
const getThemeData = httpsCallable<GetThemeDataReq, GetThemeDataResp>(
functions,
'getThemeData'
)
const retrieveThemeData = (themeId: string) => {
....
}
const FirebaseFunctionsService = {
retrieveThemeData
}
export default FirebaseFunctionsService
When opening the app from the emulated device through the URL 'https://theme.myapp.nl' the Firebase function is invoked through 'http://localhost:5001'. This fails because insecure content from the emulated device is blocked.
[blocked] The page at https://theme.myapp.nl:8800/auth/login was not allowed to display insecure content from http://localhost:5001/mijn-app-1740a/us-central1/getThemeData.
Running the same PWA in a browser on my desktop, it is able to invoke the Firebase function.
Till now i have not be able to find a way to run firebase functions locally over https, nor to be able to allow my emulated devices to use http instead op https. Setting the Chrome flags #allow-insecure-localhost does not fix the issue.
Also the answers in this question do not resolve the issue because it is not a native Android app.
How to allow all Network connection types HTTP and HTTPS in Android (9) Pie?
I was putting my hope on adding a res/xml/networkSecurityConfig.xml to my emulated Android device using adb push
, but till now unsuccesfull.
Any ideas how to be access a Firebase Emulated function from an Emulated iOS / Android device over http ?