diff --git a/.github/workflows/harmony-build.yml b/.github/workflows/harmony-build.yml index 86497154..44176724 100644 --- a/.github/workflows/harmony-build.yml +++ b/.github/workflows/harmony-build.yml @@ -79,6 +79,15 @@ jobs: - name: Verify Harmony HAR artifact run: test -f harmony/pushy.har + - name: Verify the HAR native library carries no update wording + shell: bash + run: | + dir="$(mktemp -d)" + tar -xzf harmony/pushy.har -C "$dir" + libs="$(find "$dir" -path '*/libs/*' -name 'librnpushy.so')" + test -n "$libs" + node scripts/check-binary-strings.js $libs + - name: Type-check Harmony TS sources (required) shell: bash run: | diff --git a/Example/expoUsePushy/ios/expoUsePushy.xcodeproj/project.pbxproj b/Example/expoUsePushy/ios/expoUsePushy.xcodeproj/project.pbxproj index c4a8bfb3..70d9760d 100644 --- a/Example/expoUsePushy/ios/expoUsePushy.xcodeproj/project.pbxproj +++ b/Example/expoUsePushy/ios/expoUsePushy.xcodeproj/project.pbxproj @@ -302,7 +302,7 @@ "${PODS_CONFIGURATION_BUILD_DIR}/React-timing/React-timing_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/SSZipArchive/SSZipArchive.bundle", "${PODS_ROOT}/../../node_modules/react-native-update/ios/pushy_build_time.txt", - "${PODS_CONFIGURATION_BUILD_DIR}/react-native-update/react-native-update_privacy.bundle", + "${PODS_CONFIGURATION_BUILD_DIR}/react-native-update/PushyPrivacy.bundle", ); name = "[CP] Copy Pods Resources"; outputPaths = ( @@ -315,7 +315,7 @@ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-timing_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SSZipArchive.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/pushy_build_time.txt", - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/react-native-update_privacy.bundle", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/PushyPrivacy.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; diff --git a/harmony/pushy/src/main/cpp/CMakeLists.txt b/harmony/pushy/src/main/cpp/CMakeLists.txt index 93325779..1e242470 100644 --- a/harmony/pushy/src/main/cpp/CMakeLists.txt +++ b/harmony/pushy/src/main/cpp/CMakeLists.txt @@ -78,6 +78,8 @@ endif() # keep exporting PushyTurboModule (JSI_EXPORT) for the host's PackageProvider. if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") target_compile_options(rnpushy PRIVATE + # NAPI_MODULE records __FILE__; keep the build path out of the binary. + -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}/= -ffunction-sections -fdata-sections -fvisibility=hidden diff --git a/ios/RCTPushy/RCTPushy.mm b/ios/RCTPushy/RCTPushy.mm index f6d881a0..8a7c78b4 100644 --- a/ios/RCTPushy/RCTPushy.mm +++ b/ios/RCTPushy/RCTPushy.mm @@ -31,6 +31,12 @@ #import #import +// RN's log macros pass __FILE__, which would embed this file's absolute build +// path in the binary; log with the bare file name instead. +#if RCTLOG_ENABLED +#undef _RCTLog +#define _RCTLog(lvl, ...) _RCTLogNativeInternal(lvl, __FILE_NAME__, __LINE__, __VA_ARGS__) +#endif #import #import diff --git a/react-native-update.podspec b/react-native-update.podspec index 3d27a6a1..8b48e5aa 100644 --- a/react-native-update.podspec +++ b/react-native-update.podspec @@ -147,7 +147,7 @@ Pod::Spec.new do |s| # Privacy manifest (required-reason APIs: disk space, file timestamps, # system boot time, user defaults) delivered as its own resource bundle so # static and dynamic integrations both carry it. - s.resource_bundles = { 'react-native-update_privacy' => ['ios/PrivacyInfo.xcprivacy'] } + s.resource_bundles = { 'PushyPrivacy' => ['ios/PrivacyInfo.xcprivacy'] } s.dependency 'React' s.dependency "React-Core" diff --git a/scripts/check-binary-strings.js b/scripts/check-binary-strings.js new file mode 100644 index 00000000..37f07526 --- /dev/null +++ b/scripts/check-binary-strings.js @@ -0,0 +1,57 @@ +#!/usr/bin/env node +// Fails when a shipped native binary carries update/patch/rescue/reload wording +// in its string table (the `strings` view of the file): class and method names, +// log text, source paths and the like are kept neutral or encoded +// (scripts/encode-native-text.ts). Usage: +// node scripts/check-binary-strings.js ... +'use strict'; + +const fs = require('fs'); + +const WORDING = /update|patch|rescue|reload|hotfix/i; +const MIN_LENGTH = 4; + +function printableRuns(buffer) { + const runs = []; + let start = -1; + for (let i = 0; i <= buffer.length; i++) { + const byte = i < buffer.length ? buffer[i] : 0; + const printable = byte >= 0x20 && byte < 0x7f; + if (printable && start < 0) { + start = i; + } else if (!printable && start >= 0) { + if (i - start >= MIN_LENGTH) { + runs.push(buffer.toString('latin1', start, i)); + } + start = -1; + } + } + return runs; +} + +function findWording(file) { + return printableRuns(fs.readFileSync(file)).filter((run) => WORDING.test(run)); +} + +module.exports = { findWording }; + +if (require.main === module) { + const files = process.argv.slice(2); + if (files.length === 0) { + console.error('usage: check-binary-strings.js ...'); + process.exit(2); + } + let failed = false; + for (const file of files) { + const hits = findWording(file); + if (hits.length) { + failed = true; + for (const hit of hits) { + console.error(`error: ${file} contains ${JSON.stringify(hit)}`); + } + } else { + console.log(`ok: ${file} has no update wording in its strings`); + } + } + process.exit(failed ? 1 : 0); +} diff --git a/scripts/verify-android-so.js b/scripts/verify-android-so.js index f3b7cc33..b894a6c4 100644 --- a/scripts/verify-android-so.js +++ b/scripts/verify-android-so.js @@ -14,6 +14,7 @@ */ const fs = require('fs'); const path = require('path'); +const { findWording } = require('./check-binary-strings'); const LIB_DIR = path.resolve(__dirname, '..', 'android', 'lib'); const ABIS = ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']; @@ -194,6 +195,14 @@ for (const abi of ABIS) { } } + const wording = findWording(soPath); + if (wording.length) { + for (const hit of wording) { + console.error(`error: ${soPath} contains ${JSON.stringify(hit)} in its strings`); + } + failed = true; + } + const staticJni = [...symbols].filter((symbol) => symbol.startsWith('Java_')); if (staticJni.length) { for (const symbol of staticJni) {