Tor (Simulator): add iOS simulator slice to tor-nolzma.xcframework; wire Xcode project; basic docs

This commit is contained in:
jack
2025-09-12 18:11:14 +02:00
parent 920dc31795
commit a8855dd2ec
772 changed files with 119780 additions and 39 deletions
@@ -0,0 +1,20 @@
//
// NSBundle+GeoIP.h
// Tor
//
// Created by Benjamin Erhart on 02.12.21.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSBundle (GeoIP)
@property (class, readonly, nullable) NSBundle *geoIpBundle;
@property (readonly, nullable) NSURL *geoipFile;
@property (readonly, nullable) NSURL *geoip6File;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,19 @@
//
// NSCharacterSet+PredefinedSets.h
// Tor
//
// Created by Benjamin Erhart on 12.12.19.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface NSCharacterSet (PredefinedSets)
@property (class, readonly) NSCharacterSet *doubleQuote;
@property (class, readonly) NSCharacterSet *longNameDivider;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,140 @@
//
// TORAuthKey.h
// Tor
//
// Created by Benjamin Erhart on 29.09.21.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
The representation of one private or public v3 onion service authentication key.
*/
NS_SWIFT_NAME(TorAuthKey)
@interface TORAuthKey : NSObject
/**
The location on disk, where this data was read from/will be written to.
*/
@property (nonatomic, readonly, nonnull) NSURL *file;
/**
Flag, if this is a private (\c YES) or a public (\c NO) key.
*/
@property (atomic, readonly) BOOL isPrivate;
/**
The full onion service URL.
*/
@property (nonatomic, readonly, nullable) NSURL *onionAddress;
/**
The authentication type.
Currently only the \c descriptor type is supported. This class will set this value hard for you.
*/
@property (nonatomic, readonly, nonnull) NSString *authType;
/**
The key type.
Currently only \c x25519 is supported. This class will set this value hard for you.
Make sure, that the key you provide actually is of that type!
*/
@property (nonatomic, readonly, nonnull) NSString *keyType;
/**
The actual public OR private key.
This class doesn't enforce it, but Tor wants this to be in a BASE32 encoded format.
Make sure, it is of the type \c x25519, as this is currently the only supported type by Tor and by this class!
*/
@property (nonatomic, readonly, nonnull) NSString *key;
/**
Load from a key file on disk.
See https://2019.www.torproject.org/docs/tor-manual.html.en#ClientOnionAuthDir
and https://2019.www.torproject.org/docs/tor-manual.html.en#_client_authorization
for the expected format.
@param url The URL to the file containing the key. Expected to be in the correct format.
*/
- (instancetype)initFromUrl:(NSURL *)url;
/**
Load from a key file on disk.
See https://2019.www.torproject.org/docs/tor-manual.html.en#ClientOnionAuthDir
and https://2019.www.torproject.org/docs/tor-manual.html.en#_client_authorization
for the expected format.
@param path The path to the file containing the key. Expected to be in the correct format.
*/
- (instancetype)initFromFile:(NSString *)path;
/**
Create a new private key for a given domain.
Normally, the domain will be used as file name, but this method will generate a UUID, if no domain can be found.
@param key A \c BASE32 encoded \c x25519 private key.
@param url A URL containing the v3 onion service domain for which this key is.
*/
- (instancetype)initPrivate:(NSString * _Nonnull)key forDomain:(NSURL * _Nonnull)url;
/**
Create a new public key with the given name.
The name wil be used as the file name.
@param key A \c BASE32 encoded \c x25519 public key.
@param name A name to identify this key to be used as the file name.
*/
- (instancetype)initPublic:(NSString * _Nonnull)key withName: (NSString *)name;
/**
Set the base directory for the key.
This needs to be called \b before \c persist, if you created a fresh key.
@param directory The base directory where this key should be persisted.
@see -persist
*/
- (void)setDirectory:(NSURL *)directory;
/**
Persists this key to the file system.
Call \c setDirectory:, if this instance wasn't created by reading a key from a file!
@returns \c YES on success, \c NO on failure.
@see -setDirectory:
*/
- (BOOL)persist;
/**
Keys are considered equal, if their file URLs match.
*/
- (BOOL)isEqualToAuthKey:(TORAuthKey *)authKey;
/**
Checks, if the given file name has the correct extension for either a private or public key.
@param url A file URL to a key file.
@returns \c YES, if this URL contains a key file extension.
*/
+ (BOOL)isAuthFile:(NSURL *)url;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,379 @@
//
// TORCircuit.h
// Tor
//
// Created by Benjamin Erhart on 11.12.19.
//
// Documentation this class is modelled after:
// https://gitlab.torproject.org/tpo/core/torspec/-/raw/main/control-spec.txt
// Chapter 4.1.1 Circuit status changed
#import <Foundation/Foundation.h>
#import "TORNode.h"
NS_ASSUME_NONNULL_BEGIN
NS_SWIFT_NAME(TorCircuit)
@interface TORCircuit : NSObject<NSSecureCoding>
/**
Regular expression to identify and extract ID, status and circuit path consisting of "LongNames".
Syntax of node "LongNames":
https://torproject.gitlab.io/torspec/control-spec.html#general-use-tokens
*/
@property (class, readonly) NSRegularExpression *mainInfoRegex;
/**
- Tag: statusLaunched
Circuit ID assigned to new circuit.
*/
@property (class, readonly) NSString *statusLaunched;
/**
All hops finished, can now accept streams.
*/
@property (class, readonly) NSString *statusBuilt;
/**
All hops finished, waiting to see if a circuit with a better guard will be usable.
*/
@property (class, readonly) NSString *statusGuardWait;
/**
One more hop has been completed.
*/
@property (class, readonly) NSString *statusExtended;
/**
Circuit closed (was not built).
*/
@property (class, readonly) NSString *statusFailed;
/**
Circuit closed (was built).
*/
@property (class, readonly) NSString *statusClosed;
/**
One-hop circuit, used for tunneled directory conns.
*/
@property (class, readonly) NSString *buildFlagOneHopTunnel;
/**
Internal circuit, not to be used for exiting streams.
*/
@property (class, readonly) NSString *buildFlagIsInternal;
/**
This circuit must use only high-capacity nodes.
*/
@property (class, readonly) NSString *buildFlagNeedCapacity;
/**
This circuit must use only high-uptime nodes.
*/
@property (class, readonly) NSString *buildFlagNeedUptime;
/**
Circuit for AP and/or directory request streams.
*/
@property (class, readonly) NSString *purposeGeneral;
/**
HS client-side introduction-point circuit.
*/
@property (class, readonly) NSString *purposeHsClientIntro;
/**
HS client-side rendezvous circuit; carries AP streams.
*/
@property (class, readonly) NSString *purposeHsClientRend;
/**
HS service-side introduction-point circuit.
*/
@property (class, readonly) NSString *purposeHsServiceIntro;
/**
HS service-side rendezvous circuit.
*/
@property (class, readonly) NSString *purposeHsServiceRend;
/**
Circuit created ahead of time when using HS vanguards, and later repurposed as needed.
*/
@property (class, readonly) NSString *purposeHsVanguards;
/**
Reachability-testing circuit; carries no traffic.
*/
@property (class, readonly) NSString *purposeTesting;
/**
Circuit built by a controller.
*/
@property (class, readonly) NSString *purposeController;
/**
Circuit being kept around to see how long it takes.
*/
@property (class, readonly) NSString *purposeMeasureTimeout;
/**
Circuit is part of a conflux multi-path circuit set.
https://tpo.pages.torproject.net/core/doc/tor/structcircuit__t.html#a7826adee26af5def133c43d2fe5f83fa
*/
@property (class, readonly) NSString *purposeConfluxLinked;
/**
Circuit is in the pending pool usable in future circuit sets.
https://tpo.pages.torproject.net/core/doc/tor/structcircuit__t.html#acabcbac5225591a5b7731a6994f438e4
*/
@property (class, readonly) NSString *purposeConfluxUnlinked;
/**
Client-side introduction-point circuit state: Connecting to intro point.
*/
@property (class, readonly) NSString *hsStateHsciConnecting;
/**
Client-side introduction-point circuit state: Sent INTRODUCE1; waiting for reply from IP.
*/
@property (class, readonly) NSString *hsStateHsciIntroSent;
/**
Client-side introduction-point circuit state: Received reply from IP relay; closing.
*/
@property (class, readonly) NSString *hsStateHsciDone;
/**
Client-side rendezvous-point circuit state: Connecting to or waiting for reply from RP.
*/
@property (class, readonly) NSString *hsStateHscrConnecting;
/**
Client-side rendezvous-point circuit state: Established RP; waiting for introduction.
*/
@property (class, readonly) NSString *hsStateHscrEstablishedIdle;
/**
Client-side rendezvous-point circuit state: Introduction sent to HS; waiting for rend.
*/
@property (class, readonly) NSString *hsStateHscrEstablishedWaiting;
/**
Client-side rendezvous-point circuit state: Connected to HS.
*/
@property (class, readonly) NSString *hsStateHscrJoined;
/**
Service-side introduction-point circuit state: Connecting to intro point.
*/
@property (class, readonly) NSString *hsStateHssiConnecting;
/**
Service-side introduction-point circuit state: Established intro point.
*/
@property (class, readonly) NSString *hsStateHssiEstablished;
/**
Service-side rendezvous-point circuit state: Connecting to client's rend point.
*/
@property (class, readonly) NSString *hsStateHssrConnecting;
/**
Service-side rendezvous-point circuit state: Connected to client's RP circuit.
*/
@property (class, readonly) NSString *hsStateHssrJoined;
/**
No reason given.
*/
@property (class, readonly) NSString *reasonNone;
/**
Tor protocol violation.
*/
@property (class, readonly) NSString *reasonTorProtocol;
/**
Internal error.
*/
@property (class, readonly) NSString *reasonInternal;
/**
A client sent a TRUNCATE command.
*/
@property (class, readonly) NSString *reasonRequested;
/**
Not currently operating; trying to save bandwidth.
*/
@property (class, readonly) NSString *reasonHibernating;
/**
Out of memory, sockets, or circuit IDs.
*/
@property (class, readonly) NSString *reasonResourceLimit;
/**
Unable to reach relay.
*/
@property (class, readonly) NSString *reasonConnectFailed;
/**
Connected to relay, but its OR identity was not as expected.
*/
@property (class, readonly) NSString *reasonOrIdentity;
/**
The OR connection that was carrying this circuit died.
*/
@property (class, readonly) NSString *reasonOrConnClosed;
/**
Circuit construction took too long.
*/
@property (class, readonly) NSString *reasonTimeout;
/**
The circuit has expired for being dirty or old.
*/
@property (class, readonly) NSString *reasonFinished;
/**
The circuit was destroyed w/o client TRUNCATE.
*/
@property (class, readonly) NSString *reasonDestroyed;
/**
Not enough nodes to make circuit.
*/
@property (class, readonly) NSString *reasonNoPath;
/**
Request for unknown hidden service.
*/
@property (class, readonly) NSString *reasonNoSuchService;
/**
As @c reasonTimeout, except that we had left the circuit open for measurement purposes to see how long it would take to finish.
*/
@property (class, readonly) NSString *reasonMeasurementExpired;
/**
The raw data this object is constructed from. The unchanged argument from @c initFromString:.
*/
@property (readonly, nullable) NSString *raw;
/**
The circuit ID. Currently only numbers beginning with "1" but Tor spec says, that could change.
*/
@property (readonly, nullable) NSString *circuitId;
/**
The circuit status. Should be one of @c statusLaunched, @c statusBuilt, @c statusGuardWait,
@c statusExtended, @c statusFailed or @c statusClosed .
*/
@property (readonly, nullable) NSString *status;
/**
The circuit path as a list of @c TORNode objects.
*/
@property (readonly, nullable) NSArray<TORNode *> *nodes;
/**
Build flags of the circuit. Can be any of @c buildFlagOneHopTunnel, @c buildFlagIsInternal,
@c buildFlagNeedCapacity, @c buildFlagNeedUptime or a flag which was unknown at the time of
writing of this class.
*/
@property (readonly, nullable) NSArray<NSString *> *buildFlags;
/**
Circuit purpose. May be one of @c purposeGeneral, @c purposeHsClientIntro,
@c purposeHsClientRend, @c purposeHsServiceIntro, @c purposeHsServiceRend,
@c purposeTesting, @c purposeController or, @c purposeMeasureTimeout.
*/
@property (readonly, nullable) NSString *purpose;
/**
Circuit hidden service state. May be one of @c hsStateHsciConnecting, @c hsStateHsciIntroSent,
@c hsStateHsciDone, @c hsStateHscrConnecting, @c hsStateHscrEstablishedIdle,
@c hsStateHscrEstablishedWaiting, @c hsStateHscrJoined, @c hsStateHssiConnecting,
@c hsStateHssiEstablished, @c hsStateHssrConnecting, @c hsStateHssrJoined
or a state which was unknown at the time of writing of this class.
*/
@property (readonly, nullable) NSString *hsState;
/**
The rendevouz query.
Should be equal the onion address this circuit was used for minus the @c .onion postfix.
*/
@property (readonly, nullable) NSString *rendQuery;
/**
The circuit's timestamp at which the circuit was created or cannibalized.
*/
@property (readonly, nullable) NSDate *timeCreated;
/**
The @c reason field is provided only for @c FAILED and @c CLOSED events, and only if
extended events are enabled.
May be any one of @c reasonNone, @c reasonTorProtocol, @c reasonInternal,
@c reasonRequested, @c reasonHibernating, @c reasonResourceLimit,
@c reasonConnectFailed, @c reasonOrIdentity, @c reasonOrConnClosed,
@c reasonTimeout, @c reasonFinished, @c reasonDestroyed, @c reasonNoPath,
@c reasonNoSuchService, @c reasonMeasurementExpired or a reason which was unknown at the
time of writing of this class.
*/
@property (readonly, nullable) NSString *reason;
/**
The @c remoteReason field is provided only when we receive a @c DESTROY or @c TRUNCATE cell, and
only if extended events are enabled. It contains the actual reason given by the remote OR for closing the circuit.
May be any one of @c reasonNone, @c reasonTorProtocol, @c reasonInternal,
@c reasonRequested, @c reasonHibernating, @c reasonResourceLimit,
@c reasonConnectFailed, @c reasonOrIdentity, @c reasonOrConnClosed,
@c reasonTimeout, @c reasonFinished, @c reasonDestroyed, @c reasonNoPath,
@c reasonNoSuchService, @c reasonMeasurementExpired or a reason which was unknown at the
time of writing of this class.
*/
@property (readonly, nullable) NSString *remoteReason;
/**
The @c socksUsername and @c socksPassword fields indicate the credentials that were used by a
SOCKS client to connect to Tors SOCKS port and initiate this circuit.
*/
@property (readonly, nullable) NSString *socksUsername;
/**
The @c socksUsername and @c socksPassword fields indicate the credentials that were used by a
SOCKS client to connect to Tors SOCKS port and initiate this circuit.
*/
@property (readonly, nullable) NSString *socksPassword;
/**
Extracts all circuit info from a string which should be the response to a "GETINFO circuit-status".
See https://torproject.gitlab.io/torspec/control-spec.html#getinfo
@param circuitsString A string as returned by "GETINFO circuit-status".
*/
+ (NSArray<TORCircuit *> *)circuitsFromString:(NSString *)circuitsString;
- (instancetype)initFromString:(NSString *)circuitString;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,46 @@
//
// TORConfiguration.h
// Tor
//
// Created by Conrad Kramer on 8/10/15.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
NS_SWIFT_NAME(TorConfiguration)
@interface TORConfiguration : NSObject
@property (nonatomic, copy, nullable) NSURL *dataDirectory;
@property (nonatomic, copy, nullable) NSURL *cacheDirectory;
@property (nonatomic, copy, nullable, readonly) NSURL *controlPortFile;
@property (nonatomic, copy, nullable) NSURL *controlSocket;
@property (nonatomic, copy, nullable) NSURL *socksURL;
@property (nonatomic) NSUInteger socksPort;
@property (nonatomic) NSUInteger dnsPort;
@property (nonatomic, copy, nullable) NSURL *clientAuthDirectory;
@property (nonatomic, copy, nullable) NSURL *hiddenServiceDirectory;
@property (nonatomic, copy, nullable, readonly) NSURL *serviceAuthDirectory;
@property (nonatomic, copy, nullable) NSURL *geoipFile;
@property (nonatomic, copy, nullable) NSURL *geoip6File;
@property (nonatomic, copy, nullable) NSURL *logfile;
@property (nonatomic) BOOL ignoreMissingTorrc;
@property (nonatomic) BOOL cookieAuthentication;
@property (nonatomic) BOOL autoControlPort;
@property (nonatomic) BOOL avoidDiskWrites;
@property (nonatomic) BOOL clientOnly;
@property (nonatomic, readonly) BOOL isLocked;
@property (nonatomic, copy, nullable, readonly) NSData *cookie;
@property (nonatomic, copy, null_resettable) NSMutableDictionary<NSString *, NSString *> *options;
@property (nonatomic, copy, null_resettable) NSMutableArray<NSString *> *arguments;
- (NSString *)valueOf:(NSString *)key;
- (NSArray<NSString *> *)compile;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,24 @@
//
// TORControlCommand.h
// Tor
//
// Created by Denis Kutlubaev on 30.03.2021.
//
#ifndef TORControlCommand_h
#define TORControlCommand_h
/** TOR control commands
https://github.com/torproject/torspec/blob/master/control-spec.txt
*/
static NSString * const TORCommandAuthenticate = @"AUTHENTICATE";
static NSString * const TORCommandSignalShutdown = @"SIGNAL SHUTDOWN";
static NSString * const TORCommandResetConf = @"RESETCONF";
static NSString * const TORCommandSetConf = @"SETCONF";
static NSString * const TORCommandSetEvents = @"SETEVENTS";
static NSString * const TORCommandGetInfo = @"GETINFO";
static NSString * const TORCommandSignalReload = @"SIGNAL RELOAD";
static NSString * const TORCommandSignalNewnym = @"SIGNAL NEWNYM";
static NSString * const TORCommandCloseCircuit = @"CLOSECIRCUIT";
#endif /* TORControlCommand_h */
@@ -0,0 +1,72 @@
//
// TORControlReplyCode.h
// Tor
//
// Created by Denis Kutlubaev on 30.03.2021.
//
#ifndef TORControlReplyCode_h
#define TORControlReplyCode_h
/**
TOR control reply codes
https://github.com/torproject/torspec/blob/master/control-spec.txt
The following codes are defined:
250 OK
251 Operation was unnecessary
[Tor has declined to perform the operation, but no harm was done.]
451 Resource exhausted
500 Syntax error: protocol
510 Unrecognized command
511 Unimplemented command
512 Syntax error in command argument
513 Unrecognized command argument
514 Authentication required
515 Bad authentication
550 Unspecified Tor error
551 Internal error
[Something went wrong inside Tor, so that the client's
request couldn't be fulfilled.]
552 Unrecognized entity
[A configuration key, a stream ID, circuit ID, event,
mentioned in the command did not actually exist.]
553 Invalid configuration value
[The client tried to set a configuration option to an
incorrect, ill-formed, or impossible value.]
554 Invalid descriptor
555 Unmanaged entity
650 Asynchronous event notification
*/
typedef NS_ENUM(NSInteger, TORControlReplyCode) {
TORControlReplyCodeOK = 250,
TORControlReplyCodeOperationWasUnnecessary = 251,
TORControlReplyCodeResourceExhaused = 451,
TORControlReplyCodeSyntaxErrorProtocol = 500,
TORControlReplyCodeUnrecognizedCommand = 510,
TORControlReplyCodeUnimplementedCommand = 511,
TORControlReplyCodeSyntaxErrorInCommandArgument = 512,
TORControlReplyCodeUnrecognizedCommandArgument = 513,
TORControlReplyCodeAuthenticationRequired = 514,
TORControlReplyCodeBadAuthentication = 515,
TORControlReplyCodeUnspecifiedTorError = 550,
TORControlReplyCodeInternalError = 551,
TORControlReplyCodeUnrecognizedEntity = 552,
TORControlReplyCodeInvalidConfigurationValue = 553,
TORControlReplyCodeInvalidDescriptor = 554,
TORControlReplyCodeUnmanagedEntity = 555,
TORControlReplyCodeAsynchronousEventNotification = 650
};
#endif /* TORControlReplyCode_h */
@@ -0,0 +1,110 @@
//
// TORController.h
// Tor
//
// Created by Conrad Kramer on 5/10/14.
//
#import <Foundation/Foundation.h>
#import "TORCircuit.h"
#ifdef __cplusplus
#define TOR_EXTERN extern "C" __attribute__((visibility ("default")))
#else
#define TOR_EXTERN extern __attribute__((visibility ("default")))
#endif
NS_ASSUME_NONNULL_BEGIN
typedef BOOL (^TORObserverBlock)(NSArray<NSNumber *> *codes, NSArray<NSData *> *lines, BOOL *stop);
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
TOR_EXTERN NSErrorDomain const TORControllerErrorDomain;
#else
TOR_EXTERN NSString * const TORControllerErrorDomain;
#endif
NS_SWIFT_NAME(TorController)
@interface TORController : NSObject
@property (nonatomic, readonly, copy) NSOrderedSet<NSString *> *events;
@property (nonatomic, readonly, getter=isConnected) BOOL connected;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithSocketURL:(NSURL *)url NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithSocketHost:(NSString *)host port:(in_port_t)port NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithControlPortFile:(NSURL *)file;
- (BOOL)connect:(out NSError **)error;
- (void)disconnect;
// Commands
- (void)authenticateWithData:(NSData *)data completion:(void (^__nullable)(BOOL success, NSError * __nullable error))completion;
- (void)resetConfForKey:(NSString *)key completion:(void (^__nullable)(BOOL success, NSError * __nullable error))completion;
- (void)setConfForKey:(NSString *)key withValue:(NSString *)value completion:(void (^__nullable)(BOOL success, NSError * __nullable error))completion;
- (void)setConfs:(NSArray<NSDictionary *> *)configs completion:(void (^__nullable)(BOOL success, NSError * __nullable error))completion;
- (void)listenForEvents:(NSArray<NSString *> *)events completion:(void (^__nullable)(BOOL success, NSError * __nullable error))completion;
- (void)getInfoForKeys:(NSArray<NSString *> *)keys completion:(void (^)(NSArray<NSString *> *values))completion; // TODO: Provide errors
- (void)getSessionConfiguration:(void (^)(NSURLSessionConfiguration * __nullable configuration))completion;
- (void)sendCommand:(NSString *)command arguments:(nullable NSArray<NSString *> *)arguments data:(nullable NSData *)data observer:(TORObserverBlock)observer;
/**
Get a list of all currently available circuits with detailed information about their nodes.
@note There's no clear way to determine, which circuit actually was used by a specific request.
@param completion The callback upon completion of the task. Will return A list of `TORCircuit`s . Empty if no circuit could be found.
*/
- (void)getCircuits:(void (^)(NSArray<TORCircuit *> * _Nonnull circuits))completion;
/**
Resets the Tor connection: Sends "SIGNAL RELOAD" and "SIGNAL NEWNYM" to the Tor thread.
See https://torproject.gitlab.io/torspec/control-spec.html#signal
@param completion Completion callback. Will return true, if signal calls where successful, false if not.
*/
- (void)resetConnection:(void (^__nullable)(BOOL success))completion;
/**
Try to close a list of circuits identified by their IDs.
If some closings weren't successful, the most obvious reason would be, that the circuit with the given
ID doesn't exist (anymore). So in many circumstances, you can still consider that an ok outcome.
@param circuitIds List of circuit IDs.
@param completion Completion callback. Will return true, if *all* closings were successful, false, if *at least one* closing failed.
*/
- (void)closeCircuitsByIds:(NSArray<NSString *> *)circuitIds completion:(void (^__nullable)(BOOL success))completion;
/**
Try to close a list of given circuits.
The given circuits are invalid afterwards, as you just closed them. You should throw them away on completion.
@param circuits List of circuits to close.
@param completion Completion callback. Will return true, if *all* closings were successful, false, if *at least one* closing failed.
*/
- (void)closeCircuits:(NSArray<TORCircuit *> *)circuits completion:(void (^__nullable)(BOOL success))completion;
/**
Resolve countries of given `TORNode`s and updates their `countryCode` property on success.
Nodes which already contain a `countryCode` will be ignored.
IPv4 addresses will be preferred, if Tor is able to resolve IPv4 addresses (if it has loaded the IPv4 geoip database),
and if the node has a `ipv4Address` property of non-zero length.
@param nodes List of `TORNode`s to resolve countries for.
@param testCapabilities Ask Tor first, if it is actually able to resolve. (If GeoDB databases are loaded.) Pass NO, if you're sure that Tor is able to to save on queries.
@param completion Completion callback.
*/
- (void)resolveCountriesOfNodes:(NSArray<TORNode *> * _Nullable)nodes testCapabilities:(BOOL)testCapabilities completion:(void (^__nullable)(void))completion;
// Observers
- (id)addObserverForCircuitEstablished:(void (^)(BOOL established))block;
- (id)addObserverForStatusEvents:(BOOL (^)(NSString *type, NSString *severity, NSString *action, NSDictionary<NSString *, NSString *> * __nullable arguments))block;
- (void)removeObserver:(nullable id)observer;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,23 @@
//
// TORLogging.h
// Tor
//
// Created by Benjamin Erhart on 9/9/17.
//
#import <Foundation/Foundation.h>
#import <os/log.h>
NS_ASSUME_NONNULL_BEGIN
typedef void(* tor_log_cb)(os_log_type_t severity, const char* msg);
extern void TORInstallEventLogging(void);
extern void TORInstallEventLoggingCallback(tor_log_cb cb);
extern void TORInstallTorLogging(void);
extern void TORInstallTorLoggingCallback(tor_log_cb cb);
NS_ASSUME_NONNULL_END
@@ -0,0 +1,95 @@
//
// TORNode.h
// Tor
//
// Created by Benjamin Erhart on 09.12.19.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
NS_SWIFT_NAME(TorNode)
@interface TORNode : NSObject<NSSecureCoding>
/**
Regular expression to identify and extract a valid IPv4 address.
Taken from https://nbviewer.jupyter.org/github/rasbt/python_reference/blob/master/tutorials/useful_regex.ipynb
*/
@property (class, nonatomic, readonly) NSRegularExpression *ipv4Regex;
/**
Regular expression to identify and extract a valid IPv6 address.
Taken from https://nbviewer.jupyter.org/github/rasbt/python_reference/blob/master/tutorials/useful_regex.ipynb
*/
@property (class, nonatomic, readonly) NSRegularExpression *ipv6Regex;
/**
The fingerprint aka. ID of a Tor node.
*/
@property (nonatomic, nullable) NSString *fingerprint;
/**
The nickname of a Tor node.
*/
@property (nonatomic, nullable) NSString *nickName;
/**
The IPv4 address of a Tor node.
*/
@property (nonatomic, nullable) NSString *ipv4Address;
/**
The IPv6 address of a Tor node.
*/
@property (nonatomic, nullable) NSString *ipv6Address;
/**
The country code of a Tor node's country.
*/
@property (nonatomic, nullable) NSString *countryCode;
/**
The localized country name of a Tor node's country.
*/
@property (nonatomic, readonly, nullable) NSString *localizedCountryName;
/**
If this node can act as an exit node or not.
*/
@property BOOL isExit;
/**
Create a `TORNode` object from a "LongName" node string which should contain the fingerprint and the nickname.
See https://torproject.gitlab.io/torspec/control-spec.html#general-use-tokens
@param longName A "LongName" identifying a Tor node.
*/
- (instancetype)initFromString:(NSString *)longName;
/**
Creates a list of `TORNode` objects from the response of a `ns/[*]` call which should contain the nickname and IP address(es).
See https://torproject.gitlab.io/torspec/control-spec.html#getinfo
@param nsString Response from `ns/[*]` call, identifying one or more Tor nodes.
@return a list of `TORNode`s discovered in the given string. Might be empty.
*/
+ (NSArray<TORNode *> * _Nonnull)parseFromNsString:(NSString * _Nullable)nsString exitOnly:(BOOL)exitOnly;
/**
Acquires IPv4 and IPv6 addresses from the given string.
See https://torproject.gitlab.io/torspec/control-spec.html#getinfo
@param response Should be the response of a `ns/id/<fingerprint>` call.
*/
- (void)acquireIpAddressesFromNsResponse:(NSString *)response;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,101 @@
//
// TOROnionAuth.h
// Tor
//
// Created by Benjamin Erhart on 29.09.21.
//
#import <Foundation/Foundation.h>
#import "TORAuthKey.h"
NS_ASSUME_NONNULL_BEGIN
/**
Support for Onion v3 service authentication configuration files.
*/
NS_SWIFT_NAME(TorOnionAuth)
@interface TOROnionAuth : NSObject
/**
The directory where this instance expects the private key files to be in.
*/
@property (nonatomic, nullable, readonly) NSURL *privateUrl;
/**
The directory where this instance expects the public key files to be in.
*/
@property (nonatomic, nullable, readonly) NSURL *publicUrl;
/**
The found public and/or private keys in the base \c directory.
@see -directory
*/
@property (nonatomic, nonnull, readonly) NSArray<TORAuthKey *> *keys;
/**
Initialize with a given directory. Will immediately read all keys on disk.
If you have a lot of keys, you might want to do this in a background thread!
@param privateUrl The base directory where the key files live.
Should be the same as you set in \c <ClientOnionAuthDir> for clients.
@param publicUrl The base directory where the key files live.
Should be the same as you set in \c <HiddenServiceDir> for servers.
@see https://2019.www.torproject.org/docs/tor-manual.html.en#ClientOnionAuthDir
@see https://2019.www.torproject.org/docs/tor-manual.html.en#HiddenServiceDir
@see https://2019.www.torproject.org/docs/tor-manual.html.en#_client_authorization
*/
- (instancetype)initWithPrivateDirUrl:(nullable NSURL *)privateUrl andPublicDirUrl:(nullable NSURL *)publicUrl NS_SWIFT_NAME(init(withPrivateDir:andPublicDir:));
/**
Initialize with a given directory. Will immediately read all keys on disk.
If you have a lot of keys, you might want to do this in a background thread!
@param privatePath The base directory where the key files live.
Should be the same as you set in \c <ClientOnionAuthDir> for clients.
@param publicPath The base directory where the key files live.
Should be the same as you set in \c <HiddenServiceDir> for servers.
@see https://2019.www.torproject.org/docs/tor-manual.html.en#ClientOnionAuthDir
@see https://2019.www.torproject.org/docs/tor-manual.html.en#HiddenServiceDir
@see https://2019.www.torproject.org/docs/tor-manual.html.en#_client_authorization
*/
- (instancetype)initWithPrivateDir:(NSString *)privatePath andPublicDir:(NSString *)publicPath NS_SWIFT_NAME(init(withPrivateDir:andPublicDir:));
/**
Add an authentication key (public or private) to the configuration.
If a key with the same file name already exists, it will be overwritten. If not, it will be added at the end of the
\c keys array.
@param key A new or modified key.
@returns \c YES on success, \c NO on failure.
*/
- (BOOL)set:(TORAuthKey *)key;
/**
Remove the key at the specified index.
@param idx The index of the key in \c keys.
@returns \c YES on success, \c NO on failure.
*/
- (BOOL)removeKeyAtIndex:(NSInteger)idx;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,28 @@
//
// TORThread.h
// Tor
//
// Created by Conrad Kramer on 7/19/15.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class TORConfiguration;
NS_SWIFT_NAME(TorThread)
@interface TORThread : NSThread
#if __has_feature(objc_class_property)
@property (class, readonly, nullable) TORThread *activeThread;
#else
+ (nullable TORThread *)activeThread;
#endif
- (instancetype)initWithConfiguration:(nullable TORConfiguration *)configuration;
- (instancetype)initWithArguments:(nullable NSArray<NSString *> *)arguments NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,104 @@
//
// TORX25519KeyPair.h
// Tor
//
// Created by Benjamin Erhart on 11.10.21.
//
#import <Foundation/Foundation.h>
#import "TORAuthKey.h"
NS_ASSUME_NONNULL_BEGIN
/**
Class to generate or hold a X25519 public/private key pair encoded in BASE32.
*/
NS_SWIFT_NAME(TorX25519KeyPair)
@interface TORX25519KeyPair : NSObject
/**
The BASE32 encoded private key. Should be exactly 32 bytes long, resp. 52 characters in BASE32 encoding.
*/
@property (nonatomic, nullable, readonly) NSString *privateKey;
/**
The BASE32 encoded public key. Should be exactly 32 bytes long, resp. 52 characters in BASE32 encoding.
*/
@property (nonatomic, nullable, readonly) NSString *publicKey;
/**
Generate a new X25519 key pair using Tor's implementation.
On iOS 13 and up, another option is also available: CryptoKit's \c Curve25519.KeyAggreement.PrivateKey
*/
- (instancetype)init;
/**
Initialize with a pre-generated, BASE32-encoded X25519 key pair. A valid key pair is exactly 32 bytes long,
resp. 52 characters in BASE32 encoding.
No validity checks are made! It's your responsibility to provide valid key material.
@param privateKey The private key, BASE32 encoded.
@param publicKey The public key, BASE32 encoded.
*/
- (instancetype)initWithBase32PrivateKey:(NSString *)privateKey andPublicKey:(NSString *)publicKey;
/**
Initialize with a pre-generated X25519 key pair. A valid key pair is exactly 32 bytes long.
No validity checks are made! It's your responsibility to provide valid key material.
@param privateKey The private key.
@param publicKey The public key.
*/
- (instancetype)initWithPrivateKey:(NSData *)privateKey andPublicKey:(NSData *)publicKey;
/**
Create a private \c TORAuthKey from this key material using the provided domain.
@param domain The domain name, this private key is for. Must include the \c .onion TLD!
@returns the private \c TORAuthKey of this key pair's private key or \c nil if the \c domain is empty or this class doesn't contain a private key.
*/
- (nullable TORAuthKey *)getPrivateAuthKeyForDomain:(nonnull NSString *)domain;
/**
Create a private \c TORAuthKey from this key material using the provided domain.
@param url The domain, this private key is for.
@returns the private \c TORAuthKey of this key pair's private key or \c nil if this class doesn't contain a private key.
*/
- (nullable TORAuthKey *)getPrivateAuthKeyForUrl:(nonnull NSURL *)url;
/**
Create a public \c TORAuthKey from this key material using the provided name.
@param name The name used to store that \c TORAuthKey, without the extension!
@returns the public \c TORAuthKey of this key pair's public key or \c nil if the \c name is empty or this class doesn't contain a public key.
*/
- (nullable TORAuthKey *)getPublicAuthKeyWithName:(nonnull NSString *)name;
/**
Helper method to BASE32 encode raw binary \c NSData into a \c NSString.
@param raw The raw binary \c NSData to encode.
@returns a BASE32 encoded representation of that binary data.
*/
+ (nullable NSString *)base32Encode:(NSData *)raw;
/**
Helper method to decode raw binary \c NSData contained in a BASE32 encoded \c NSString.
@param encoded The BASE32 encoded data to decode.
@returns binary data.
*/
+ (nullable NSData *)base32Decode:(NSString *)encoded;
@end
NS_ASSUME_NONNULL_END