Initial commit
This commit is contained in:
347
local_pod_repo/objcTox/Classes/Private/Manager/OCTManagerImpl.m
Normal file
347
local_pod_repo/objcTox/Classes/Private/Manager/OCTManagerImpl.m
Normal file
@@ -0,0 +1,347 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#import "OCTManagerImpl.h"
|
||||
#import "OCTTox.h"
|
||||
#import "OCTToxEncryptSave.h"
|
||||
#import "OCTManagerConfiguration.h"
|
||||
#import "OCTManagerFactory.h"
|
||||
#import "OCTSubmanagerBootstrapImpl.h"
|
||||
#import "OCTSubmanagerCallsImpl.h"
|
||||
#import "OCTSubmanagerChatsImpl.h"
|
||||
#import "OCTSubmanagerFilesImpl.h"
|
||||
#import "OCTSubmanagerFriendsImpl.h"
|
||||
#import "OCTSubmanagerObjectsImpl.h"
|
||||
#import "OCTSubmanagerUserImpl.h"
|
||||
#import "OCTRealmManager.h"
|
||||
|
||||
@interface OCTManagerImpl () <OCTToxDelegate, OCTSubmanagerDataSource>
|
||||
|
||||
@property (copy, nonatomic, readonly) OCTManagerConfiguration *currentConfiguration;
|
||||
|
||||
@property (strong, nonatomic, readonly) OCTTox *tox;
|
||||
@property (strong, nonatomic, readonly) NSObject *toxSaveFileLock;
|
||||
|
||||
@property (strong, nonatomic, nonnull) OCTToxEncryptSave *encryptSave;
|
||||
|
||||
@property (strong, nonatomic, readonly) OCTRealmManager *realmManager;
|
||||
@property (strong, atomic) NSNotificationCenter *notificationCenter;
|
||||
|
||||
@property (strong, nonatomic, readwrite) OCTSubmanagerBootstrapImpl *bootstrap;
|
||||
@property (strong, nonatomic, readwrite) OCTSubmanagerCallsImpl *calls;
|
||||
@property (strong, nonatomic, readwrite) OCTSubmanagerChatsImpl *chats;
|
||||
@property (strong, nonatomic, readwrite) OCTSubmanagerFilesImpl *files;
|
||||
@property (strong, nonatomic, readwrite) OCTSubmanagerFriendsImpl *friends;
|
||||
@property (strong, nonatomic, readwrite) OCTSubmanagerObjectsImpl *objects;
|
||||
@property (strong, nonatomic, readwrite) OCTSubmanagerUserImpl *user;
|
||||
|
||||
@end
|
||||
|
||||
@implementation OCTManagerImpl
|
||||
|
||||
#pragma mark - Lifecycle
|
||||
|
||||
- (instancetype)initWithConfiguration:(OCTManagerConfiguration *)configuration
|
||||
tox:(OCTTox *)tox
|
||||
toxEncryptSave:(OCTToxEncryptSave *)toxEncryptSave
|
||||
realmManager:(OCTRealmManager *)realmManager
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (! self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
_currentConfiguration = [configuration copy];
|
||||
|
||||
_tox = tox;
|
||||
_tox.delegate = self;
|
||||
_toxSaveFileLock = [NSObject new];
|
||||
|
||||
_encryptSave = toxEncryptSave;
|
||||
|
||||
_realmManager = realmManager;
|
||||
_notificationCenter = [[NSNotificationCenter alloc] init];
|
||||
|
||||
[_tox start];
|
||||
[self saveTox];
|
||||
|
||||
[self createSubmanagers];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[self killSubmanagers];
|
||||
[self.tox stop];
|
||||
}
|
||||
|
||||
#pragma mark - Public
|
||||
|
||||
- (OCTManagerConfiguration *)configuration
|
||||
{
|
||||
return [self.currentConfiguration copy];
|
||||
}
|
||||
|
||||
- (NSString *)exportToxSaveFileAndReturnError:(NSError **)error
|
||||
{
|
||||
@synchronized(self.toxSaveFileLock) {
|
||||
NSString *savedDataPath = self.currentConfiguration.fileStorage.pathForToxSaveFile;
|
||||
NSString *tempPath = self.currentConfiguration.fileStorage.pathForTemporaryFilesDirectory;
|
||||
tempPath = [tempPath stringByAppendingPathComponent:[savedDataPath lastPathComponent]];
|
||||
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
|
||||
if ([fileManager fileExistsAtPath:tempPath]) {
|
||||
[fileManager removeItemAtPath:tempPath error:error];
|
||||
}
|
||||
|
||||
if (! [fileManager copyItemAtPath:savedDataPath toPath:tempPath error:error]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return tempPath;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)changeEncryptPassword:(nonnull NSString *)newPassword oldPassword:(nonnull NSString *)oldPassword
|
||||
{
|
||||
OCTToxEncryptSave *encryptSave = [self changeToxPassword:newPassword oldPassword:oldPassword];
|
||||
if (encryptSave == nil) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (! [self changeDatabasePassword:newPassword oldPassword:oldPassword]) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
self.encryptSave = encryptSave;
|
||||
[self saveTox];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isManagerEncryptedWithPassword:(nonnull NSString *)password
|
||||
{
|
||||
NSString *toxFilePath = self.currentConfiguration.fileStorage.pathForToxSaveFile;
|
||||
|
||||
return [self isDataAtPath:toxFilePath encryptedWithPassword:password];
|
||||
}
|
||||
|
||||
#pragma mark - OCTSubmanagerDataSource
|
||||
|
||||
- (OCTTox *)managerGetTox
|
||||
{
|
||||
return self.tox;
|
||||
}
|
||||
|
||||
- (BOOL)managerIsToxConnected
|
||||
{
|
||||
return (self.user.connectionStatus != OCTToxConnectionStatusNone);
|
||||
}
|
||||
|
||||
- (void)managerSaveTox
|
||||
{
|
||||
return [self saveTox];
|
||||
}
|
||||
|
||||
- (OCTRealmManager *)managerGetRealmManager
|
||||
{
|
||||
return self.realmManager;
|
||||
}
|
||||
|
||||
- (id<OCTFileStorageProtocol>)managerGetFileStorage
|
||||
{
|
||||
return self.currentConfiguration.fileStorage;
|
||||
}
|
||||
|
||||
- (NSNotificationCenter *)managerGetNotificationCenter
|
||||
{
|
||||
return self.notificationCenter;
|
||||
}
|
||||
|
||||
- (BOOL)managerUseFauxOfflineMessaging
|
||||
{
|
||||
return self.currentConfiguration.useFauxOfflineMessaging;
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (NSData *)getSavedDataFromPath:(NSString *)path
|
||||
{
|
||||
return [[NSFileManager defaultManager] fileExistsAtPath:path] ?
|
||||
([NSData dataWithContentsOfFile:path]) :
|
||||
nil;
|
||||
}
|
||||
|
||||
- (BOOL)isDataAtPath:(NSString *)path encryptedWithPassword:(NSString *)password
|
||||
{
|
||||
NSData *savedData = [self getSavedDataFromPath:path];
|
||||
|
||||
if (! savedData) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if ([OCTToxEncryptSave isDataEncrypted:savedData]) {
|
||||
return [OCTToxEncryptSave decryptData:savedData withPassphrase:password error:nil] != nil;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)createSubmanagers
|
||||
{
|
||||
_bootstrap = [self createSubmanagerWithClass:[OCTSubmanagerBootstrapImpl class]];
|
||||
_chats = [self createSubmanagerWithClass:[OCTSubmanagerChatsImpl class]];
|
||||
_files = [self createSubmanagerWithClass:[OCTSubmanagerFilesImpl class]];
|
||||
_friends = [self createSubmanagerWithClass:[OCTSubmanagerFriendsImpl class]];
|
||||
_objects = [self createSubmanagerWithClass:[OCTSubmanagerObjectsImpl class]];
|
||||
_user = [self createSubmanagerWithClass:[OCTSubmanagerUserImpl class]];
|
||||
|
||||
OCTSubmanagerCallsImpl *calls = [[OCTSubmanagerCallsImpl alloc] initWithTox:_tox];
|
||||
calls.dataSource = self;
|
||||
_calls = calls;
|
||||
[_calls setupAndReturnError:nil];
|
||||
}
|
||||
|
||||
- (void)killSubmanagers
|
||||
{
|
||||
self.bootstrap = nil;
|
||||
self.calls = nil;
|
||||
self.chats = nil;
|
||||
self.files = nil;
|
||||
self.friends = nil;
|
||||
self.objects = nil;
|
||||
self.user = nil;
|
||||
}
|
||||
|
||||
- (id)createSubmanagerWithClass:(Class)class
|
||||
{
|
||||
id<OCTSubmanagerProtocol> submanager = [[class alloc] init];
|
||||
submanager.dataSource = self;
|
||||
|
||||
if ([submanager respondsToSelector:@selector(configure)]) {
|
||||
[submanager configure];
|
||||
}
|
||||
|
||||
return submanager;
|
||||
}
|
||||
|
||||
- (BOOL)respondsToSelector:(SEL)aSelector
|
||||
{
|
||||
id submanager = [self forwardingTargetForSelector:aSelector];
|
||||
|
||||
if (submanager) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return [super respondsToSelector:aSelector];
|
||||
}
|
||||
|
||||
- (id)forwardingTargetForSelector:(SEL)aSelector
|
||||
{
|
||||
struct objc_method_description description = protocol_getMethodDescription(@protocol(OCTToxDelegate), aSelector, NO, YES);
|
||||
|
||||
if (description.name == NULL) {
|
||||
// We forward methods only from OCTToxDelegate protocol.
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSArray *submanagers = @[
|
||||
self.bootstrap,
|
||||
self.chats,
|
||||
self.files,
|
||||
self.friends,
|
||||
self.objects,
|
||||
self.user,
|
||||
];
|
||||
|
||||
for (id delegate in submanagers) {
|
||||
if ([delegate respondsToSelector:aSelector]) {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)saveTox
|
||||
{
|
||||
@synchronized(self.toxSaveFileLock) {
|
||||
void (^throwException)(NSError *) = ^(NSError *error) {
|
||||
NSDictionary *userInfo = nil;
|
||||
|
||||
if (error) {
|
||||
userInfo = @{ @"NSError" : error };
|
||||
}
|
||||
|
||||
@throw [NSException exceptionWithName:@"saveToxException" reason:error.debugDescription userInfo:userInfo];
|
||||
};
|
||||
|
||||
NSData *data = [self.tox save];
|
||||
|
||||
NSError *error;
|
||||
|
||||
data = [self.encryptSave encryptData:data error:&error];
|
||||
|
||||
if (! data) {
|
||||
throwException(error);
|
||||
}
|
||||
|
||||
if (! [data writeToFile:self.currentConfiguration.fileStorage.pathForToxSaveFile options:NSDataWritingAtomic error:&error]) {
|
||||
throwException(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// On success returns encryptSave with new password.
|
||||
- (OCTToxEncryptSave *)changeToxPassword:(NSString *)newPassword oldPassword:(NSString *)oldPassword
|
||||
{
|
||||
NSString *toxFilePath = self.currentConfiguration.fileStorage.pathForToxSaveFile;
|
||||
|
||||
if (! [self isDataAtPath:toxFilePath encryptedWithPassword:oldPassword]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
__block OCTToxEncryptSave *newEncryptSave;
|
||||
|
||||
@synchronized(self.toxSaveFileLock) {
|
||||
// Passing nil as tox data as we are setting new password.
|
||||
newEncryptSave = [[OCTToxEncryptSave alloc] initWithPassphrase:newPassword toxData:nil error:nil];
|
||||
}
|
||||
|
||||
return newEncryptSave;
|
||||
}
|
||||
|
||||
- (BOOL)changeDatabasePassword:(NSString *)newPassword oldPassword:(NSString *)oldPassword
|
||||
{
|
||||
NSParameterAssert(newPassword);
|
||||
NSParameterAssert(oldPassword);
|
||||
|
||||
NSString *encryptedKeyPath = self.currentConfiguration.fileStorage.pathForDatabaseEncryptionKey;
|
||||
NSData *encryptedKey = [NSData dataWithContentsOfFile:encryptedKeyPath];
|
||||
|
||||
if (! encryptedKey) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSData *key = [OCTToxEncryptSave decryptData:encryptedKey withPassphrase:oldPassword error:nil];
|
||||
|
||||
if (! key) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSData *newEncryptedKey = [OCTToxEncryptSave encryptData:key withPassphrase:newPassword error:nil];
|
||||
|
||||
if (! newEncryptedKey) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
return [newEncryptedKey writeToFile:encryptedKeyPath options:NSDataWritingAtomic error:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user