Skip to content

Commit 9725f8f

Browse files
committed
Merge branch 'main' into fix_74591
2 parents 7a9fcb7 + a7d994c commit 9725f8f

52 files changed

Lines changed: 1096 additions & 332 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Mobile-Expensify

android/app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ android {
114114
minSdkVersion rootProject.ext.minSdkVersion
115115
targetSdkVersion rootProject.ext.targetSdkVersion
116116
multiDexEnabled rootProject.ext.multiDexEnabled
117-
versionCode 1009026000
118-
versionName "9.2.60-0"
117+
versionCode 1009026001
118+
versionName "9.2.60-1"
119119
// Supported language variants must be declared here to avoid from being removed during the compilation.
120120
// This also helps us to not include unnecessary language variants in the APK.
121121
resConfigs "en", "es"

cspell.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@
9797
"capitalone",
9898
"CAROOT",
9999
"Carta",
100+
"cacerts",
101+
"changeit",
100102
"ccache",
101103
"ccupload",
102104
"cdfbmo",
@@ -211,10 +213,12 @@
211213
"Expensable",
212214
"expensescount",
213215
"Expensi",
216+
"Expensidev",
214217
"Expensicon",
215218
"Expensicons",
216219
"expensicorp",
217220
"Expensifier",
221+
"EXPENSIDEV",
218222
"EXPENSIFYAPI",
219223
"expensifyhelp",
220224
"expensifylite",
@@ -437,6 +441,7 @@
437441
"noopener",
438442
"noreferer",
439443
"noreferrer",
444+
"noprompt",
440445
"nosymbol",
441446
"Noto",
442447
"NSQS",
@@ -625,6 +630,7 @@
625630
"stdev",
626631
"stdlib",
627632
"storepass",
633+
"stackoverflow",
628634
"STORYLANE",
629635
"strikethrough",
630636
"Strikethrough",
@@ -676,6 +682,7 @@
676682
"tranid",
677683
"Transpiles",
678684
"trivago",
685+
"trustcacerts",
679686
"Typeform",
680687
"uatp",
681688
"UATP",

ios/NewExpensify/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
</dict>
4545
</array>
4646
<key>CFBundleVersion</key>
47-
<string>9.2.60.0</string>
47+
<string>9.2.60.1</string>
4848
<key>FullStory</key>
4949
<dict>
5050
<key>OrgId</key>

ios/NotificationServiceExtension/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<key>CFBundleShortVersionString</key>
1414
<string>9.2.60</string>
1515
<key>CFBundleVersion</key>
16-
<string>9.2.60.0</string>
16+
<string>9.2.60.1</string>
1717
<key>NSExtension</key>
1818
<dict>
1919
<key>NSExtensionPointIdentifier</key>

ios/ShareViewController/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<key>CFBundleShortVersionString</key>
1414
<string>9.2.60</string>
1515
<key>CFBundleVersion</key>
16-
<string>9.2.60.0</string>
16+
<string>9.2.60.1</string>
1717
<key>NSExtension</key>
1818
<dict>
1919
<key>NSExtensionAttributes</key>

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "new.expensify",
3-
"version": "9.2.60-0",
3+
"version": "9.2.60-1",
44
"author": "Expensify, Inc.",
55
"homepage": "https://new.expensify.com",
66
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
#!/bin/bash
2+
#
3+
# Imports the Cloudflare WARP Gateway Root CA certificate into all Java installations.
4+
# This is necessary because Cloudflare Zero Trust WARP acts as a man-in-the-middle proxy,
5+
# intercepting SSL connections with its own certificate. Without importing this certificate,
6+
# Gradle and other Java tools fail with SSL handshake errors when downloading dependencies.
7+
# This script automatically finds all JDKs, stops Gradle daemons, and imports the certificate.
8+
9+
set -eu
10+
11+
# Get the directory where this script lives
12+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13+
readonly SCRIPT_DIR
14+
15+
source "${SCRIPT_DIR}/shellUtils.sh"
16+
17+
# Certificate is in the Expensidev repo (two levels up from scripts directory)
18+
EXPENSIDEV_DIR="$(dirname "$(dirname "${SCRIPT_DIR}")")"
19+
readonly EXPENSIDEV_DIR
20+
readonly CERT_FILE="${EXPENSIDEV_DIR}/config/ssl/cloudflare-ca.pem"
21+
22+
# Global constants
23+
readonly CERT_ALIAS="cloudflare-gateway-root"
24+
readonly KEYSTORE_PASSWORD="${JAVA_KEYSTORE_PASSWORD:-changeit}"
25+
26+
# Global variables
27+
JAVA_HOMES=""
28+
JAVA_HOME_PATH=""
29+
KEYSTORE=""
30+
SUCCESS_COUNT=0
31+
FAIL_COUNT=0
32+
33+
# Function to set the KEYSTORE global variable for the current JAVA_HOME_PATH
34+
# Returns 0 if found, 1 if not found
35+
function get_keystore_path() {
36+
if [[ -f "${JAVA_HOME_PATH}/lib/security/cacerts" ]]; then
37+
KEYSTORE="${JAVA_HOME_PATH}/lib/security/cacerts"
38+
return 0
39+
elif [[ -f "${JAVA_HOME_PATH}/jre/lib/security/cacerts" ]]; then
40+
KEYSTORE="${JAVA_HOME_PATH}/jre/lib/security/cacerts"
41+
return 0
42+
fi
43+
return 1
44+
}
45+
46+
# Function to check if Cloudflare WARP certificate is imported into default JDK
47+
# Returns 0 if certificate is imported, 1 otherwise
48+
function is_cloudflare_cert_imported() {
49+
if ! command -v keytool &>/dev/null; then
50+
return 1
51+
fi
52+
53+
JAVA_HOME_PATH=$(/usr/libexec/java_home 2>/dev/null) || return 1
54+
55+
if ! get_keystore_path; then
56+
return 1
57+
fi
58+
59+
keytool -list -keystore "${KEYSTORE}" \
60+
-storepass "${KEYSTORE_PASSWORD}" -alias "${CERT_ALIAS}" &>/dev/null
61+
}
62+
63+
function stop_gradle_daemons() {
64+
if pgrep -f "GradleDaemon" &>/dev/null; then
65+
pkill -f "GradleDaemon" &>/dev/null || true
66+
success "Gradle daemons stopped"
67+
else
68+
echo "No Gradle daemons running"
69+
fi
70+
}
71+
72+
function find_java_installations() {
73+
JAVA_HOMES=$(/usr/libexec/java_home -V 2>&1 | grep -E "^\s+[0-9]" | awk '{print $NF}')
74+
75+
if [[ -z "${JAVA_HOMES}" ]]; then
76+
error "No Java installations found"
77+
exit 1
78+
fi
79+
80+
local JDK_COUNT
81+
JDK_COUNT=$(echo "${JAVA_HOMES}" | wc -l | tr -d ' ')
82+
success "Found ${JDK_COUNT} Java installation(s)"
83+
}
84+
85+
function import_certificates() {
86+
while IFS= read -r JAVA_HOME_PATH; do
87+
if [[ -z "${JAVA_HOME_PATH}" ]]; then
88+
continue
89+
fi
90+
91+
# Get Java version for display
92+
local VERSION
93+
VERSION=$("${JAVA_HOME_PATH}/bin/java" -version 2>&1 | head -n 1 | awk -F'"' '{print $2}')
94+
echo
95+
echo "Processing: Java ${VERSION}"
96+
echo " Location: ${JAVA_HOME_PATH}"
97+
98+
# Get keystore location
99+
if ! get_keystore_path; then
100+
error "Could not find cacerts file\n Tried: ${JAVA_HOME_PATH}/lib/security/cacerts\n Tried: ${JAVA_HOME_PATH}/jre/lib/security/cacerts"
101+
((FAIL_COUNT++))
102+
continue
103+
fi
104+
105+
# Check if certificate already exists
106+
if keytool -list -keystore "${KEYSTORE}" -storepass "${KEYSTORE_PASSWORD}" \
107+
-alias "${CERT_ALIAS}" &>/dev/null; then
108+
echo " Certificate already exists, removing old one..."
109+
keytool -delete -keystore "${KEYSTORE}" -alias "${CERT_ALIAS}" \
110+
-storepass "${KEYSTORE_PASSWORD}" \
111+
&>/dev/null || true
112+
fi
113+
114+
# Import the certificate
115+
if keytool -import -trustcacerts -keystore "${KEYSTORE}" \
116+
-alias "${CERT_ALIAS}" \
117+
-file "${CERT_FILE}" \
118+
-storepass "${KEYSTORE_PASSWORD}" \
119+
-noprompt &>/dev/null; then
120+
success "Certificate imported successfully"
121+
((SUCCESS_COUNT++))
122+
else
123+
error "Failed to import certificate"
124+
((FAIL_COUNT++))
125+
fi
126+
done <<< "${JAVA_HOMES}"
127+
}
128+
129+
function print_summary() {
130+
echo
131+
success "Successfully imported: ${SUCCESS_COUNT}"
132+
if [[ "${FAIL_COUNT}" -gt 0 ]]; then
133+
error "Failed: ${FAIL_COUNT}"
134+
fi
135+
136+
echo
137+
if [[ "${SUCCESS_COUNT}" -gt 0 ]]; then
138+
success "Certificate import complete!"
139+
echo
140+
echo "The Cloudflare WARP certificate has been imported into your"
141+
echo "Java keystores. You can now build Android apps with WARP enabled."
142+
echo
143+
info "Gradle daemon will automatically use the updated certificates when it restarts on your next build."
144+
exit 0
145+
else
146+
error "No certificates were imported successfully"
147+
exit 1
148+
fi
149+
}
150+
151+
function main() {
152+
# Early exit if certs are already imported
153+
if is_cloudflare_cert_imported; then
154+
success "Cloudflare certificates are already imported into JDK."
155+
exit 0
156+
fi
157+
158+
# At this point, certs need to be imported
159+
# If not running with sudo, re-exec with sudo (will prompt for password)
160+
if [[ "${EUID}" -ne 0 ]]; then
161+
info "Importing certificates requires sudo access."
162+
exec sudo bash "${BASH_SOURCE[0]}" "$@"
163+
fi
164+
165+
# At this point, we're running with sudo and certs need to be imported
166+
title "Cloudflare WARP Certificate Importer"
167+
168+
# Verify certificate file exists
169+
if [[ ! -f "${CERT_FILE}" ]]; then
170+
error "Cloudflare certificate not found at: ${CERT_FILE}\nMake sure you have the Expensidev repository cloned and that App is a child of Expensidev.\nAlternatively, manually follow this stackoverflow: https://stackoverflowteams.com/c/expensify/questions/18506"
171+
exit 1
172+
fi
173+
174+
title "Step 1: Stopping Gradle daemons"
175+
stop_gradle_daemons
176+
177+
title "Step 2: Finding all Java installations"
178+
find_java_installations
179+
180+
title "Step 3: Importing certificate into Java keystores"
181+
import_certificates
182+
183+
print_summary
184+
}
185+
186+
main "$@"

scripts/run-build.sh

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
#!/bin/bash
22
set -e
33

4+
# Get the directory where this script lives
5+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6+
7+
# Source shellUtils for helper functions
8+
source "${SCRIPT_DIR}/shellUtils.sh"
9+
410
if [ -f .env ]; then
511
set -a
612
source .env
@@ -12,22 +18,22 @@ ANDROID_MODE="developmentDebug"
1218
SCHEME="New Expensify Dev"
1319
APP_ID="com.expensify.chat.dev"
1420

15-
GREEN='\033[1;32m'
16-
RED='\033[1;31m'
17-
NC='\033[0m'
18-
1921
# Function to print error message and exit
2022
function print_error_and_exit {
21-
echo -e "${RED}Error: Invalid invocation. Please use one of: [ios, ipad, ipad-sm, android].${NC}"
23+
error "Invalid invocation. Please use one of: [ios, ipad, ipad-sm, android]."
2224
exit 1
2325
}
2426

25-
# Assign the arguments to variables if arguments are correct
26-
if [ "$#" -ne 1 ] || [[ "$1" != "--ios" && "$1" != "--ipad" && "$1" != "--ipad-sm" && "$1" != "--android" ]]; then
27+
# Parse arguments
28+
if [ "$#" -lt 1 ] || [[ "$1" != "--ios" && "$1" != "--ipad" && "$1" != "--ipad-sm" && "$1" != "--android" ]]; then
2729
print_error_and_exit
2830
fi
2931

3032
BUILD="$1"
33+
shift
34+
35+
# Capture any additional flags to pass through to rock
36+
ROCK_FLAGS=("$@")
3137

3238
# See if we're in the HybridApp repo
3339
IS_HYBRID_APP_REPO=$(scripts/is-hybrid-app.sh)
@@ -45,11 +51,13 @@ if [[ "$IS_HYBRID_APP_REPO" == "true" && "$NEW_DOT_FLAG" == "false" ]]; then
4551
# Build Yapl JS
4652
cd Mobile-Expensify && npm run grunt:build:shared && cd ..
4753

48-
echo -e "\n${GREEN}Starting a HybridApp build!${NC}"
54+
echo
55+
success "Starting a HybridApp build!"
4956
export CUSTOM_APK_NAME="Expensify-debug.apk"
5057
export IS_HYBRID_APP="true"
5158
else
52-
echo -e "\n${GREEN}Starting a standalone NewDot build!${NC}"
59+
echo
60+
success "Starting a standalone NewDot build!"
5361
echo $ANDROID_MODE
5462
unset CUSTOM_APK_NAME
5563
fi
@@ -58,16 +66,21 @@ fi
5866
# RCT_USE_RN_DEP=0 RCT_USE_PREBUILT_RNCORE=0 - force React Native to build from source to include our custom patches
5967
case "$BUILD" in
6068
--ios)
61-
RCT_USE_RN_DEP=0 RCT_USE_PREBUILT_RNCORE=0 npx rock run:ios --configuration $IOS_MODE --scheme "$SCHEME" --dev-server
69+
RCT_USE_RN_DEP=0 RCT_USE_PREBUILT_RNCORE=0 npx rock run:ios --configuration $IOS_MODE --scheme "$SCHEME" --dev-server "${ROCK_FLAGS[@]}"
6270
;;
6371
--ipad)
64-
RCT_USE_RN_DEP=0 RCT_USE_PREBUILT_RNCORE=0 npx rock run:ios --simulator "iPad Pro (12.9-inch) (6th generation)" --configuration $IOS_MODE --scheme "$SCHEME" --dev-server
72+
RCT_USE_RN_DEP=0 RCT_USE_PREBUILT_RNCORE=0 npx rock run:ios --simulator "iPad Pro (12.9-inch) (6th generation)" --configuration $IOS_MODE --scheme "$SCHEME" --dev-server "${ROCK_FLAGS[@]}"
6573
;;
6674
--ipad-sm)
67-
RCT_USE_RN_DEP=0 RCT_USE_PREBUILT_RNCORE=0 npx rock run:ios --simulator "iPad Pro (11-inch) (4th generation)" --configuration $IOS_MODE --scheme "$SCHEME" --dev-server
75+
RCT_USE_RN_DEP=0 RCT_USE_PREBUILT_RNCORE=0 npx rock run:ios --simulator "iPad Pro (11-inch) (4th generation)" --configuration $IOS_MODE --scheme "$SCHEME" --dev-server "${ROCK_FLAGS[@]}"
6876
;;
6977
--android)
70-
npx rock run:android --variant $ANDROID_MODE --app-id $APP_ID --active-arch-only --verbose --dev-server
78+
# Check if Cloudflare WARP is active and certificates need to be imported
79+
if is_warp_active; then
80+
"${SCRIPT_DIR}/import-cloudflare-certs-into-jdk.sh"
81+
fi
82+
83+
npx rock run:android --variant $ANDROID_MODE --app-id $APP_ID --active-arch-only --verbose --dev-server "${ROCK_FLAGS[@]}"
7184
;;
7285
*)
7386
print_error_and_exit

0 commit comments

Comments
 (0)