mirror of https://github.com/oxen-io/session-ios
Create SignalUtilitiesKit
parent
82127bfe4d
commit
c475f895e8
@ -1 +1 @@
|
||||
Subproject commit 0c79ca436b633fdf1b0daf90e86fd323dcc60c55
|
||||
Subproject commit e28da414f77b9cba508c92e90b16b815847cde7e
|
@ -1,20 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface Randomness : NSObject
|
||||
|
||||
/**
|
||||
* Generates a given number of cryptographically secure bytes using SecRandomCopyBytes.
|
||||
*
|
||||
* @param numberBytes The number of bytes to be generated.
|
||||
*
|
||||
* @return Random Bytes.
|
||||
*/
|
||||
|
||||
+ (NSData *)generateRandomBytes:(int)numberBytes;
|
||||
|
||||
|
||||
@end
|
@ -1,24 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Randomness.h"
|
||||
#import <SessionProtocolKit/OWSAsserts.h>
|
||||
|
||||
@implementation Randomness
|
||||
|
||||
+ (NSData *)generateRandomBytes:(int)numberBytes
|
||||
{
|
||||
NSMutableData *_Nullable randomBytes = [NSMutableData dataWithLength:numberBytes];
|
||||
if (!randomBytes) {
|
||||
OWSFail(@"Could not allocate buffer for random bytes.");
|
||||
}
|
||||
int err = 0;
|
||||
err = SecRandomCopyBytes(kSecRandomDefault, numberBytes, [randomBytes mutableBytes]);
|
||||
if (err != noErr || randomBytes.length != numberBytes) {
|
||||
OWSFail(@"Could not generate random bytes.");
|
||||
}
|
||||
return [randomBytes copy];
|
||||
}
|
||||
|
||||
@end
|
@ -1,7 +1,7 @@
|
||||
import PromiseKit
|
||||
|
||||
/// Delay the execution of the promise constructed in `body` by `delay` seconds.
|
||||
internal func withDelay<T>(_ delay: TimeInterval, completionQueue: DispatchQueue, body: @escaping () -> Promise<T>) -> Promise<T> {
|
||||
public func withDelay<T>(_ delay: TimeInterval, completionQueue: DispatchQueue, body: @escaping () -> Promise<T>) -> Promise<T> {
|
||||
#if DEBUG
|
||||
assert(Thread.current.isMainThread) // Timers don't do well on background queues
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,34 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import PromiseKit
|
||||
|
||||
// TODO define actual type, and validate length
|
||||
public typealias IdentityKey = Data
|
||||
|
||||
/// based on libsignal-service-java's AccountManager class
|
||||
@objc(SSKAccountServiceClient)
|
||||
public class AccountServiceClient: NSObject {
|
||||
|
||||
static var shared = AccountServiceClient()
|
||||
|
||||
private let serviceClient: SignalServiceClient
|
||||
|
||||
override init() {
|
||||
self.serviceClient = SignalServiceRestClient()
|
||||
}
|
||||
|
||||
public func getPreKeysCount() -> Promise<Int> {
|
||||
return serviceClient.getAvailablePreKeys()
|
||||
}
|
||||
|
||||
public func setPreKeys(identityKey: IdentityKey, signedPreKeyRecord: SignedPreKeyRecord, preKeyRecords: [PreKeyRecord]) -> Promise<Void> {
|
||||
return serviceClient.registerPreKeys(identityKey: identityKey, signedPreKeyRecord: signedPreKeyRecord, preKeyRecords: preKeyRecords)
|
||||
}
|
||||
|
||||
public func setSignedPreKey(_ signedPreKey: SignedPreKeyRecord) -> Promise<Void> {
|
||||
return serviceClient.setCurrentSignedPreKey(signedPreKey)
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
import PromiseKit
|
||||
|
||||
public extension AnyPromise {
|
||||
|
||||
public static func from<T : Any>(_ promise: Promise<T>) -> AnyPromise {
|
||||
let result = AnyPromise(promise)
|
||||
result.retainUntilComplete()
|
||||
return result
|
||||
}
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
static inline BOOL OWSIsDebugBuild()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
return YES;
|
||||
#else
|
||||
return NO;
|
||||
#endif
|
||||
}
|
||||
|
||||
// These are fired whenever the corresponding "main app" or "app extension"
|
||||
// notification is fired.
|
||||
//
|
||||
// 1. This saves you the work of observing both.
|
||||
// 2. This allows us to ensure that any critical work (e.g. re-opening
|
||||
// databases) has been done before app re-enters foreground, etc.
|
||||
extern NSString *const OWSApplicationDidEnterBackgroundNotification;
|
||||
extern NSString *const OWSApplicationWillEnterForegroundNotification;
|
||||
extern NSString *const OWSApplicationWillResignActiveNotification;
|
||||
extern NSString *const OWSApplicationDidBecomeActiveNotification;
|
||||
|
||||
typedef void (^BackgroundTaskExpirationHandler)(void);
|
||||
typedef void (^AppActiveBlock)(void);
|
||||
|
||||
NSString *NSStringForUIApplicationState(UIApplicationState value);
|
||||
|
||||
@class OWSAES256Key;
|
||||
|
||||
@protocol SSKKeychainStorage;
|
||||
|
||||
@protocol AppContext <NSObject>
|
||||
|
||||
@property (nonatomic, readonly) BOOL isMainApp;
|
||||
@property (nonatomic, readonly) BOOL isMainAppAndActive;
|
||||
/// Whether the app was woken up by a silent push notification. This is important for
|
||||
/// determining whether attachments should be downloaded or not.
|
||||
@property (nonatomic) BOOL wasWokenUpByPushNotification;
|
||||
|
||||
// Whether the user is using a right-to-left language like Arabic.
|
||||
@property (nonatomic, readonly) BOOL isRTL;
|
||||
|
||||
@property (nonatomic, readonly) BOOL isRunningTests;
|
||||
|
||||
@property (atomic, nullable) UIWindow *mainWindow;
|
||||
|
||||
// Unlike UIApplication.applicationState, this is thread-safe.
|
||||
// It contains the "last known" application state.
|
||||
//
|
||||
// Because it is updated in response to "will/did-style" events, it is
|
||||
// conservative and skews toward less-active and not-foreground:
|
||||
//
|
||||
// * It doesn't report "is active" until the app is active
|
||||
// and reports "inactive" as soon as it _will become_ inactive.
|
||||
// * It doesn't report "is foreground (but inactive)" until the app is
|
||||
// foreground & inactive and reports "background" as soon as it _will
|
||||
// enter_ background.
|
||||
//
|
||||
// This conservatism is useful, since we want to err on the side of
|
||||
// caution when, for example, we do work that should only be done
|
||||
// when the app is foreground and active.
|
||||
@property (atomic, readonly) UIApplicationState reportedApplicationState;
|
||||
|
||||
// A convenience accessor for reportedApplicationState.
|
||||
//
|
||||
// This method is thread-safe.
|
||||
- (BOOL)isInBackground;
|
||||
|
||||
// A convenience accessor for reportedApplicationState.
|
||||
//
|
||||
// This method is thread-safe.
|
||||
- (BOOL)isAppForegroundAndActive;
|
||||
|
||||
// Should start a background task if isMainApp is YES.
|
||||
// Should just return UIBackgroundTaskInvalid if isMainApp is NO.
|
||||
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:
|
||||
(BackgroundTaskExpirationHandler)expirationHandler;
|
||||
|
||||
// Should be a NOOP if isMainApp is NO.
|
||||
- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)backgroundTaskIdentifier;
|
||||
|
||||
// Should be a NOOP if isMainApp is NO.
|
||||
- (void)ensureSleepBlocking:(BOOL)shouldBeBlocking blockingObjects:(NSArray<id> *)blockingObjects;
|
||||
|
||||
// Should only be called if isMainApp is YES.
|
||||
- (void)setMainAppBadgeNumber:(NSInteger)value;
|
||||
|
||||
- (void)setStatusBarHidden:(BOOL)isHidden animated:(BOOL)isAnimated;
|
||||
|
||||
@property (nonatomic, readonly) CGFloat statusBarHeight;
|
||||
|
||||
// Returns the VC that should be used to present alerts, modals, etc.
|
||||
- (nullable UIViewController *)frontmostViewController;
|
||||
|
||||
// Returns nil if isMainApp is NO
|
||||
@property (nullable, nonatomic, readonly) UIAlertAction *openSystemSettingsAction;
|
||||
|
||||
// Should be a NOOP if isMainApp is NO.
|
||||
- (void)setNetworkActivityIndicatorVisible:(BOOL)value;
|
||||
|
||||
- (void)runNowOrWhenMainAppIsActive:(AppActiveBlock)block;
|
||||
|
||||
@property (atomic, readonly) NSDate *appLaunchTime;
|
||||
|
||||
- (id<SSKKeychainStorage>)keychainStorage;
|
||||
|
||||
- (NSString *)appDocumentDirectoryPath;
|
||||
|
||||
- (NSString *)appSharedDataDirectoryPath;
|
||||
|
||||
- (NSUserDefaults *)appUserDefaults;
|
||||
|
||||
@end
|
||||
|
||||
id<AppContext> CurrentAppContext(void);
|
||||
void SetCurrentAppContext(id<AppContext> appContext);
|
||||
|
||||
void ExitShareExtension(void);
|
||||
|
||||
#ifdef DEBUG
|
||||
void ClearCurrentAppContextForTests(void);
|
||||
#endif
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -0,0 +1,61 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppContext.h"
|
||||
#import <SessionProtocolKit/SessionProtocolKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NSString *const OWSApplicationDidEnterBackgroundNotification = @"OWSApplicationDidEnterBackgroundNotification";
|
||||
NSString *const OWSApplicationWillEnterForegroundNotification = @"OWSApplicationWillEnterForegroundNotification";
|
||||
NSString *const OWSApplicationWillResignActiveNotification = @"OWSApplicationWillResignActiveNotification";
|
||||
NSString *const OWSApplicationDidBecomeActiveNotification = @"OWSApplicationDidBecomeActiveNotification";
|
||||
|
||||
NSString *NSStringForUIApplicationState(UIApplicationState value)
|
||||
{
|
||||
switch (value) {
|
||||
case UIApplicationStateActive:
|
||||
return @"UIApplicationStateActive";
|
||||
case UIApplicationStateInactive:
|
||||
return @"UIApplicationStateInactive";
|
||||
case UIApplicationStateBackground:
|
||||
return @"UIApplicationStateBackground";
|
||||
}
|
||||
}
|
||||
|
||||
static id<AppContext> currentAppContext = nil;
|
||||
|
||||
id<AppContext> CurrentAppContext(void)
|
||||
{
|
||||
OWSCAssertDebug(currentAppContext);
|
||||
|
||||
return currentAppContext;
|
||||
}
|
||||
|
||||
void SetCurrentAppContext(id<AppContext> appContext)
|
||||
{
|
||||
// The main app context should only be set once.
|
||||
//
|
||||
// App extensions may be opened multiple times in the same process,
|
||||
// so statics will persist.
|
||||
OWSCAssertDebug(!currentAppContext || !currentAppContext.isMainApp);
|
||||
|
||||
currentAppContext = appContext;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void ClearCurrentAppContextForTests()
|
||||
{
|
||||
currentAppContext = nil;
|
||||
}
|
||||
#endif
|
||||
|
||||
void ExitShareExtension(void)
|
||||
{
|
||||
OWSLogInfo(@"ExitShareExtension");
|
||||
[DDLog flushLog];
|
||||
exit(0);
|
||||
}
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -0,0 +1,38 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void (^AppReadyBlock)(void);
|
||||
|
||||
@interface AppReadiness : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
// This method can be called on any thread.
|
||||
+ (BOOL)isAppReady;
|
||||
|
||||
// This method should only be called on the main thread.
|
||||
+ (void)setAppIsReady;
|
||||
|
||||
// If the app is ready, the block is called immediately;
|
||||
// otherwise it is called when the app becomes ready.
|
||||
//
|
||||
// This method should only be called on the main thread.
|
||||
// The block will always be called on the main thread.
|
||||
//
|
||||
// * The "will become ready" blocks are called before the "did become ready" blocks.
|
||||
// * The "will become ready" blocks should be used for internal setup of components
|
||||
// so that they are ready to interact with other components of the system.
|
||||
// * The "did become ready" blocks should be used for any work that should be done
|
||||
// on app launch, especially work that uses other components.
|
||||
// * We should usually use "did become ready" blocks since they are safer.
|
||||
+ (void)runNowOrWhenAppWillBecomeReady:(AppReadyBlock)block NS_SWIFT_NAME(runNowOrWhenAppWillBecomeReady(_:));
|
||||
+ (void)runNowOrWhenAppDidBecomeReady:(AppReadyBlock)block NS_SWIFT_NAME(runNowOrWhenAppDidBecomeReady(_:));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -0,0 +1,144 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppReadiness.h"
|
||||
#import <SessionProtocolKit/SessionProtocolKit.h>
|
||||
#import "AppContext.h"
|
||||
#import "SSKAsserts.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AppReadiness ()
|
||||
|
||||
@property (atomic) BOOL isAppReady;
|
||||
|
||||
@property (nonatomic) NSMutableArray<AppReadyBlock> *appWillBecomeReadyBlocks;
|
||||
@property (nonatomic) NSMutableArray<AppReadyBlock> *appDidBecomeReadyBlocks;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation AppReadiness
|
||||
|
||||
+ (instancetype)sharedManager
|
||||
{
|
||||
static AppReadiness *sharedMyManager = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
sharedMyManager = [[self alloc] initDefault];
|
||||
});
|
||||
return sharedMyManager;
|
||||
}
|
||||
|
||||
- (instancetype)initDefault
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
OWSSingletonAssert();
|
||||
|
||||
self.appWillBecomeReadyBlocks = [NSMutableArray new];
|
||||
self.appDidBecomeReadyBlocks = [NSMutableArray new];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (BOOL)isAppReady
|
||||
{
|
||||
return [self.sharedManager isAppReady];
|
||||
}
|
||||
|
||||
+ (void)runNowOrWhenAppWillBecomeReady:(AppReadyBlock)block
|
||||
{
|
||||
DispatchMainThreadSafe(^{
|
||||
[self.sharedManager runNowOrWhenAppWillBecomeReady:block];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)runNowOrWhenAppWillBecomeReady:(AppReadyBlock)block
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(block);
|
||||
|
||||
if (CurrentAppContext().isRunningTests) {
|
||||
// We don't need to do any "on app ready" work in the tests.
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.isAppReady) {
|
||||
block();
|
||||
return;
|
||||
}
|
||||
|
||||
[self.appWillBecomeReadyBlocks addObject:block];
|
||||
}
|
||||
|
||||
+ (void)runNowOrWhenAppDidBecomeReady:(AppReadyBlock)block
|
||||
{
|
||||
DispatchMainThreadSafe(^{
|
||||
[self.sharedManager runNowOrWhenAppDidBecomeReady:block];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)runNowOrWhenAppDidBecomeReady:(AppReadyBlock)block
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(block);
|
||||
|
||||
if (CurrentAppContext().isRunningTests) {
|
||||
// We don't need to do any "on app ready" work in the tests.
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.isAppReady) {
|
||||
block();
|
||||
return;
|
||||
}
|
||||
|
||||
[self.appDidBecomeReadyBlocks addObject:block];
|
||||
}
|
||||
|
||||
+ (void)setAppIsReady
|
||||
{
|
||||
[self.sharedManager setAppIsReady];
|
||||
}
|
||||
|
||||
- (void)setAppIsReady
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(!self.isAppReady);
|
||||
|
||||
OWSLogInfo(@"");
|
||||
|
||||
self.isAppReady = YES;
|
||||
|
||||
[self runAppReadyBlocks];
|
||||
}
|
||||
|
||||
- (void)runAppReadyBlocks
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(self.isAppReady);
|
||||
|
||||
NSArray<AppReadyBlock> *appWillBecomeReadyBlocks = [self.appWillBecomeReadyBlocks copy];
|
||||
[self.appWillBecomeReadyBlocks removeAllObjects];
|
||||
NSArray<AppReadyBlock> *appDidBecomeReadyBlocks = [self.appDidBecomeReadyBlocks copy];
|
||||
[self.appDidBecomeReadyBlocks removeAllObjects];
|
||||
|
||||
// We invoke the _will become_ blocks before the _did become_ blocks.
|
||||
for (AppReadyBlock block in appWillBecomeReadyBlocks) {
|
||||
block();
|
||||
}
|
||||
for (AppReadyBlock block in appDidBecomeReadyBlocks) {
|
||||
block();
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -0,0 +1,32 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AppVersion : NSObject
|
||||
|
||||
// The properties are updated immediately after launch.
|
||||
@property (atomic, readonly) NSString *firstAppVersion;
|
||||
@property (atomic, nullable, readonly) NSString *lastAppVersion;
|
||||
@property (atomic, readonly) NSString *currentAppVersion;
|
||||
|
||||
// There properties aren't updated until appLaunchDidComplete is called.
|
||||
@property (atomic, nullable, readonly) NSString *lastCompletedLaunchAppVersion;
|
||||
@property (atomic, nullable, readonly) NSString *lastCompletedLaunchMainAppVersion;
|
||||
@property (atomic, nullable, readonly) NSString *lastCompletedLaunchSAEAppVersion;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
+ (instancetype)sharedInstance;
|
||||
|
||||
- (void)mainAppLaunchDidComplete;
|
||||
- (void)saeLaunchDidComplete;
|
||||
|
||||
- (BOOL)isFirstLaunch;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -0,0 +1,133 @@
|
||||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppVersion.h"
|
||||
#import "NSUserDefaults+OWS.h"
|
||||
#import <SessionProtocolKit/SessionProtocolKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NSString *const kNSUserDefaults_FirstAppVersion = @"kNSUserDefaults_FirstAppVersion";
|
||||
NSString *const kNSUserDefaults_LastAppVersion = @"kNSUserDefaults_LastVersion";
|
||||
NSString *const kNSUserDefaults_LastCompletedLaunchAppVersion = @"kNSUserDefaults_LastCompletedLaunchAppVersion";
|
||||
NSString *const kNSUserDefaults_LastCompletedLaunchAppVersion_MainApp
|
||||
= @"kNSUserDefaults_LastCompletedLaunchAppVersion_MainApp";
|
||||
NSString *const kNSUserDefaults_LastCompletedLaunchAppVersion_SAE
|
||||
= @"kNSUserDefaults_LastCompletedLaunchAppVersion_SAE";
|
||||
|
||||
@interface AppVersion ()
|
||||
|
||||
@property (atomic) NSString *firstAppVersion;
|
||||
@property (atomic, nullable) NSString *lastAppVersion;
|
||||
@property (atomic) NSString *currentAppVersion;
|
||||
|
||||
@property (atomic, nullable) NSString *lastCompletedLaunchAppVersion;
|
||||
@property (atomic, nullable) NSString *lastCompletedLaunchMainAppVersion;
|
||||
@property (atomic, nullable) NSString *lastCompletedLaunchSAEAppVersion;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation AppVersion
|
||||
|
||||
+ (instancetype)sharedInstance
|
||||
{
|
||||
static AppVersion *instance = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
instance = [AppVersion new];
|
||||
[instance configure];
|
||||
});
|
||||
return instance;
|
||||
}
|
||||
|
||||
- (void)configure {
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
self.currentAppVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
|
||||
|
||||
// The version of the app when it was first launched.
|
||||
// nil if the app has never been launched before.
|
||||
self.firstAppVersion = [[NSUserDefaults appUserDefaults] objectForKey:kNSUserDefaults_FirstAppVersion];
|
||||
// The version of the app the last time it was launched.
|
||||
// nil if the app has never been launched before.
|
||||
self.lastAppVersion = [[NSUserDefaults appUserDefaults] objectForKey:kNSUserDefaults_LastAppVersion];
|
||||
self.lastCompletedLaunchAppVersion =
|
||||
[[NSUserDefaults appUserDefaults] objectForKey:kNSUserDefaults_LastCompletedLaunchAppVersion];
|
||||
self.lastCompletedLaunchMainAppVersion =
|
||||
[[NSUserDefaults appUserDefaults] objectForKey:kNSUserDefaults_LastCompletedLaunchAppVersion_MainApp];
|
||||
self.lastCompletedLaunchSAEAppVersion =
|
||||
[[NSUserDefaults appUserDefaults] objectForKey:kNSUserDefaults_LastCompletedLaunchAppVersion_SAE];
|
||||
|
||||
// Ensure the value for the "first launched version".
|
||||
if (!self.firstAppVersion) {
|
||||
self.firstAppVersion = self.currentAppVersion;
|
||||
[[NSUserDefaults appUserDefaults] setObject:self.currentAppVersion forKey:kNSUserDefaults_FirstAppVersion];
|
||||
}
|
||||
|
||||
// Update the value for the "most recently launched version".
|
||||
[[NSUserDefaults appUserDefaults] setObject:self.currentAppVersion forKey:kNSUserDefaults_LastAppVersion];
|
||||
[[NSUserDefaults appUserDefaults] synchronize];
|
||||
|
||||
// The long version string looks like an IPv4 address.
|
||||
// To prevent the log scrubber from scrubbing it,
|
||||
// we replace . with _.
|
||||
NSString *longVersionString = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]
|
||||
stringByReplacingOccurrencesOfString:@"."
|
||||
withString:@"_"];
|
||||
|
||||
OWSLogInfo(@"firstAppVersion: %@", self.firstAppVersion);
|
||||
OWSLogInfo(@"lastAppVersion: %@", self.lastAppVersion);
|
||||
OWSLogInfo(@"currentAppVersion: %@ (%@)", self.currentAppVersion, longVersionString);
|
||||
|
||||
OWSLogInfo(@"lastCompletedLaunchAppVersion: %@", self.lastCompletedLaunchAppVersion);
|
||||
OWSLogInfo(@"lastCompletedLaunchMainAppVersion: %@", self.lastCompletedLaunchMainAppVersion);
|
||||
OWSLogInfo(@"lastCompletedLaunchSAEAppVersion: %@", self.lastCompletedLaunchSAEAppVersion);
|
||||
}
|
||||
|
||||
- (void)appLaunchDidComplete
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
OWSLogInfo(@"appLaunchDidComplete");
|
||||
|
||||
self.lastCompletedLaunchAppVersion = self.currentAppVersion;
|
||||
|
||||
// Update the value for the "most recently launch-completed version".
|
||||
[[NSUserDefaults appUserDefaults] setObject:self.currentAppVersion
|
||||
forKey:kNSUserDefaults_LastCompletedLaunchAppVersion];
|
||||
[[NSUserDefaults appUserDefaults] synchronize];
|
||||
}
|
||||
|
||||
- (void)mainAppLaunchDidComplete
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
self.lastCompletedLaunchMainAppVersion = self.currentAppVersion;
|
||||
[[NSUserDefaults appUserDefaults] setObject:self.currentAppVersion
|
||||
forKey:kNSUserDefaults_LastCompletedLaunchAppVersion_MainApp];
|
||||
|
||||
[self appLaunchDidComplete];
|
||||
}
|
||||
|
||||
- (void)saeLaunchDidComplete
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
self.lastCompletedLaunchSAEAppVersion = self.currentAppVersion;
|
||||
[[NSUserDefaults appUserDefaults] setObject:self.currentAppVersion
|
||||
forKey:kNSUserDefaults_LastCompletedLaunchAppVersion_SAE];
|
||||
|
||||
[self appLaunchDidComplete];
|
||||
}
|
||||
|
||||
- (BOOL)isFirstLaunch
|
||||
{
|
||||
return self.firstAppVersion != nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -0,0 +1,7 @@
|
||||
|
||||
public extension Array where Element : CustomStringConvertible {
|
||||
|
||||
public var prettifiedDescription: String {
|
||||
return "[ " + map { $0.description }.joined(separator: ", ") + " ]"
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
|
||||
public enum BuildConfiguration : String, CustomStringConvertible {
|
||||
case debug, production
|
||||
|
||||
public static let current: BuildConfiguration = {
|
||||
#if DEBUG
|
||||
return .debug
|
||||
#else
|
||||
return .production
|
||||
#endif
|
||||
}()
|
||||
|
||||
public var description: String { return rawValue }
|
||||
}
|
||||
|
||||
@objc public final class LKBuildConfiguration : NSObject {
|
||||
|
||||
override private init() { }
|
||||
|
||||
@objc public static var current: String { return BuildConfiguration.current.description }
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ByteParser : NSObject
|
||||
|
||||
@property (nonatomic, readonly) BOOL hasError;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data littleEndian:(BOOL)littleEndian;
|
||||
|
||||
#pragma mark - Short
|
||||
|
||||
- (uint16_t)shortAtIndex:(NSUInteger)index;
|
||||
- (uint16_t)nextShort;
|
||||
|
||||
#pragma mark - Int
|
||||
|
||||
- (uint32_t)intAtIndex:(NSUInteger)index;
|
||||
- (uint32_t)nextInt;
|
||||
|
||||
#pragma mark - Long
|
||||
|
||||
- (uint64_t)longAtIndex:(NSUInteger)index;
|
||||
- (uint64_t)nextLong;
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (BOOL)readZero:(NSUInteger)length;
|
||||
|
||||
- (nullable NSData *)readBytes:(NSUInteger)length;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -0,0 +1,143 @@
|
||||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ByteParser.h"
|
||||
#import <SessionProtocolKit/SessionProtocolKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ByteParser ()
|
||||
|
||||
@property (nonatomic, readonly) BOOL littleEndian;
|
||||
@property (nonatomic, readonly) NSData *data;
|
||||
@property (nonatomic) NSUInteger cursor;
|
||||
@property (nonatomic) BOOL hasError;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation ByteParser
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data littleEndian:(BOOL)littleEndian
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_littleEndian = littleEndian;
|
||||
_data = data;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Short
|
||||
|
||||
- (uint16_t)shortAtIndex:(NSUInteger)index
|
||||
{
|
||||
uint16_t value;
|
||||
const size_t valueSize = sizeof(value);
|
||||
OWSAssertDebug(valueSize == 2);
|
||||
if (index + valueSize > self.data.length) {
|
||||
self.hasError = YES;
|
||||
return 0;
|
||||
}
|
||||
[self.data getBytes:&value range:NSMakeRange(index, valueSize)];
|
||||
if (self.littleEndian) {
|
||||
return CFSwapInt16LittleToHost(value);
|
||||
} else {
|
||||
return CFSwapInt16BigToHost(value);
|
||||
}
|
||||
}
|
||||
|
||||
- (uint16_t)nextShort
|
||||
{
|
||||
uint16_t value = [self shortAtIndex:self.cursor];
|
||||
self.cursor += sizeof(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
#pragma mark - Int
|
||||
|
||||
- (uint32_t)intAtIndex:(NSUInteger)index
|
||||
{
|
||||
uint32_t value;
|
||||
const size_t valueSize = sizeof(value);
|
||||
OWSAssertDebug(valueSize == 4);
|
||||
if (index + valueSize > self.data.length) {
|
||||
self.hasError = YES;
|
||||
return 0;
|
||||
}
|
||||
[self.data getBytes:&value range:NSMakeRange(index, valueSize)];
|
||||
if (self.littleEndian) {
|
||||
return CFSwapInt32LittleToHost(value);
|
||||
} else {
|
||||
return CFSwapInt32BigToHost(value);
|
||||
}
|
||||
}
|
||||
|
||||
- (uint32_t)nextInt
|
||||
{
|
||||
uint32_t value = [self intAtIndex:self.cursor];
|
||||
self.cursor += sizeof(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
#pragma mark - Long
|
||||
|
||||
- (uint64_t)longAtIndex:(NSUInteger)index
|
||||
{
|
||||
uint64_t value;
|
||||
const size_t valueSize = sizeof(value);
|
||||
OWSAssertDebug(valueSize == 8);
|
||||
if (index + valueSize > self.data.length) {
|
||||
self.hasError = YES;
|
||||
return 0;
|
||||
}
|
||||
[self.data getBytes:&value range:NSMakeRange(index, valueSize)];
|
||||
if (self.littleEndian) {
|
||||
return CFSwapInt64LittleToHost(value);
|
||||
} else {
|
||||
return CFSwapInt64BigToHost(value);
|
||||
}
|
||||
}
|
||||
|
||||
- (uint64_t)nextLong
|
||||
{
|
||||
uint64_t value = [self longAtIndex:self.cursor];
|
||||
self.cursor += sizeof(value);
|
||||