mirror of https://github.com/oxen-io/session-ios
Add test app context; use mock "document" and "shared data container" directories in tests, use mock keychain storage in tests.
parent
0357699fc8
commit
399dd13cee
@ -0,0 +1,103 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SAMKeychain
|
||||
|
||||
public enum KeychainStorageError: Error {
|
||||
case failure(description: String)
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
@objc public protocol KeychainStorage: class {
|
||||
|
||||
@objc func string(forKey key: String, service: String) throws -> String
|
||||
|
||||
@objc func set(string: String, forKey key: String, service: String) throws
|
||||
|
||||
@objc func data(forKey key: String, service: String) throws -> Data
|
||||
|
||||
@objc func set(data: Data, forKey key: String, service: String) throws
|
||||
|
||||
@objc func remove(key: String, service: String) throws
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
@objc
|
||||
public class SSKKeychainStorage: NSObject, KeychainStorage {
|
||||
|
||||
@objc public static let sharedInstance = SSKKeychainStorage()
|
||||
|
||||
// Force usage as a singleton
|
||||
override private init() {
|
||||
super.init()
|
||||
|
||||
SwiftSingletons.register(self)
|
||||
}
|
||||
|
||||
@objc public func string(forKey key: String, service: String) throws -> String {
|
||||
var error: NSError?
|
||||
let result = SAMKeychain.password(forService: service, account: key, error: &error)
|
||||
if let error = error {
|
||||
throw SSKProtoError.invalidProtobuf(description: "\(logTag) error retrieving string: \(error)")
|
||||
}
|
||||
guard let string = result else {
|
||||
throw SSKProtoError.invalidProtobuf(description: "\(logTag) could not retrieve string")
|
||||
}
|
||||
return string
|
||||
}
|
||||
|
||||
@objc public func set(string: String, forKey key: String, service: String) throws {
|
||||
|
||||
SAMKeychain.setAccessibilityType(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)
|
||||
|
||||
var error: NSError?
|
||||
let result = SAMKeychain.setPassword(string, forService: service, account: key, error: &error)
|
||||
if let error = error {
|
||||
throw SSKProtoError.invalidProtobuf(description: "\(logTag) error setting string: \(error)")
|
||||
}
|
||||
guard result else {
|
||||
throw SSKProtoError.invalidProtobuf(description: "\(logTag) could not set string")
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func data(forKey key: String, service: String) throws -> Data {
|
||||
var error: NSError?
|
||||
let result = SAMKeychain.passwordData(forService: service, account: key, error: &error)
|
||||
if let error = error {
|
||||
throw SSKProtoError.invalidProtobuf(description: "\(logTag) error retrieving data: \(error)")
|
||||
}
|
||||
guard let data = result else {
|
||||
throw SSKProtoError.invalidProtobuf(description: "\(logTag) could not retrieve data")
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
@objc public func set(data: Data, forKey key: String, service: String) throws {
|
||||
|
||||
SAMKeychain.setAccessibilityType(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)
|
||||
|
||||
var error: NSError?
|
||||
let result = SAMKeychain.setPasswordData(data, forService: service, account: key, error: &error)
|
||||
if let error = error {
|
||||
throw SSKProtoError.invalidProtobuf(description: "\(logTag) error setting data: \(error)")
|
||||
}
|
||||
guard result else {
|
||||
throw SSKProtoError.invalidProtobuf(description: "\(logTag) could not set data")
|
||||
}
|
||||
}
|
||||
|
||||
@objc public func remove(key: String, service: String) throws {
|
||||
var error: NSError?
|
||||
let result = SAMKeychain.deletePassword(forService: service, account: key, error: &error)
|
||||
if let error = error {
|
||||
throw SSKProtoError.invalidProtobuf(description: "\(logTag) error removing data: \(error)")
|
||||
}
|
||||
guard result else {
|
||||
throw SSKProtoError.invalidProtobuf(description: "\(logTag) could not remove data")
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppContext.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TestAppContext : NSObject <AppContext>
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -0,0 +1,153 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TestAppContext.h"
|
||||
#import "TestKeychainStorage.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface TestAppContext ()
|
||||
|
||||
@property (nonatomic) TestKeychainStorage *testKeychainStorage;
|
||||
@property (nonatomic) NSString *appDocumentDirPath;
|
||||
@property (nonatomic) NSString *appSharedDataDirPath;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation TestAppContext
|
||||
|
||||
@synthesize mainWindow = _mainWindow;
|
||||
@synthesize appLaunchTime = _appLaunchTime;
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
self.testKeychainStorage = [TestKeychainStorage new];
|
||||
|
||||
NSString *temporaryDirectory = NSTemporaryDirectory();
|
||||
self.appDocumentDirPath = [temporaryDirectory stringByAppendingPathComponent:NSUUID.UUID.UUIDString];
|
||||
self.appSharedDataDirPath = [temporaryDirectory stringByAppendingPathComponent:NSUUID.UUID.UUIDString];
|
||||
|
||||
_appLaunchTime = [NSDate new];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIApplicationState)reportedApplicationState
|
||||
{
|
||||
return UIApplicationStateActive;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (BOOL)isMainApp
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isMainAppAndActive
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)isRTL
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)setStatusBarHidden:(BOOL)isHidden animated:(BOOL)isAnimated
|
||||
{
|
||||
}
|
||||
|
||||
- (CGFloat)statusBarHeight
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
|
||||
- (BOOL)isInBackground
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isAppForegroundAndActive
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:
|
||||
(BackgroundTaskExpirationHandler)expirationHandler
|
||||
{
|
||||
return UIBackgroundTaskInvalid;
|
||||
}
|
||||
|
||||
- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)backgroundTaskIdentifier
|
||||
{
|
||||
}
|
||||
|
||||
- (void)ensureSleepBlocking:(BOOL)shouldBeBlocking blockingObjects:(NSArray<id> *)blockingObjects
|
||||
{
|
||||
}
|
||||
|
||||
- (void)setMainAppBadgeNumber:(NSInteger)value
|
||||
{
|
||||
}
|
||||
|
||||
- (nullable UIViewController *)frontmostViewController
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (nullable UIAlertAction *)openSystemSettingsAction
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)doMultiDeviceUpdateWithProfileKey:(OWSAES256Key *)profileKey
|
||||
{
|
||||
}
|
||||
|
||||
- (BOOL)isRunningTests
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)setNetworkActivityIndicatorVisible:(BOOL)value
|
||||
{
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)runNowOrWhenMainAppIsActive:(AppActiveBlock)block
|
||||
{
|
||||
block();
|
||||
}
|
||||
|
||||
- (void)runAppActiveBlocks
|
||||
{
|
||||
}
|
||||
|
||||
- (id<KeychainStorage>)keychainStorage
|
||||
{
|
||||
return self.testKeychainStorage;
|
||||
}
|
||||
|
||||
- (NSString *)appDocumentDirectoryPath
|
||||
{
|
||||
return self.appDocumentDirPath;
|
||||
}
|
||||
|
||||
- (NSString *)appSharedDataDirectoryPath
|
||||
{
|
||||
return self.appSharedDataDirPath;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -0,0 +1,15 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol KeychainStorage;
|
||||
|
||||
@interface TestKeychainStorage : NSObject <KeychainStorage>
|
||||
|
||||
@property (nonatomic) NSMutableDictionary<NSString *, NSData *> *dataMap;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -0,0 +1,113 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "TestKeychainStorage.h"
|
||||
#import "NSData+OWS.h"
|
||||
#import <SignalServiceKit/SignalServiceKit-Swift.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation TestKeychainStorage
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
self.dataMap = [NSMutableDictionary new];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *_Nullable)stringForKey:(NSString *)key
|
||||
service:(NSString *)service
|
||||
error:(NSError *_Nullable *_Nullable)error
|
||||
{
|
||||
OWSAssert(error);
|
||||
OWSAssert(key.length > 0);
|
||||
OWSAssert(service.length > 0);
|
||||
|
||||
*error = nil;
|
||||
|
||||
NSString *mapKey = [NSString stringWithFormat:@"%@-%@", service, key];
|
||||
NSData *_Nullable data = self.dataMap[mapKey];
|
||||
if (!data) {
|
||||
NSLog(@"stringForKey:%@ service:%@ -> nil", key, service);
|
||||
return nil;
|
||||
}
|
||||
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
NSLog(@"stringForKey:%@ service:%@ -> %@", key, service, string);
|
||||
return string;
|
||||
}
|
||||
|
||||
- (BOOL)setWithString:(NSString *)string
|
||||
forKey:(NSString *)key
|
||||
service:(NSString *)service
|
||||
error:(NSError *_Nullable *_Nullable)error
|
||||
{
|
||||
OWSAssert(error);
|
||||
OWSAssert(key.length > 0);
|
||||
OWSAssert(service.length > 0);
|
||||
|
||||
*error = nil;
|
||||
|
||||
NSLog(@"setWithString:%@ service:%@ -> %@", key, service, string);
|
||||
|
||||
NSString *mapKey = [NSString stringWithFormat:@"%@-%@", service, key];
|
||||
self.dataMap[mapKey] = [string dataUsingEncoding:NSUTF8StringEncoding];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSData *_Nullable)dataForKey:(NSString *)key service:(NSString *)service error:(NSError *_Nullable *_Nullable)error
|
||||
{
|
||||
OWSAssert(error);
|
||||
OWSAssert(key.length > 0);
|
||||
OWSAssert(service.length > 0);
|
||||
|
||||
*error = nil;
|
||||
|
||||
NSString *mapKey = [NSString stringWithFormat:@"%@-%@", service, key];
|
||||
NSData *_Nullable data = self.dataMap[mapKey];
|
||||
NSLog(@"dataForKey:%@ service:%@ -> %@", key, service, data.hexadecimalString);
|
||||
return data;
|
||||
}
|
||||
|
||||
- (BOOL)setWithData:(NSData *)data
|
||||
forKey:(NSString *)key
|
||||
service:(NSString *)service
|
||||
error:(NSError *_Nullable *_Nullable)error
|
||||
{
|
||||
OWSAssert(error);
|
||||
OWSAssert(key.length > 0);
|
||||
OWSAssert(service.length > 0);
|
||||
|
||||
*error = nil;
|
||||
|
||||
NSLog(@"setWithData:%@ service:%@ -> %@", key, service, data.hexadecimalString);
|
||||
|
||||
NSString *mapKey = [NSString stringWithFormat:@"%@-%@", service, key];
|
||||
self.dataMap[mapKey] = data;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)removeWithKey:(NSString *)key service:(NSString *)service error:(NSError *_Nullable *_Nullable)error
|
||||
{
|
||||
OWSAssert(error);
|
||||
OWSAssert(key.length > 0);
|
||||
OWSAssert(service.length > 0);
|
||||
|
||||
*error = nil;
|
||||
|
||||
NSLog(@"removeWithKey:%@ service:%@", key, service);
|
||||
|
||||
NSString *mapKey = [NSString stringWithFormat:@"%@-%@", service, key];
|
||||
[self.dataMap removeObjectForKey:mapKey];
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
Loading…
Reference in New Issue