* feat(mobile): upgrade Expo SDK to v55 Upgrade Expo SDK from v54 to v55, along with React Native 0.83.4, React 19.2, and all related dependencies. Key changes: - Refactored @safe-global/theme to use sub-path exports to fix RN import resolution issues - Added react-native patch for Appearance.setColorScheme bug (facebook/react-native#08d176453) not yet in 0.83.4 release - Replaced Tamagui Skeleton with custom SafeSkeleton component - Updated expo config plugins for SDK 55 compatibility * fix: downgrade eslint-config-next to v15 to match next.js version eslint-config-next v16 requires next v16 but the project uses next v15.5.8. The v16 package tries to import next/dist/compiled/babel/ eslint-parser which doesn't exist in next v15. * fix: migrate packages away from eslint-config-next eslint-config-next requires next at runtime for its babel parser, but next is only installed in apps/web. After the Expo SDK v55 upgrade changed dependency hoisting, the parser became unreachable. - Create shared config/eslint/base.mjs using direct plugin imports - Migrate store, theme, utils, and tx-builder to the shared config - Add packageExtensions in .yarnrc.yml so eslint-config-next in apps/web can still resolve next as a peer dependency * chore: align react 19.2 across workspaces and fix MUI peer dep - Bump react/react-dom to 19.2.0 in web and tx-builder to match mobile - Add @mui/material as optional peer dependency in theme package to avoid duplicate installations causing type conflicts * chore(mobile): update storybook on mobile to v10 * fix(web): resolve @emotion/react hoisting issue after Expo SDK 55 upgrade Yarn 4's node-modules hoisting shifted after dependency graph changes, leaving @emotion/react only in apps/web/node_modules while @mui/styled-engine remained at root. Add webpack resolve aliases to ensure Next.js finds emotion packages from the web workspace. * fix(web): resolve @emotion hoisting issue in Jest config Same hoisting fix as next.config.mjs but for Jest's module resolution. Add moduleNameMapper entries for @emotion/react and @emotion/styled. * fix(tx-builder): prettier * fix: resolve type-check errors after Expo SDK 55 upgrade - Fix BlurView tint prop: map ColorSchemeName to valid BlurTint values - Replace @storybook/test imports with storybook/test (merged in v10) - Align @types/react (~19.2.10) and @types/react-dom (~19.2.0) across all workspaces to prevent duplicate @mui/material type mismatches - Spread visuallyHidden into sx prop for @types/react 19.2.x compat - Add @types/react, @types/react-dom, storybook to yarn version checker * chore: align more dependencies * chore(web): update storybook snapshot * fix(mobile): normalize color scheme and deduplicate MUI/emotion packages - Normalize useTheme colorScheme to 'light' | 'dark', never 'unspecified' so TamaguiProvider always receives a valid theme name - Update ColorScheme type to exclude 'unspecified' - Remove redundant ?? 'light' fallbacks in SafeThemeProvider - Align @emotion/* and @mui/icons-material versions across workspaces to prevent Yarn from creating duplicate lockfile resolutions - Remove emotion webpack/Jest aliases (no longer needed after dedup) - Add @emotion/react, @emotion/styled, @mui/material, @mui/icons-material to yarn version consistency checker --------- Co-authored-by: Hanzo Dev <[email protected]>
SSL Pinning Expo Config Plugin
This plugin implements SSL certificate pinning for React Native apps using Expo, supporting both iOS and Android platforms.
Features
- iOS SSL Pinning: Uses TrustKit library for secure certificate validation
- Android SSL Pinning: Uses OkHttp's built-in certificate pinner
- Automatic native code modification: Handles all necessary iOS and Android code changes
How SSL Pinning Works
SSL pinning enhances security by embedding specific certificate hashes directly into your app code. This prevents man-in-the-middle attacks even if an attacker manages to install malicious certificates on the device or compromises a certificate authority.
Getting Certificate Hashes
Before configuring the plugin, you need to obtain the public key hashes for your domains:
Method 1: Use the Certificate Extraction Script (Recommended)
# This script automatically extracts certificates and provides ready-to-use SSL pinning configuration
cd apps/mobile
node scripts/getCertificates.js safe-client.safe.global
# Multiple domains at once
node scripts/getCertificates.js safe-client.safe.global safe-client.staging.5afe.dev
Method 2: Manual OpenSSL Commands
Step 1: Get Full Certificate Chain
# Get the complete certificate chain
openssl s_client -servername example.com -connect example.com:443 -showcerts > fullchain.pem
Step 2: Extract Specific Certificates
# Extract leaf certificate (first certificate)
awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/' fullchain.pem | sed -n '1,/END CERTIFICATE/p' > leaf.pem
# Extract intermediate certificate (second certificate)
awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/' fullchain.pem | sed -n '2,/END CERTIFICATE/p' > intermediate.pem
# Extract root certificate (last certificate)
awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/' fullchain.pem | tail -n +2 > root.pem
Step 3: Generate Certificate Hashes
# Leaf certificate hash
openssl x509 -in leaf.pem -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
# Intermediate certificate hash (recommended for backup)
openssl x509 -in intermediate.pem -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
# Root certificate hash
openssl x509 -in root.pem -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
Configuration
1. Configure SSL Pinning Domains
Update apps/mobile/app.config.js to include your domains and certificate hashes in the SSL pinning plugin configuration:
[
'./expo-plugins/ssl-pinning/withSSLPinning.js',
{
domains: {
'api.safeglobal.io': [
'PRIMARY_CERT_HASH_BASE64'
],
'dev-api.safeglobal.io': [
'DEV_PRIMARY_CERT_HASH_BASE64'
],
},
},
],
2. Plugin Configuration
The plugin is already integrated into the app configuration. Simply update the domains object with your certificate hashes.
Environment Configuration
The plugin uses the same domain configuration for all builds. You can include both production and development/staging domains in the same configuration:
- All configured domains will be pinned across all build variants
- Include both production and staging/development domains as needed
- Each domain can have multiple certificate hashes for backup
Testing SSL Pinning
Testing Valid Certificates
- Build and run your app
- Make network requests to pinned domains
- Requests should work normally
Testing Invalid Certificates
- Change one of the certificate hashes to an invalid value (e.g., all A's)
- Rebuild the app completely
- Clear app cache/data or reinstall
- Network requests to pinned domains should fail
Important: iOS maintains a TLS session cache, so you may need to:
- Delete and reinstall the app
- Reset the iOS Simulator
- Wait for the cache to expire
Using Proxy Tools
You can test SSL pinning using tools like:
When SSL pinning is working correctly, requests through these proxies should fail.