Support downloading config from server

This commit is contained in:
Peter 2019-10-11 18:13:47 +04:00
parent be07587074
commit aa3f6306d1
13 changed files with 229 additions and 291 deletions

View File

@ -13,7 +13,6 @@ load("//Config:buck_rule_macros.bzl",
) )
framework_dependencies = [ framework_dependencies = [
"//submodules/MtProtoKit:MtProtoKit",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display", "//submodules/Display:Display",

View File

@ -5,7 +5,6 @@ import BuildConfig
import WalletUI import WalletUI
import WalletCore import WalletCore
import AVFoundation import AVFoundation
import MtProtoKit
private func encodeText(_ string: String, _ key: Int) -> String { private func encodeText(_ string: String, _ key: Int) -> String {
var result = "" var result = ""
@ -366,6 +365,7 @@ private final class WalletContextImpl: NSObject, WalletContext, UIImagePickerCon
self.storage = WalletStorageInterfaceImpl(path: basePath + "/data") self.storage = WalletStorageInterfaceImpl(path: basePath + "/data")
self.window = window self.window = window
self.tonInstance = TonInstance( self.tonInstance = TonInstance(
basePath: basePath + "/keys", basePath: basePath + "/keys",
config: config, config: config,
@ -544,6 +544,10 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
), backgroundDetailsMode: nil ), backgroundDetailsMode: nil
) )
mainWindow.viewController = navigationController
self.window?.makeKeyAndVisible()
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
print("Starting with \(documentsPath)") print("Starting with \(documentsPath)")
@ -573,230 +577,87 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
} }
""" """
let walletContext = WalletContextImpl(basePath: documentsPath, config: config, blockchainName: "testnet", navigationBarTheme: navigationBarTheme, window: mainWindow) let updatedConfigSignal: Signal<String, NoError> = Signal { subscriber in
self.walletContext = walletContext let downloadTask = URLSession.shared.downloadTask(with: URL(string: "https://test.ton.org/ton-lite-client-test1.config.json")!, completionHandler: { location, _, error in
if let location = location, let data = try? Data(contentsOf: location), let string = String(data: data, encoding: .utf8) {
subscriber.putNext(string)
subscriber.putCompletion()
}
})
downloadTask.resume()
return ActionDisposable {
}
}
let _ = (combineLatest(queue: .mainQueue(), let updatedConfig = Promise<String>()
walletContext.storage.getWalletRecords(), updatedConfig.set(updatedConfigSignal)
walletContext.keychain.encryptionPublicKey()
) let configPath = documentsPath + "/config"
|> deliverOnMainQueue).start(next: { records, publicKey in var initialConfig: Signal<String, NoError> = .complete()
if let record = records.first { if let data = try? Data(contentsOf: URL(fileURLWithPath: configPath)), let string = String(data: data, encoding: .utf8) {
if let publicKey = publicKey { initialConfig = .single(string)
print("publicKey = \(publicKey.base64EncodedString())") } else {
if record.info.encryptedSecret.publicKey == publicKey { initialConfig = updatedConfig.get() |> take(1)
if record.exportCompleted { }
let _ = (walletAddress(publicKey: record.info.publicKey, tonInstance: walletContext.tonInstance)
|> deliverOnMainQueue).start(next: { address in let _ = (initialConfig
let infoScreen = WalletInfoScreen(context: walletContext, walletInfo: record.info, address: address, enableDebugActions: false) |> deliverOnMainQueue).start(next: { initialConfig in
let walletContext = WalletContextImpl(basePath: documentsPath, config: initialConfig, blockchainName: "testnet", navigationBarTheme: navigationBarTheme, window: mainWindow)
self.walletContext = walletContext
let _ = (updatedConfig.get()
|> deliverOnMainQueue).start(next: { config in
if config != initialConfig {
walletContext.tonInstance.updateConfig(config: config, blockchainName: "testnet")
}
})
let _ = (combineLatest(queue: .mainQueue(),
walletContext.storage.getWalletRecords(),
walletContext.keychain.encryptionPublicKey()
)
|> deliverOnMainQueue).start(next: { records, publicKey in
if let record = records.first {
if let publicKey = publicKey {
print("publicKey = \(publicKey.base64EncodedString())")
if record.info.encryptedSecret.publicKey == publicKey {
if record.exportCompleted {
let _ = (walletAddress(publicKey: record.info.publicKey, tonInstance: walletContext.tonInstance)
|> deliverOnMainQueue).start(next: { address in
let infoScreen = WalletInfoScreen(context: walletContext, walletInfo: record.info, address: address, enableDebugActions: false)
navigationController.setViewControllers([infoScreen], animated: false) navigationController.setViewControllers([infoScreen], animated: false)
}) })
} else {
let createdScreen = WalletSplashScreen(context: walletContext, mode: .created(record.info, nil), walletCreatedPreloadState: nil)
navigationController.setViewControllers([createdScreen], animated: false)
}
} else { } else {
let createdScreen = WalletSplashScreen(context: walletContext, mode: .created(record.info, nil), walletCreatedPreloadState: nil) let splashScreen = WalletSplashScreen(context: walletContext, mode: .secureStorageReset(.changed), walletCreatedPreloadState: nil)
navigationController.setViewControllers([createdScreen], animated: false) navigationController.setViewControllers([splashScreen], animated: false)
} }
} else { } else {
let splashScreen = WalletSplashScreen(context: walletContext, mode: .secureStorageReset(.changed), walletCreatedPreloadState: nil) let splashScreen = WalletSplashScreen(context: walletContext, mode: WalletSplashMode.secureStorageReset(.notAvailable), walletCreatedPreloadState: nil)
navigationController.setViewControllers([splashScreen], animated: false) navigationController.setViewControllers([splashScreen], animated: false)
} }
} else { } else {
let splashScreen = WalletSplashScreen(context: walletContext, mode: WalletSplashMode.secureStorageReset(.notAvailable), walletCreatedPreloadState: nil) if publicKey != nil {
let splashScreen = WalletSplashScreen(context: walletContext, mode: .intro, walletCreatedPreloadState: nil)
navigationController.setViewControllers([splashScreen], animated: false)
navigationController.setViewControllers([splashScreen], animated: false)
} else {
let splashScreen = WalletSplashScreen(context: walletContext, mode: .secureStorageNotAvailable, walletCreatedPreloadState: nil)
navigationController.setViewControllers([splashScreen], animated: false)
}
} }
} else { })
if publicKey != nil {
let splashScreen = WalletSplashScreen(context: walletContext, mode: .intro, walletCreatedPreloadState: nil)
navigationController.setViewControllers([splashScreen], animated: false)
} else {
let splashScreen = WalletSplashScreen(context: walletContext, mode: .secureStorageNotAvailable, walletCreatedPreloadState: nil)
navigationController.setViewControllers([splashScreen], animated: false)
}
}
}) })
mainWindow.viewController = navigationController
self.window?.makeKeyAndVisible()
return true return true
} }
} }
private final class Serialization: NSObject, MTSerialization {
func currentLayer() -> UInt {
return 106
}
func parseMessage(_ data: Data!) -> Any! {
return nil
}
func exportAuthorization(_ datacenterId: Int32, data: AutoreleasingUnsafeMutablePointer<NSData?>!) -> MTExportAuthorizationResponseParser! {
return nil
}
func importAuthorization(_ authId: Int32, bytes: Data!) -> Data! {
return Data()
}
func requestDatacenterAddress(with data: AutoreleasingUnsafeMutablePointer<NSData?>!) -> MTRequestDatacenterAddressListParser! {
return { _ in
return nil
}
}
func requestNoop(_ data: AutoreleasingUnsafeMutablePointer<NSData?>!) -> MTRequestNoopParser! {
return { _ in
return nil
}
}
}
private final class Keychain: NSObject, MTKeychain {
let get: (String) -> Data?
let set: (String, Data) -> Void
let remove: (String) -> Void
init(get: @escaping (String) -> Data?, set: @escaping (String, Data) -> Void, remove: @escaping (String) -> Void) {
self.get = get
self.set = set
self.remove = remove
}
func setObject(_ object: Any!, forKey aKey: String!, group: String!) {
if let object = object {
let data = NSKeyedArchiver.archivedData(withRootObject: object)
self.set(group + ":" + aKey, data)
} else {
self.remove(group + ":" + aKey)
}
}
func object(forKey aKey: String!, group: String!) -> Any! {
if let data = self.get(group + ":" + aKey) {
return NSKeyedUnarchiver.unarchiveObject(with: data as Data)
}
return nil
}
func removeObject(forKey aKey: String!, group: String!) {
self.remove(group + ":" + aKey)
}
func dropGroup(_ group: String!) {
}
}
private final class TonProxyImpl: TonNetworkProxy {
private let context: MTContext
private let mtProto: MTProto
private let requestService: MTRequestMessageService
init() {
let serialization = Serialization()
var apiEnvironment = MTApiEnvironment()
apiEnvironment.apiId = 8
apiEnvironment.langPack = "ios"
apiEnvironment.layer = serialization.currentLayer() as NSNumber
apiEnvironment.disableUpdates = true
apiEnvironment = apiEnvironment.withUpdatedLangPackCode("en")
self.context = MTContext(serialization: serialization, apiEnvironment: apiEnvironment, isTestingEnvironment: false, useTempAuthKeys: false)
let seedAddressList: [Int: [String]]
seedAddressList = [
1: ["149.154.175.50", "2001:b28:f23d:f001::a"],
2: ["149.154.167.50", "2001:67c:4e8:f002::a"],
3: ["149.154.175.100", "2001:b28:f23d:f003::a"],
4: ["149.154.167.91", "2001:67c:4e8:f004::a"],
5: ["149.154.171.5", "2001:b28:f23f:f005::a"]
]
for (id, ips) in seedAddressList {
self.context.setSeedAddressSetForDatacenterWithId(id, seedAddressSet: MTDatacenterAddressSet(addressList: ips.map { MTDatacenterAddress(ip: $0, port: 443, preferForMedia: false, restrictToTcp: false, cdn: false, preferForProxy: false, secret: nil)! }))
}
let keychainDict = Atomic<[String: Data]>(value: [:])
self.context.keychain = Keychain(get: { key in
return keychainDict.with { dict -> Data? in
return dict[key]
}
}, set: { key, value in
let _ = keychainDict.modify { dict in
var dict = dict
dict[key] = value
return dict
}
}, remove: { key in
let _ = keychainDict.modify { dict in
var dict = dict
dict.removeValue(forKey: key)
return dict
}
})
let mtProto = MTProto(context: self.context, datacenterId: 2, usageCalculationInfo: nil)!
mtProto.useTempAuthKeys = self.context.useTempAuthKeys
mtProto.checkForProxyConnectionIssues = false
self.mtProto = mtProto
self.requestService = MTRequestMessageService(context: context)!
mtProto.add(self.requestService)
self.mtProto.resume()
}
func request(data: Data, timeout: Double, completion: @escaping (TonNetworkProxyResult) -> Void) -> Disposable {
let request = MTRequest()
let outputStream = MTOutputStream()
//wallet.sendLiteRequest#e2c9d33e body:bytes = wallet.LiteResponse;
outputStream.write(Int32(bitPattern: 0xe2c9d33e as UInt32))
outputStream.writeBytes(data)
request.setPayload(outputStream.currentBytes(), metadata: "wallet.sendLiteRequest", shortMetadata: "wallet.sendLiteRequest", responseParser: { response in
guard let response = response else {
return nil
}
let inputStream = MTInputStream(data: response)!
//wallet.liteResponse#764386d7 response:bytes = wallet.LiteResponse;
let signature = inputStream.readInt32()
if (signature != 0x764386d7 as Int32) {
return nil
}
return inputStream.readBytes()
})
request.dependsOnPasswordEntry = false
request.shouldContinueExecutionWithErrorContext = { _ in
return true
};
request.completed = { response, _, error in
if let response = response as? Data {
completion(.reponse(response))
} else {
completion(.error(error?.errorDescription ?? "UNKNOWN ERROR"))
}
}
let requestId = request.internalId
self.requestService.add(request)
return ActionDisposable { [weak self] in
self?.requestService.removeRequest(byInternalId: requestId)
}
}
}

View File

@ -22,7 +22,7 @@ static_library(
"Sources/*.h", "Sources/*.h",
]), ]),
deps = [ deps = [
"//submodules/MtProtoKit:MtProtoKit#shared", "//submodules/PKCS:PKCS",
], ],
frameworks = [ frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework", "$SDKROOT/System/Library/Frameworks/Foundation.framework",

View File

@ -10,11 +10,17 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifdef BUCK #import <CommonCrypto/CommonCrypto.h>
#import <MtProtoKit/MtProtoKit.h> #import <CommonCrypto/CommonDigest.h>
#else
#import <MtProtoKitDynamic/MtProtoKitDynamic.h> #import <PKCS/PKCS.h>
#endif
static NSData *sha1(NSData *data) {
uint8_t digest[20];
CC_SHA1(data.bytes, (CC_LONG)data.length, digest);
return [[NSData alloc] initWithBytes:digest length:20];
}
static NSString *telegramApplicationSecretKey = @"telegramApplicationSecretKey_v3"; static NSString *telegramApplicationSecretKey = @"telegramApplicationSecretKey_v3";
@ -376,7 +382,7 @@ API_AVAILABLE(ios(10))
_dataDict[@"name"] = signature.subjectName; _dataDict[@"name"] = signature.subjectName;
} }
if (signature.data != nil) { if (signature.data != nil) {
_dataDict[@"data"] = [MTSha1(signature.data) base64EncodedStringWithOptions:0]; _dataDict[@"data"] = [sha1(signature.data) base64EncodedStringWithOptions:0];
_dataDict[@"data1"] = [signature.data base64EncodedStringWithOptions:0]; _dataDict[@"data1"] = [signature.data base64EncodedStringWithOptions:0];
} }
} }

View File

@ -16,6 +16,8 @@ public enum StatusBarStyle {
self = .White self = .White
case .blackOpaque: case .blackOpaque:
self = .Black self = .Black
default:
self = .Black
} }
} }

20
submodules/PKCS/BUCK Normal file
View File

@ -0,0 +1,20 @@
load("//Config:buck_rule_macros.bzl", "static_library")
static_library(
name = "PKCS",
srcs = glob([
"Sources/**/*.m",
]),
headers = glob([
"Sources/**/*.h",
]),
exported_headers = glob([
"Sources/**/*.h",
]),
deps = [
"//submodules/openssl:openssl",
],
frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
],
)

View File

@ -4,13 +4,17 @@ static_library(
name = "TonBinding", name = "TonBinding",
srcs = glob([ srcs = glob([
"Sources/**/*.m", "Sources/**/*.m",
"Sources/**/*.mm",
]), ]),
headers = merge_maps([ headers = glob([
"Sources/**/*.h",
]),
exported_headers = glob([
"Sources/**/*.h", "Sources/**/*.h",
]), ]),
visibility = ["PUBLIC"], visibility = ["PUBLIC"],
deps = [ deps = [
"//submodules/SSignalKit/SignalKit:SSignalKit", "//submodules/SSignalKit/SSignalKit:SSignalKit",
"//submodules/openssl:openssl", "//submodules/openssl:openssl",
"//submodules/ton:ton", "//submodules/ton:ton",
], ],

View File

@ -1,9 +1,8 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <SSignalKit/SSignalKit.h>
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@class MTSignal;
@interface TONError : NSObject @interface TONError : NSObject
@property (nonatomic, strong, readonly) NSString *text; @property (nonatomic, strong, readonly) NSString *text;
@ -88,15 +87,17 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithKeystoreDirectory:(NSString *)keystoreDirectory config:(NSString *)config blockchainName:(NSString *)blockchainName performExternalRequest:(void (^)(TONExternalRequest * _Nonnull))performExternalRequest enableExternalRequests:(bool)enableExternalRequests; - (instancetype)initWithKeystoreDirectory:(NSString *)keystoreDirectory config:(NSString *)config blockchainName:(NSString *)blockchainName performExternalRequest:(void (^)(TONExternalRequest * _Nonnull))performExternalRequest enableExternalRequests:(bool)enableExternalRequests;
- (MTSignal *)createKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword; - (SSignal *)updateConfig:(NSString *)config blockchainName:(NSString *)blockchainName;
- (MTSignal *)getWalletAccountAddressWithPublicKey:(NSString *)publicKey;
- (MTSignal *)getAccountStateWithAddress:(NSString *)accountAddress; - (SSignal *)createKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword;
- (MTSignal *)sendGramsFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount textMessage:(NSData *)textMessage forceIfDestinationNotInitialized:(bool)forceIfDestinationNotInitialized timeout:(int32_t)timeout randomId:(int64_t)randomId; - (SSignal *)getWalletAccountAddressWithPublicKey:(NSString *)publicKey;
- (MTSignal *)exportKey:(TONKey *)key localPassword:(NSData *)localPassword; - (SSignal *)getAccountStateWithAddress:(NSString *)accountAddress;
- (MTSignal *)importKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword wordList:(NSArray<NSString *> *)wordList; - (SSignal *)sendGramsFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount textMessage:(NSData *)textMessage forceIfDestinationNotInitialized:(bool)forceIfDestinationNotInitialized timeout:(int32_t)timeout randomId:(int64_t)randomId;
- (MTSignal *)deleteKey:(TONKey *)key; - (SSignal *)exportKey:(TONKey *)key localPassword:(NSData *)localPassword;
- (MTSignal *)deleteAllKeys; - (SSignal *)importKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword wordList:(NSArray<NSString *> *)wordList;
- (MTSignal *)getTransactionListWithAddress:(NSString * _Nonnull)address lt:(int64_t)lt hash:(NSData * _Nonnull)hash; - (SSignal *)deleteKey:(TONKey *)key;
- (SSignal *)deleteAllKeys;
- (SSignal *)getTransactionListWithAddress:(NSString * _Nonnull)address lt:(int64_t)lt hash:(NSData * _Nonnull)hash;
- (NSData *)encrypt:(NSData *)decryptedData secret:(NSData *)data; - (NSData *)encrypt:(NSData *)decryptedData secret:(NSData *)data;
- (NSData * __nullable)decrypt:(NSData *)encryptedData secret:(NSData *)data; - (NSData * __nullable)decrypt:(NSData *)encryptedData secret:(NSData *)data;

View File

@ -1,9 +1,6 @@
#import "TON.h" #import "TON.h"
#import "MTLogging.h"
#import "tonlib/Client.h" #import "tonlib/Client.h"
#import "MTQueue.h"
#import "MTSignal.h"
static td::SecureString makeSecureString(NSData * _Nonnull data) { static td::SecureString makeSecureString(NSData * _Nonnull data) {
if (data == nil || data.length == 0) { if (data == nil || data.length == 0) {
@ -226,9 +223,10 @@ typedef enum {
uint64_t _nextRequestId; uint64_t _nextRequestId;
NSLock *_requestHandlersLock; NSLock *_requestHandlersLock;
NSMutableDictionary<NSNumber *, TONRequestHandler *> *_requestHandlers; NSMutableDictionary<NSNumber *, TONRequestHandler *> *_requestHandlers;
MTPipe *_initializedStatus; SPipe *_initializedStatus;
NSMutableSet *_sendGramRandomIds; NSMutableSet *_sendGramRandomIds;
MTQueue *_queue; SQueue *_queue;
bool _enableExternalRequests;
} }
@end @end
@ -247,13 +245,14 @@ typedef enum {
- (instancetype)initWithKeystoreDirectory:(NSString *)keystoreDirectory config:(NSString *)config blockchainName:(NSString *)blockchainName performExternalRequest:(void (^)(TONExternalRequest * _Nonnull))performExternalRequest enableExternalRequests:(bool)enableExternalRequests { - (instancetype)initWithKeystoreDirectory:(NSString *)keystoreDirectory config:(NSString *)config blockchainName:(NSString *)blockchainName performExternalRequest:(void (^)(TONExternalRequest * _Nonnull))performExternalRequest enableExternalRequests:(bool)enableExternalRequests {
self = [super init]; self = [super init];
if (self != nil) { if (self != nil) {
_queue = [MTQueue mainQueue]; _queue = [SQueue mainQueue];
_requestHandlersLock = [[NSLock alloc] init]; _requestHandlersLock = [[NSLock alloc] init];
_requestHandlers = [[NSMutableDictionary alloc] init]; _requestHandlers = [[NSMutableDictionary alloc] init];
_initializedStatus = [[MTPipe alloc] initWithReplay:true]; _initializedStatus = [[SPipe alloc] initWithReplay:true];
_initializedStatus.sink(@(TONInitializationStatusInitializing)); _initializedStatus.sink(@(TONInitializationStatusInitializing));
_nextRequestId = 1; _nextRequestId = 1;
_sendGramRandomIds = [[NSMutableSet alloc] init]; _sendGramRandomIds = [[NSMutableSet alloc] init];
_enableExternalRequests = enableExternalRequests;
_client = std::make_shared<tonlib::Client>(); _client = std::make_shared<tonlib::Client>();
@ -306,7 +305,7 @@ typedef enum {
[[NSFileManager defaultManager] createDirectoryAtPath:keystoreDirectory withIntermediateDirectories:true attributes:nil error:nil]; [[NSFileManager defaultManager] createDirectoryAtPath:keystoreDirectory withIntermediateDirectories:true attributes:nil error:nil];
MTPipe *initializedStatus = _initializedStatus; SPipe *initializedStatus = _initializedStatus;
[[self requestInitWithConfigString:config blockchainName:blockchainName keystoreDirectory:keystoreDirectory enableExternalRequests:enableExternalRequests] startWithNext:nil error:^(id error) { [[self requestInitWithConfigString:config blockchainName:blockchainName keystoreDirectory:keystoreDirectory enableExternalRequests:enableExternalRequests] startWithNext:nil error:^(id error) {
NSString *errorText = @"Unknown error"; NSString *errorText = @"Unknown error";
if ([error isKindOfClass:[TONError class]]) { if ([error isKindOfClass:[TONError class]]) {
@ -354,8 +353,8 @@ typedef enum {
return readSecureString(value->bytes_); return readSecureString(value->bytes_);
} }
- (MTSignal *)requestInitWithConfigString:(NSString *)configString blockchainName:(NSString *)blockchainName keystoreDirectory:(NSString *)keystoreDirectory enableExternalRequests:(bool)enableExternalRequests { - (SSignal *)requestInitWithConfigString:(NSString *)configString blockchainName:(NSString *)blockchainName keystoreDirectory:(NSString *)keystoreDirectory enableExternalRequests:(bool)enableExternalRequests {
return [[[[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) { return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
uint64_t requestId = _nextRequestId; uint64_t requestId = _nextRequestId;
_nextRequestId += 1; _nextRequestId += 1;
@ -381,13 +380,42 @@ typedef enum {
)); ));
_client->send({ requestId, std::move(query) }); _client->send({ requestId, std::move(query) });
return [[MTBlockDisposable alloc] initWithBlock:^{ return [[SBlockDisposable alloc] initWithBlock:^{
}]; }];
}] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]]; }] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
} }
- (MTSignal *)createKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword { - (SSignal *)updateConfig:(NSString *)config blockchainName:(NSString *)blockchainName {
return [[[[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) { return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
uint64_t requestId = _nextRequestId;
_nextRequestId += 1;
_requestHandlers[@(requestId)] = [[TONRequestHandler alloc] initWithCompletion:^(tonlib_api::object_ptr<tonlib_api::Object> &object) {
if (object->get_id() == tonlib_api::error::ID) {
auto error = tonlib_api::move_object_as<tonlib_api::error>(object);
[subscriber putError:[[TONError alloc] initWithText:[[NSString alloc] initWithUTF8String:error->message_.c_str()]]];
} else {
[subscriber putCompletion];
}
}];
auto query = make_object<tonlib_api::options_setConfig>(
make_object<tonlib_api::config>(
config.UTF8String,
blockchainName.UTF8String,
_enableExternalRequests,
false
)
);
_client->send({ requestId, std::move(query) });
return [[SBlockDisposable alloc] initWithBlock:^{
}];
}] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
}
- (SSignal *)createKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword {
return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
uint64_t requestId = _nextRequestId; uint64_t requestId = _nextRequestId;
_nextRequestId += 1; _nextRequestId += 1;
@ -417,17 +445,17 @@ typedef enum {
); );
_client->send({ requestId, std::move(query) }); _client->send({ requestId, std::move(query) });
return [[MTBlockDisposable alloc] initWithBlock:^{ return [[SBlockDisposable alloc] initWithBlock:^{
}]; }];
}] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]]; }] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
} }
- (MTSignal *)getWalletAccountAddressWithPublicKey:(NSString *)publicKey { - (SSignal *)getWalletAccountAddressWithPublicKey:(NSString *)publicKey {
return [[[[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) { return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
NSData *publicKeyData = [publicKey dataUsingEncoding:NSUTF8StringEncoding]; NSData *publicKeyData = [publicKey dataUsingEncoding:NSUTF8StringEncoding];
if (publicKeyData == nil) { if (publicKeyData == nil) {
[subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in getWalletAccountAddressWithPublicKey"]]; [subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in getWalletAccountAddressWithPublicKey"]];
return [[MTBlockDisposable alloc] initWithBlock:^{}]; return [[SBlockDisposable alloc] initWithBlock:^{}];
} }
uint64_t requestId = _nextRequestId; uint64_t requestId = _nextRequestId;
@ -453,13 +481,13 @@ typedef enum {
); );
_client->send({ requestId, std::move(query) }); _client->send({ requestId, std::move(query) });
return [[MTBlockDisposable alloc] initWithBlock:^{ return [[SBlockDisposable alloc] initWithBlock:^{
}]; }];
}] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]]; }] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
} }
- (MTSignal *)getAccountStateWithAddress:(NSString *)accountAddress { - (SSignal *)getAccountStateWithAddress:(NSString *)accountAddress {
return [[[[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) { return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
uint64_t requestId = _nextRequestId; uint64_t requestId = _nextRequestId;
_nextRequestId += 1; _nextRequestId += 1;
@ -491,34 +519,34 @@ typedef enum {
auto query = make_object<tonlib_api::generic_getAccountState>(make_object<tonlib_api::accountAddress>(accountAddress.UTF8String)); auto query = make_object<tonlib_api::generic_getAccountState>(make_object<tonlib_api::accountAddress>(accountAddress.UTF8String));
_client->send({ requestId, std::move(query) }); _client->send({ requestId, std::move(query) });
return [[MTBlockDisposable alloc] initWithBlock:^{ return [[SBlockDisposable alloc] initWithBlock:^{
}]; }];
}] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]]; }] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
} }
- (MTSignal *)sendGramsFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount textMessage:(NSData *)textMessage forceIfDestinationNotInitialized:(bool)forceIfDestinationNotInitialized timeout:(int32_t)timeout randomId:(int64_t)randomId { - (SSignal *)sendGramsFromKey:(TONKey *)key localPassword:(NSData *)localPassword fromAddress:(NSString *)fromAddress toAddress:(NSString *)address amount:(int64_t)amount textMessage:(NSData *)textMessage forceIfDestinationNotInitialized:(bool)forceIfDestinationNotInitialized timeout:(int32_t)timeout randomId:(int64_t)randomId {
return [[[[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) { return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
if ([_sendGramRandomIds containsObject:@(randomId)]) { if ([_sendGramRandomIds containsObject:@(randomId)]) {
[_sendGramRandomIds addObject:@(randomId)]; [_sendGramRandomIds addObject:@(randomId)];
return [[MTBlockDisposable alloc] initWithBlock:^{ return [[SBlockDisposable alloc] initWithBlock:^{
}]; }];
} }
NSData *publicKeyData = [key.publicKey dataUsingEncoding:NSUTF8StringEncoding]; NSData *publicKeyData = [key.publicKey dataUsingEncoding:NSUTF8StringEncoding];
if (publicKeyData == nil) { if (publicKeyData == nil) {
[subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in sendGramsFromKey"]]; [subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in sendGramsFromKey"]];
return [[MTBlockDisposable alloc] initWithBlock:^{}]; return [[SBlockDisposable alloc] initWithBlock:^{}];
} }
uint64_t requestId = _nextRequestId; uint64_t requestId = _nextRequestId;
_nextRequestId += 1; _nextRequestId += 1;
__weak TON *weakSelf = self; __weak TON *weakSelf = self;
MTQueue *queue = _queue; SQueue *queue = _queue;
_requestHandlers[@(requestId)] = [[TONRequestHandler alloc] initWithCompletion:^(tonlib_api::object_ptr<tonlib_api::Object> &object) { _requestHandlers[@(requestId)] = [[TONRequestHandler alloc] initWithCompletion:^(tonlib_api::object_ptr<tonlib_api::Object> &object) {
if (object->get_id() == tonlib_api::error::ID) { if (object->get_id() == tonlib_api::error::ID) {
[queue dispatchOnQueue:^{ [queue dispatch:^{
__strong TON *strongSelf = weakSelf; __strong TON *strongSelf = weakSelf;
if (strongSelf != nil) { if (strongSelf != nil) {
[_sendGramRandomIds removeObject:@(randomId)]; [_sendGramRandomIds removeObject:@(randomId)];
@ -553,17 +581,17 @@ typedef enum {
); );
_client->send({ requestId, std::move(query) }); _client->send({ requestId, std::move(query) });
return [[MTBlockDisposable alloc] initWithBlock:^{ return [[SBlockDisposable alloc] initWithBlock:^{
}]; }];
}] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]]; }] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
} }
- (MTSignal *)exportKey:(TONKey *)key localPassword:(NSData *)localPassword { - (SSignal *)exportKey:(TONKey *)key localPassword:(NSData *)localPassword {
return [[[[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) { return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
NSData *publicKeyData = [key.publicKey dataUsingEncoding:NSUTF8StringEncoding]; NSData *publicKeyData = [key.publicKey dataUsingEncoding:NSUTF8StringEncoding];
if (publicKeyData == nil) { if (publicKeyData == nil) {
[subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in exportKey"]]; [subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in exportKey"]];
return [[MTBlockDisposable alloc] initWithBlock:^{}]; return [[SBlockDisposable alloc] initWithBlock:^{}];
} }
uint64_t requestId = _nextRequestId; uint64_t requestId = _nextRequestId;
@ -601,13 +629,13 @@ typedef enum {
); );
_client->send({ requestId, std::move(query) }); _client->send({ requestId, std::move(query) });
return [[MTBlockDisposable alloc] initWithBlock:^{ return [[SBlockDisposable alloc] initWithBlock:^{
}]; }];
}] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]]; }] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
} }
- (MTSignal *)importKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword wordList:(NSArray<NSString *> *)wordList { - (SSignal *)importKeyWithLocalPassword:(NSData *)localPassword mnemonicPassword:(NSData *)mnemonicPassword wordList:(NSArray<NSString *> *)wordList {
return [[[[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) { return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
uint64_t requestId = _nextRequestId; uint64_t requestId = _nextRequestId;
_nextRequestId += 1; _nextRequestId += 1;
@ -642,17 +670,17 @@ typedef enum {
make_object<tonlib_api::exportedKey>(std::move(wordVector))); make_object<tonlib_api::exportedKey>(std::move(wordVector)));
_client->send({ requestId, std::move(query) }); _client->send({ requestId, std::move(query) });
return [[MTBlockDisposable alloc] initWithBlock:^{ return [[SBlockDisposable alloc] initWithBlock:^{
}]; }];
}] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]]; }] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
} }
- (MTSignal *)deleteKey:(TONKey *)key { - (SSignal *)deleteKey:(TONKey *)key {
return [[[[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) { return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
NSData *publicKeyData = [key.publicKey dataUsingEncoding:NSUTF8StringEncoding]; NSData *publicKeyData = [key.publicKey dataUsingEncoding:NSUTF8StringEncoding];
if (publicKeyData == nil) { if (publicKeyData == nil) {
[subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in deleteKey"]]; [subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in deleteKey"]];
return [[MTBlockDisposable alloc] initWithBlock:^{}]; return [[SBlockDisposable alloc] initWithBlock:^{}];
} }
uint64_t requestId = _nextRequestId; uint64_t requestId = _nextRequestId;
@ -675,13 +703,13 @@ typedef enum {
); );
_client->send({ requestId, std::move(query) }); _client->send({ requestId, std::move(query) });
return [[MTBlockDisposable alloc] initWithBlock:^{ return [[SBlockDisposable alloc] initWithBlock:^{
}]; }];
}] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]]; }] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
} }
- (MTSignal *)deleteAllKeys { - (SSignal *)deleteAllKeys {
return [[[[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) { return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
uint64_t requestId = _nextRequestId; uint64_t requestId = _nextRequestId;
_nextRequestId += 1; _nextRequestId += 1;
@ -697,17 +725,17 @@ typedef enum {
auto query = make_object<tonlib_api::deleteAllKeys>(); auto query = make_object<tonlib_api::deleteAllKeys>();
_client->send({ requestId, std::move(query) }); _client->send({ requestId, std::move(query) });
return [[MTBlockDisposable alloc] initWithBlock:^{ return [[SBlockDisposable alloc] initWithBlock:^{
}]; }];
}] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]]; }] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
} }
- (MTSignal *)getTransactionListWithAddress:(NSString * _Nonnull)address lt:(int64_t)lt hash:(NSData * _Nonnull)hash { - (SSignal *)getTransactionListWithAddress:(NSString * _Nonnull)address lt:(int64_t)lt hash:(NSData * _Nonnull)hash {
return [[[[MTSignal alloc] initWithGenerator:^id<MTDisposable>(MTSubscriber *subscriber) { return [[[[SSignal alloc] initWithGenerator:^id<SDisposable>(SSubscriber *subscriber) {
NSData *addressData = [address dataUsingEncoding:NSUTF8StringEncoding]; NSData *addressData = [address dataUsingEncoding:NSUTF8StringEncoding];
if (addressData == nil) { if (addressData == nil) {
[subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in getTransactionListWithAddress"]]; [subscriber putError:[[TONError alloc] initWithText:@"Error encoding UTF8 string in getTransactionListWithAddress"]];
return [[MTBlockDisposable alloc] initWithBlock:^{}]; return [[SBlockDisposable alloc] initWithBlock:^{}];
} }
uint64_t requestId = _nextRequestId; uint64_t requestId = _nextRequestId;
@ -750,9 +778,9 @@ typedef enum {
); );
_client->send({ requestId, std::move(query) }); _client->send({ requestId, std::move(query) });
return [[MTBlockDisposable alloc] initWithBlock:^{ return [[SBlockDisposable alloc] initWithBlock:^{
}]; }];
}] startOn:[MTQueue mainQueue]] deliverOn:[MTQueue mainQueue]]; }] startOn:[SQueue mainQueue]] deliverOn:[SQueue mainQueue]];
} }
@end @end

View File

@ -6,7 +6,6 @@ static_library(
"Sources/**/*.swift", "Sources/**/*.swift",
]), ]),
deps = [ deps = [
"//submodules/MtProtoKit:MtProtoKit#shared",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared",
"//submodules/TonBinding:TonBinding", "//submodules/TonBinding:TonBinding",
], ],

View File

@ -4,7 +4,7 @@ import SwiftSignalKitMac
import MtProtoKitMac import MtProtoKitMac
#else #else
import SwiftSignalKit import SwiftSignalKit
import MtProtoKit import TonBinding
#endif #endif
public struct TonKeychainEncryptedData: Codable, Equatable { public struct TonKeychainEncryptedData: Codable, Equatable {
@ -102,6 +102,24 @@ public final class TonInstance {
}) })
} }
public func updateConfig(config: String, blockchainName: String) -> Signal<Never, NoError> {
return Signal { subscriber in
let disposable = MetaDisposable()
self.impl.with { impl in
impl.withInstance { ton in
let cancel = ton.updateConfig(config, blockchainName: blockchainName).start(next: nil, error: { _ in
}, completed: {
subscriber.putCompletion()
})
disposable.set(ActionDisposable {
cancel?.dispose()
})
}
}
return disposable
}
}
fileprivate func exportKey(key: TONKey, localPassword: Data) -> Signal<[String], NoError> { fileprivate func exportKey(key: TONKey, localPassword: Data) -> Signal<[String], NoError> {
return Signal { subscriber in return Signal { subscriber in
let disposable = MetaDisposable() let disposable = MetaDisposable()