IOS works!

This commit is contained in:
Gus 2020-11-20 06:40:59 -05:00
parent 6bb93ff447
commit 2eebfee007
15 changed files with 275 additions and 93 deletions

1
.gitignore vendored
View File

@ -58,3 +58,4 @@ android/keystores/debug.keystore
# generated by bob
lib/
**/**/*.swp

View File

@ -61,8 +61,8 @@ target 'TorExample' do
#
# Note that if you have use_frameworks! enabled, Flipper will not work and
# you should disable these next few lines.
add_flipper_pods!
post_install do |installer|
flipper_post_install(installer)
end
# add_flipper_pods!
# post_install do |installer|
# flipper_post_install(installer)
# end
end

View File

@ -142,6 +142,7 @@
ORGANIZATIONNAME = Facebook;
TargetAttributes = {
13B07F861A680F5B00A75B9A = {
DevelopmentTeam = D6MP3CUG29;
LastSwiftMigration = 1110;
};
};
@ -269,6 +270,9 @@
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = D6MP3CUG29;
ENABLE_BITCODE = NO;
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = TorExample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_CFLAGS = (
@ -296,6 +300,9 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = D6MP3CUG29;
ENABLE_BITCODE = NO;
GCC_NO_COMMON_BLOCKS = YES;
INFOPLIST_FILE = TorExample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_CFLAGS = (

View File

@ -12,30 +12,30 @@
#import <React/RCTRootView.h>
#if DEBUG
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
static void InitializeFlipper(UIApplication *application) {
FlipperClient *client = [FlipperClient sharedClient];
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
[client addPlugin:[FlipperKitReactPlugin new]];
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
[client start];
}
//#import <FlipperKit/FlipperClient.h>
//#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
//#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
//#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
//#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
//#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
//static void InitializeFlipper(UIApplication *application) {
// FlipperClient *client = [FlipperClient sharedClient];
// SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
// [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
// [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
// [client addPlugin:[FlipperKitReactPlugin new]];
// [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
// [client start];
//}
#endif
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
#if DEBUG
InitializeFlipper(application);
#endif
// #if DEBUG
// InitializeFlipper(application);
// #endif
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"TorExample"

View File

@ -2,37 +2,52 @@
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}

View File

@ -39,6 +39,12 @@
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>processing</string>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>

View File

@ -1,21 +1,41 @@
import * as React from 'react';
import { StyleSheet, View, Text, Button } from 'react-native';
import Tor from 'react-native-tor';
import { StyleSheet, View, Text, Button, TextInput } from 'react-native';
import TorBridge from 'react-native-tor';
export default function App() {
const [socksPort, setSocksPort] = React.useState<number | undefined>();
const [onion, setOnion] = React.useState<string | undefined>(
'http://keybase5wmilwokqirssclfnsqrjdsi7jdir5wy7y7iu3tanwmtp6oid.onion'
);
const startTor = async () => {
const port = await Tor.startDaemon();
console.log('Tor started socks port', port);
setSocksPort(port);
try {
const port = await TorBridge.startDaemon();
console.log('Tor started socks port', port);
setSocksPort(port);
} catch (err) {
console.error(err);
}
};
const stopTor = async () => {
await Tor.stopDaemon();
try {
await TorBridge.stopDaemon();
} catch (err) {
console.error(err);
}
setSocksPort(undefined);
console.log('Tor stopped');
};
const getOnion = async () => {
try {
if (!onion) throw 'No onion detected';
let resp = await TorBridge.getOnionUrl(onion);
console.log('got resp', resp);
} catch (err) {
console.error(err);
}
};
return (
<View style={styles.container}>
<View>
@ -23,9 +43,22 @@ export default function App() {
<Text>Start Tor</Text>
</Button>
<Button onPress={stopTor} title="Stop Tor" disabled={!!socksPort}>
<Button onPress={stopTor} title="Stop Tor" disabled={!socksPort}>
<Text>Stop Tor</Text>
</Button>
{!!socksPort && (
<View>
<TextInput
style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
onChangeText={setOnion}
value={onion}
/>
<Button onPress={getOnion} title="Get onion">
<Text>Get Onion</Text>
</Button>
</View>
)}
</View>
<Text>SocksPort: {socksPort}</Text>
</View>

View File

@ -1 +1 @@
#import <React/RCTBridgeModule.h>
#import "React/RCTBridgeModule.h"

View File

@ -1,9 +1,19 @@
#import <React/RCTBridgeModule.h>
#import "React/RCTBridgeModule.h"
@interface RCT_EXTERN_MODULE(Tor, NSObject)
@interface RCT_EXTERN_REMAP_MODULE(TorBridge, Tor, NSObject)
RCT_EXTERN_METHOD(multiply:(float)a withB:(float)b
withResolver:(RCTPromiseResolveBlock)resolve
withRejecter:(RCTPromiseRejectBlock)reject)
RCT_EXTERN_METHOD(
startDaemon:(RCTPromiseResolveBlock)resolve
rejecter: (RCTPromiseRejectBlock)reject
)
RCT_EXTERN_METHOD(
stopDaemon:(RCTPromiseResolveBlock)resolve
rejecter: (RCTPromiseRejectBlock)reject
)
RCT_EXTERN_METHOD(
getOnionUrl:(NSString*)url
resolver:(RCTPromiseResolveBlock)resolve
rejecter: (RCTPromiseRejectBlock)reject
)
@end

View File

@ -1,8 +1,88 @@
@objc(Tor)
class Tor: NSObject {
@objc(multiply:withB:withResolver:withRejecter:)
func multiply(a: Float, b: Float, resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock) -> Void {
resolve(a*b)
var service:Optional<OpaquePointer> = nil;
func getProxiedClient()->URLSession{
let config = URLSessionConfiguration.default;
config.requestCachePolicy = URLRequest.CachePolicy.reloadIgnoringLocalCacheData;
config.connectionProxyDictionary = [AnyHashable: Any]();
config.connectionProxyDictionary?[kCFNetworkProxiesHTTPEnable as String] = 1;
config.connectionProxyDictionary?[kCFStreamPropertySOCKSProxyHost as String] = "127.0.0.1";
config.connectionProxyDictionary?[kCFStreamPropertySOCKSProxyPort as String] = 19032;
config.connectionProxyDictionary?[kCFProxyTypeSOCKS as String] = 1;
return URLSession.init(configuration: config, delegate: nil, delegateQueue: OperationQueue.current)
}
@objc(getOnionUrl:resolver:rejecter:)
func getOnionUrl(url:String, resolve:@escaping RCTPromiseResolveBlock,reject:@escaping RCTPromiseRejectBlock){
let session = getProxiedClient();
guard let _url = URL(string:url) else {
// FIXME just to test
reject("TOR","Could not parse url",NSError.init(domain: "TOR", code: 404));
return;
}
do{
let task = session.dataTask(with: _url) { data, resp, error in
guard let dataResp = data , error == nil else {
reject("TOR",error?.localizedDescription,error);
return;
}
resolve(dataResp.base64EncodedString());
return;
}
task.resume();
} catch{
reject("TOR",error.localizedDescription,error);
}
}
@objc(startDaemon:rejecter:)
func startDaemon( resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock)->Void{
if service != nil {
reject("TOR","Tor Service Already Running. Call `stopDaemon` first.",NSError.init(domain: "TOR", code: 99));
return;
}
do {
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(),isDirectory: true)
let socksPort:UInt16 = 19032;
// this gives file:///Users/.../tmp/ so we remove the file:// prefix and trailing slash
let path = try String(temporaryDirectoryURL.absoluteString.dropFirst(7).dropLast());
let call_result = get_owned_TorService(path, socksPort).pointee;
switch(call_result.message.tag){
case Success:
service = Optional.some(call_result.result);
resolve(socksPort);
return;
case Error:
// Convert RustByteSlice to String
let error_body = call_result.message.error._0
let buffer = UnsafeBufferPointer(start: error_body.bytes, count: Int(error_body.len));
if let string = String(bytes: buffer, encoding: String.Encoding.utf8){
reject("TOR",string,NSError.init(domain: "TOR", code: 0))
} else {
reject("TOR","unknown",NSError.init(domain: "TOR", code: 99));
}
return;
default:
reject("TOR","unknown-default",NSError.init(domain: "TOR", code: 99));
return;
}
}
catch {
reject("TOR",error.localizedDescription,error);
}
}
@objc(stopDaemon:rejecter:)
func stopDaemon( resolve:RCTPromiseResolveBlock,reject:RCTPromiseRejectBlock)->Void {
if let hasSevice = service {
shutdown_owned_TorService(hasSevice);
service = nil
}
resolve(true);
}
}

View File

@ -7,11 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
F4FF95D7245B92E800C19C63 /* Tor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D6245B92E800C19C63 /* Tor.swift */; };
5E555C0D2413F4C50049A1A2 /* Tor.mm in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* Tor.mm */; };
85C70A3025646C68003FF04C /* libsifir_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 85C70A2E25646C67003FF04C /* libsifir_ios.a */; };
F4FF95D7245B92E800C19C63 /* Tor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D6245B92E800C19C63 /* Tor.swift */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@ -27,13 +24,12 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
134814201AA4EA6300B7C361 /* libTor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libTor.a; sourceTree = BUILT_PRODUCTS_DIR; };
855294A225646B1000C35C05 /* libTor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; name = libTor.a; path = "/Users/ghassanabidi/Projects/react-native-tor/ios/build/Debug-iphoneos/libTor.a"; sourceTree = "<absolute>"; };
85C70A2E25646C67003FF04C /* libsifir_ios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libsifir_ios.a; sourceTree = "<group>"; };
85C70A2F25646C67003FF04C /* sifir-tor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "sifir-tor.h"; sourceTree = "<group>"; };
B3E7B5891CC2AC0600A0062D /* Tor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Tor.m; sourceTree = "<group>"; };
F4FF95D5245B92E700C19C63 /* Tor-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tor-Bridging-Header.h"; sourceTree = "<group>"; };
F4FF95D6245B92E800C19C63 /* Tor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tor.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -41,30 +37,21 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
85C70A3025646C68003FF04C /* libsifir_ios.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
134814211AA4EA7D00B7C361 /* Products */ = {
isa = PBXGroup;
children = (
134814201AA4EA6300B7C361 /* libTor.a */,
);
name = Products;
sourceTree = "<group>";
};
58B511D21A9E6C8500147676 = {
isa = PBXGroup;
children = (
F4FF95D6245B92E800C19C63 /* Tor.swift */,
B3E7B5891CC2AC0600A0062D /* Tor.m */,
F4FF95D5245B92E700C19C63 /* Tor-Bridging-Header.h */,
134814211AA4EA7D00B7C361 /* Products */,
85C70A2E25646C67003FF04C /* libsifir_ios.a */,
85C70A2F25646C67003FF04C /* sifir-tor.h */,
);
sourceTree = "<group>";
};
@ -85,7 +72,7 @@
);
name = Tor;
productName = RCTDataManager;
productReference = 134814201AA4EA6300B7C361 /* libTor.a */;
productReference = 855294A225646B1000C35C05 /* libTor.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
@ -125,11 +112,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F4FF95D7245B92E800C19C63 /* Tor.swift in Sources */,
B3E7B58A1CC2AC0600A0062D /* Tor.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -238,15 +221,16 @@
"$(SRCROOT)/../../../React/**",
"$(SRCROOT)/../../react-native/React/**",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)",
);
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = Tor;
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "Tor-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
};
name = Debug;
};
@ -259,14 +243,15 @@
"$(SRCROOT)/../../../React/**",
"$(SRCROOT)/../../react-native/React/**",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)",
);
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = Tor;
SKIP_INSTALL = YES;
SWIFT_OBJC_BRIDGING_HEADER = "Tor-Bridging-Header.h";
SWIFT_VERSION = 5.0;
};
name = Release;
};

44
ios/sifir-tor.h Normal file
View File

@ -0,0 +1,44 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct OwnedTorService OwnedTorService_t;
typedef struct {
const uint8_t *bytes;
uintptr_t len;
} RustByteSlice;
typedef enum {
Success,
Error,
} ResultMessage_Tag;
typedef struct {
RustByteSlice _0;
} Error_Body;
typedef struct {
ResultMessage_Tag tag;
union {
Error_Body error;
};
} ResultMessage;
/**
* Since the FFI simply starts and shutdowns the daemon we use an
* Opaque pointer here to pass across the FFI
*/
typedef struct {
OwnedTorService_t *result;
ResultMessage message;
} BoxedResult_OwnedTorService;
BoxedResult_OwnedTorService *get_owned_TorService(const char *data_dir, uint16_t socks_port);
/**
*# Safety
* Destroy and release ownedTorBox which will shut down owned connection and shutdown daemon
*/
void shutdown_owned_TorService(OwnedTorService_t *owned_client);

View File

@ -34,13 +34,13 @@
"ios",
"android"
],
"repository": "https://github.com/gabidi/react-native-tor",
"repository": "",
"author": "gabidi <gabidi@gmail.com> (https://github.com/gabidi)",
"license": "MIT",
"bugs": {
"url": "https://github.com/gabidi/react-native-tor/issues"
"url": "https://github.com/Sifir-io/react-native-tor/issues"
},
"homepage": "https://github.com/gabidi/react-native-tor#readme",
"homepage": "https://github.com/Sifir-io/react-native-tor/",
"devDependencies": {
"@commitlint/config-conventional": "^8.3.4",
"@react-native-community/bob": "^0.16.2",

View File

@ -11,11 +11,11 @@ Pod::Spec.new do |s|
s.authors = package["author"]
s.platforms = { :ios => "9.0" }
s.source = { :git => "https://github.com/gabidi/react-native-tor.git", :tag => "#{s.version}" }
s.source = { :git => "https://github.com/Sifir-io/react-native-tor.git", :tag => "#{s.version}" }
s.source_files = "ios/**/*.{h,m,mm,swift}"
s.ios.vendored_library = "ios/libsifir_ios.a"
s.dependency "React"
end

View File

@ -4,8 +4,9 @@ type SocksPortNumber = number;
type TorType = {
startDaemon(): Promise<SocksPortNumber>;
stopDaemon(): Promise<void>;
getOnionUrl(url: string): Promise<string>;
};
const { Tor } = NativeModules;
const { TorBridge } = NativeModules;
export default Tor as TorType;
export default TorBridge as TorType;