Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,11 @@ jobs:
yarn build:android

build-ios:
# Vendored TalsecRuntime fallback (FREERASP_DISABLE_SPM=1).
runs-on: macos-latest
needs: build-library
env:
FREERASP_DISABLE_SPM: "1"
steps:
- name: Checkout
uses: actions/checkout@v6
Expand All @@ -99,3 +102,25 @@ jobs:
working-directory: ./example
run: |
yarn build:ios

build-ios-spm:
# SPM path (default, dynamic frameworks).
runs-on: macos-latest
needs: build-library
env:
USE_FRAMEWORKS: dynamic
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup
uses: ./.github/actions/setup

- name: Install pods (SPM)
working-directory: ./example/ios
run: pod install

- name: Build example for iOS (SPM)
working-directory: ./example
run: |
yarn build:ios
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ xcuserdata
*.xccheckout
*.moved-aside
DerivedData
.build/
*.hmap
*.ipa
*.xcuserstate
Expand Down
51 changes: 47 additions & 4 deletions example/ios/FreeraspRNExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
objects = {

/* Begin PBXBuildFile section */
0C80B921A6F3F58F76C31292 /* libPods-FreeraspRNExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-FreeraspRNExample.a */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
B1EB9AB7744AD93A8B6158B0 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; };
C73C359964238BC19E9222C4 /* Pods_FreeraspRNExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E5F6A1D4DB8919B5ABBB72F8 /* Pods_FreeraspRNExample.framework */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
Expand All @@ -21,9 +21,9 @@
13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = FreeraspRNExample/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
3B4392A12AC88292D35C810B /* Pods-FreeraspRNExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FreeraspRNExample.debug.xcconfig"; path = "Target Support Files/Pods-FreeraspRNExample/Pods-FreeraspRNExample.debug.xcconfig"; sourceTree = "<group>"; };
5709B34CF0A7D63546082F79 /* Pods-FreeraspRNExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FreeraspRNExample.release.xcconfig"; path = "Target Support Files/Pods-FreeraspRNExample/Pods-FreeraspRNExample.release.xcconfig"; sourceTree = "<group>"; };
5DCACB8F33CDC322A6C60F78 /* libPods-FreeraspRNExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-FreeraspRNExample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
761780EC2CA45674006654EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = FreeraspRNExample/AppDelegate.swift; sourceTree = "<group>"; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = FreeraspRNExample/LaunchScreen.storyboard; sourceTree = "<group>"; };
E5F6A1D4DB8919B5ABBB72F8 /* Pods_FreeraspRNExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_FreeraspRNExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */

Expand All @@ -32,7 +32,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0C80B921A6F3F58F76C31292 /* libPods-FreeraspRNExample.a in Frameworks */,
C73C359964238BC19E9222C4 /* Pods_FreeraspRNExample.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -55,7 +55,7 @@
isa = PBXGroup;
children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
5DCACB8F33CDC322A6C60F78 /* libPods-FreeraspRNExample.a */,
E5F6A1D4DB8919B5ABBB72F8 /* Pods_FreeraspRNExample.framework */,
);
name = Frameworks;
sourceTree = "<group>";
Expand Down Expand Up @@ -118,6 +118,9 @@
dependencies = (
);
name = FreeraspRNExample;
packageProductDependencies = (
48BC1057BF9DD44F5B4CFB92 /* TalsecRuntime */,
);
productName = FreeraspRNExample;
productReference = 13B07F961A680F5B00A75B9A /* FreeraspRNExample.app */;
productType = "com.apple.product-type.application";
Expand All @@ -144,6 +147,9 @@
Base,
);
mainGroup = 83CBB9F61A601CBA00E9B192;
packageReferences = (
B8E138E288186BEE6FC6ADBA /* XCLocalSwiftPackageReference "TalsecRuntimePackage" */,
);
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
projectDirPath = "";
projectRoot = "";
Expand Down Expand Up @@ -358,6 +364,17 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx",
"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios",
);
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
Expand Down Expand Up @@ -431,6 +448,17 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx",
"${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers",
"${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios",
);
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
Expand Down Expand Up @@ -483,6 +511,21 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */

/* Begin XCLocalSwiftPackageReference section */
B8E138E288186BEE6FC6ADBA /* XCLocalSwiftPackageReference "TalsecRuntimePackage" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = "/Users/tpsota/Documents/Free-RASP-ReactNative/ios/TalsecRuntimePackage";
};
/* End XCLocalSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
48BC1057BF9DD44F5B4CFB92 /* TalsecRuntime */ = {
isa = XCSwiftPackageProductDependency;
package = B8E138E288186BEE6FC6ADBA /* XCLocalSwiftPackageReference "TalsecRuntimePackage" */;
productName = TalsecRuntime;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
}
17 changes: 12 additions & 5 deletions example/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ require Pod::Executable.execute_command('node', ['-p',
platform :ios, min_ios_version_supported
prepare_react_native_project!

linkage = ENV['USE_FRAMEWORKS']
if linkage != nil
Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
use_frameworks! :linkage => linkage.to_sym
end
# freerasp-react-native delivers TalsecRuntime via Swift Package Manager, which
# requires dynamically linked frameworks. Default to dynamic; USE_FRAMEWORKS may
# override the linkage.
linkage = (ENV['USE_FRAMEWORKS'] || 'dynamic').to_sym
Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
use_frameworks! :linkage => linkage

target 'FreeraspRNExample' do
config = use_native_modules!
Expand All @@ -31,5 +32,11 @@ target 'FreeraspRNExample' do
:mac_catalyst_enabled => false,
# :ccache_enabled => true
)

# freeRASP: embed TalsecRuntime into the app target on the SPM path (the helper is a
# no-op / cleanup on the vendored fallback, so it is safe to call unconditionally).
# Real apps resolve the helper from node_modules; this example requires it from the repo root.
require_relative '../../freerasp_spm.rb'
freerasp_embed_talsec_spm!(installer)
end
end
42 changes: 34 additions & 8 deletions freerasp-react-native.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ require "json"
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'

# TalsecRuntime: local SPM manifest by default (RN >= 0.75), vendored xcframework
# fallback. The manifest pins the remote binary URL and checksum.
# Opt out of SPM with FREERASP_DISABLE_SPM=1.
talsec_spm_path = File.expand_path('ios/TalsecRuntimePackage', __dir__)

Pod::Spec.new do |s|
s.name = "freerasp-react-native"
s.version = package["version"]
Expand All @@ -14,14 +19,35 @@ Pod::Spec.new do |s|
s.platforms = { :ios => "11.0" }
s.source = { :git => "https://github.com/talsec/freerasp-react-native.git", :tag => "#{s.version}" }

s.source_files = 'ios/models/*.{h,m,mm,swift}',
'ios/utils/*.{h,m,mm,swift}',
'ios/dispatchers/*.{h,m,mm,swift}',
'ios/*.{h,m,mm,swift}',
'ios/TalsecRuntime.xcframework'
s.xcconfig = { 'OTHER_LDFLAGS' => '-framework TalsecRuntime' }
s.ios.vendored_frameworks = "ios/TalsecRuntime.xcframework"

# SPM is the default whenever the spm_dependency helper is available (RN >= 0.75),
# unless the consumer opts out with FREERASP_DISABLE_SPM=1.
use_spm = respond_to?(:spm_dependency, true) && ENV['FREERASP_DISABLE_SPM'] != '1'

source_globs = [
'ios/models/*.{h,m,mm,swift}',
'ios/utils/*.{h,m,mm,swift}',
'ios/dispatchers/*.{h,m,mm,swift}',
'ios/*.{h,m,mm,swift}',
]

if use_spm
# SPM injects the reference into the Pods project; the framework is embedded into the
# app target by freerasp_embed_talsec_spm! (freerasp_spm.rb), called from the Podfile.
s.ios.deployment_target = '13.0'
spm_dependency(s,
url: talsec_spm_path,
requirement: {},
products: ['TalsecRuntime']
)
else
# Vendored xcframework fallback (RN < 0.75 or FREERASP_DISABLE_SPM=1).
source_globs << 'ios/TalsecRuntime.xcframework'
s.xcconfig = { 'OTHER_LDFLAGS' => '-framework TalsecRuntime' }
s.ios.vendored_frameworks = 'ios/TalsecRuntime.xcframework'
end

s.source_files = source_globs

# Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
# See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
if respond_to?(:install_modules_dependencies, true)
Expand Down
81 changes: 81 additions & 0 deletions freerasp_spm.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# freeRASP — links the local TalsecRuntime Swift package to the pod and embeds its
# product into the app target(s). React Native 0.75–0.83 treats local package paths
# as remote URLs, so this helper also replaces that invalid reference after
# react_native_post_install. It is idempotent and safe to call unconditionally.

def freerasp_embed_talsec_spm!(installer,
package_path: File.expand_path('ios/TalsecRuntimePackage', __dir__),
product: 'TalsecRuntime')

package_path = File.expand_path(package_path)
local_pkg_class = Xcodeproj::Project::Object::XCLocalSwiftPackageReference
remote_pkg_class = Xcodeproj::Project::Object::XCRemoteSwiftPackageReference
ref_class = Xcodeproj::Project::Object::XCSwiftPackageProductDependency

# Mirror the podspec: SPM active unless unavailable (RN < 0.75) or opted out.
spm_active = respond_to?(:spm_dependency, true) && ENV['FREERASP_DISABLE_SPM'] != '1'

if spm_active && !File.file?(File.join(package_path, 'Package.swift'))
raise Pod::Informative, "[freeRASP][SPM] Package.swift not found at #{package_path}"
end

projects_and_targets = {}
pods_project = installer.pods_project
projects_and_targets[pods_project] = pods_project.targets.select do |target|
target.name == 'freerasp-react-native'
end

installer.aggregate_targets.each do |aggregate_target|
project = aggregate_target.user_project
next if project.nil?

app_targets = aggregate_target.user_targets.select do |t|
t.respond_to?(:product_type) && t.product_type == 'com.apple.product-type.application'
end
projects_and_targets[project] ||= []
projects_and_targets[project].concat(app_targets)
end

new_object = lambda do |project, klass|
uuid = project.generate_uuid
uuid = project.generate_uuid while project.objects_by_uuid.key?(uuid)
object = klass.new(project, uuid)
object.initialize_defaults
object
end

projects_and_targets.each do |project, targets|
targets.uniq!

# Remove local and incorrectly-created remote references first.
targets.each do |target|
target.package_product_dependencies.delete_if do |r|
next false unless r.class == ref_class && r.product_name == product

package = r.package
(package.class == local_pkg_class && package.relative_path == package_path) ||
(package.class == remote_pkg_class && package.repositoryURL == package_path)
end
end
project.root_object.package_references.delete_if do |p|
(p.class == local_pkg_class && p.relative_path == package_path) ||
(p.class == remote_pkg_class && p.repositoryURL == package_path)
end

if spm_active
pkg = new_object.call(project, local_pkg_class)
pkg.relative_path = package_path
project.root_object.package_references << pkg

targets.each do |target|
Pod::UI.puts "[freeRASP][SPM] Linking #{product} to target #{target.name}"
dep = new_object.call(project, ref_class)
dep.package = pkg
dep.product_name = product
target.package_product_dependencies << dep
end
end

project.save
end
end
19 changes: 19 additions & 0 deletions ios/TalsecRuntimePackage/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// swift-tools-version:5.9
import PackageDescription

let package = Package(
name: "TalsecRuntime",
platforms: [
.iOS(.v13),
],
products: [
.library(name: "TalsecRuntime", targets: ["TalsecRuntime"]),
],
targets: [
.binaryTarget(
name: "TalsecRuntime",
url: "https://storage.googleapis.com/freerasp/ios/react-native/6.14.4/TalsecRuntime.zip",
checksum: "1ee2ba204688b4f059f9ab30b8f8c769f673f3412c7e46d52a2dc25b3561105b"
),
]
)
1 change: 1 addition & 0 deletions plugin/build/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { type ConfigPlugin } from '@expo/config-plugins';
import { type PluginConfigType } from './pluginConfig';
declare const _default: ConfigPlugin<PluginConfigType>;
export default _default;
Loading
Loading