Page MenuHomePhabricator

No OneTemporary

diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h
index 8d68165b8..94e73fb9b 100644
--- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h
+++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h
@@ -1,71 +1,72 @@
#pragma once
#include "../CryptoTools/Persist.h"
#include "DatabaseQueryExecutor.h"
#include "entities/Draft.h"
#include <mutex>
#include <string>
namespace comm {
class SQLiteQueryExecutor : public DatabaseQueryExecutor {
void migrate() const;
static void assign_encryption_key();
static auto &getStorage();
void setMetadata(std::string entry_name, std::string data) const override;
void clearMetadata(std::string entry_name) const override;
std::string getMetadata(std::string entry_name) const override;
static std::once_flag initialized;
static int sqlcipherEncryptionKeySize;
- static std::string secureStoreEncryptionKeyID;
public:
static std::string sqliteFilePath;
static std::string encryptionKey;
+ static std::string secureStoreEncryptionKeyID;
+
SQLiteQueryExecutor();
static void initialize(std::string &databasePath);
std::unique_ptr<Thread> getThread(std::string threadID) const override;
std::string getDraft(std::string key) const override;
void updateDraft(std::string key, std::string text) const override;
bool moveDraft(std::string oldKey, std::string newKey) const override;
std::vector<Draft> getAllDrafts() const override;
void removeAllDrafts() const override;
void removeAllMessages() const override;
std::vector<std::pair<Message, std::vector<Media>>>
getAllMessages() const override;
void removeMessages(const std::vector<std::string> &ids) const override;
void removeMessagesForThreads(
const std::vector<std::string> &threadIDs) const override;
void replaceMessage(const Message &message) const override;
void rekeyMessage(std::string from, std::string to) const override;
void removeAllMedia() const override;
void removeMediaForMessages(
const std::vector<std::string> &msg_ids) const override;
void removeMediaForMessage(std::string msg_id) const override;
void removeMediaForThreads(
const std::vector<std::string> &thread_ids) const override;
void replaceMedia(const Media &media) const override;
void rekeyMediaContainers(std::string from, std::string to) const override;
std::vector<Thread> getAllThreads() const override;
void removeThreads(std::vector<std::string> ids) const override;
void replaceThread(const Thread &thread) const override;
void removeAllThreads() const override;
void beginTransaction() const override;
void commitTransaction() const override;
void rollbackTransaction() const override;
std::vector<OlmPersistSession> getOlmPersistSessionsData() const override;
folly::Optional<std::string> getOlmPersistAccountData() const override;
void storeOlmPersistData(crypto::Persist persist) const override;
void setNotifyToken(std::string token) const override;
void clearNotifyToken() const override;
void setCurrentUserID(std::string userID) const override;
std::string getCurrentUserID() const override;
void setDeviceID(std::string deviceID) const override;
std::string getDeviceID() const override;
void clearSensitiveData() const override;
};
} // namespace comm
diff --git a/native/ios/Comm/AppDelegate.mm b/native/ios/Comm/AppDelegate.mm
index 5436d2fbf..e53a28677 100644
--- a/native/ios/Comm/AppDelegate.mm
+++ b/native/ios/Comm/AppDelegate.mm
@@ -1,294 +1,301 @@
#import "AppDelegate.h"
#import "Orientation.h"
#import "RNNotifications.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTConvert.h>
#import <React/RCTRootView.h>
#import <React/RCTBridge+Private.h>
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTJSIExecutorRuntimeInstaller.h>
#import <cxxreact/JSExecutor.h>
#import <jsireact/JSIExecutor.h>
#import <reacthermes/HermesExecutorFactory.h>
#import "CommCoreModule.h"
+#import "CommSecureStoreIOSWrapper.h"
#import "GlobalDBSingleton.h"
#import "Logger.h"
#import "MessageOperationsUtilities.h"
#import "SQLiteQueryExecutor.h"
#import "TemporaryMessageStorage.h"
#import "ThreadOperations.h"
#import "Tools.h"
#import <cstdio>
#import <stdexcept>
#import <string>
#ifdef FB_SONARKIT_ENABLED
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
static void InitializeFlipper(UIApplication *application) {
FlipperClient *client = [FlipperClient sharedClient];
SKDescriptorMapper *layoutDescriptorMapper =
[[SKDescriptorMapper alloc] initWithDefaults];
[client addPlugin:[[FlipperKitLayoutPlugin alloc]
initWithRootNode:application
withDescriptorMapper:layoutDescriptorMapper]];
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
[client addPlugin:[FlipperKitReactPlugin new]];
[client addPlugin:[[FlipperKitNetworkPlugin alloc]
initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
[client start];
}
#endif
#import <ReactCommon/RCTTurboModuleManager.h>
#import <RNReanimated/REAInitializer.h>
#import <UserNotifications/UserNotifications.h>
NSString *const backgroundNotificationTypeKey = @"backgroundNotifType";
NSString *const setUnreadStatusKey = @"setUnreadStatus";
@interface AppDelegate () <
RCTCxxBridgeDelegate,
RCTTurboModuleManagerDelegate> {
}
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+ NSString *secureStoreEncryptionKeyID = [NSString
+ stringWithUTF8String:
+ (comm::SQLiteQueryExecutor::secureStoreEncryptionKeyID.c_str())];
+ [[CommSecureStoreIOSWrapper sharedInstance]
+ migrateOptionsForKey:secureStoreEncryptionKeyID
+ withVersion:@"0"];
[self attemptDatabaseInitialization];
return YES;
}
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
#ifdef FB_SONARKIT_ENABLED
InitializeFlipper(application);
#endif
[self moveMessagesToDatabase];
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self
launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"Comm"
initialProperties:nil];
if (@available(iOS 13.0, *)) {
rootView.backgroundColor = [UIColor systemBackgroundColor];
} else {
rootView.backgroundColor = [UIColor whiteColor];
}
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[super application:application didFinishLaunchingWithOptions:launchOptions];
// This prevents a very small flicker from occurring before expo-splash-screen
// is able to display
UIView *launchScreenView =
[[UIStoryboard storyboardWithName:@"SplashScreen"
bundle:nil] instantiateInitialViewController]
.view;
launchScreenView.frame = self.window.bounds;
rootView.loadingView = launchScreenView;
rootView.loadingViewFadeDelay = 0;
rootView.loadingViewFadeDuration = 0.001;
return YES;
}
- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge {
// If you'd like to export some custom RCTBridgeModules that are not Expo
// modules, add them here!
return @[];
}
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[RNNotifications
didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
- (void)application:(UIApplication *)application
didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
[RNNotifications didFailToRegisterForRemoteNotificationsWithError:error];
}
// Required for the notification event. You must call the completion handler
// after handling the remote notification.
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)notification
fetchCompletionHandler:
(void (^)(UIBackgroundFetchResult))completionHandler {
BOOL handled = NO;
if (notification[@"aps"][@"content-available"] &&
notification[backgroundNotificationTypeKey]) {
handled = [self handleBackgroundNotification:notification
fetchCompletionHandler:completionHandler];
}
if (handled) {
return;
}
[RNNotifications didReceiveRemoteNotification:notification
fetchCompletionHandler:completionHandler];
}
- (BOOL)handleBackgroundNotification:(NSDictionary *)notification
fetchCompletionHandler:
(void (^)(UIBackgroundFetchResult))completionHandler {
if ([notification[backgroundNotificationTypeKey] isEqualToString:@"CLEAR"]) {
if (notification[setUnreadStatusKey] && notification[@"threadID"]) {
std::string threadID =
std::string([notification[@"threadID"] UTF8String]);
// this callback may be called from inactive state so we need
// to initialize the database
[self attemptDatabaseInitialization];
comm::GlobalDBSingleton::instance.scheduleOrRun([threadID]() mutable {
comm::ThreadOperations::updateSQLiteUnreadStatus(threadID, false);
});
}
[[UNUserNotificationCenter currentNotificationCenter]
getDeliveredNotificationsWithCompletionHandler:^(
NSArray<UNNotification *> *notifications) {
for (UNNotification *notif in notifications) {
if ([notification[@"notificationId"]
isEqual:notif.request.content.userInfo[@"id"]]) {
NSArray *identifiers =
[NSArray arrayWithObjects:notif.request.identifier, nil];
[[UNUserNotificationCenter currentNotificationCenter]
removeDeliveredNotificationsWithIdentifiers:identifiers];
}
}
dispatch_async(dispatch_get_main_queue(), ^{
completionHandler(UIBackgroundFetchResultNewData);
});
}];
return YES;
}
return NO;
}
// Required for the localNotification event.
- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification {
[RNNotifications didReceiveLocalNotification:notification];
}
- (UIInterfaceOrientationMask)application:(UIApplication *)application
supportedInterfaceOrientationsForWindow:(UIWindow *)window {
return [Orientation getOrientation];
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
#if DEBUG
return
[[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"
fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:@"main"
withExtension:@"jsbundle"];
#endif
}
using JSExecutorFactory = facebook::react::JSExecutorFactory;
using HermesExecutorFactory = facebook::react::HermesExecutorFactory;
using Runtime = facebook::jsi::Runtime;
- (std::unique_ptr<JSExecutorFactory>)jsExecutorFactoryForBridge:
(RCTBridge *)bridge {
__weak __typeof(self) weakSelf = self;
const auto commRuntimeInstaller = [weakSelf,
bridge](facebook::jsi::Runtime &rt) {
if (!bridge) {
return;
}
__typeof(self) strongSelf = weakSelf;
if (strongSelf) {
std::shared_ptr<comm::CommCoreModule> nativeModule =
std::make_shared<comm::CommCoreModule>(bridge.jsCallInvoker);
rt.global().setProperty(
rt,
facebook::jsi::PropNameID::forAscii(rt, "CommCoreModule"),
facebook::jsi::Object::createFromHostObject(rt, nativeModule));
}
};
const auto installer =
reanimated::REAJSIExecutorRuntimeInstaller(bridge, commRuntimeInstaller);
return std::make_unique<HermesExecutorFactory>(
facebook::react::RCTJSIExecutorRuntimeInstaller(installer),
JSIExecutor::defaultTimeoutInvoker,
makeRuntimeConfig(3072));
}
- (void)attemptDatabaseInitialization {
std::string sqliteFilePath =
std::string([[Tools getSQLiteFilePath] UTF8String]);
// Previous Comm versions used app group location for SQLite
// database, so that NotificationService was able to acces it directly.
// Unfortunately it caused errores related to system locks. The code
// below re-migrates SQLite from app group to app specific location
// on devices where previous Comm version was installed.
NSString *appGroupSQLiteFilePath = [Tools getAppGroupSQLiteFilePath];
if ([NSFileManager.defaultManager fileExistsAtPath:appGroupSQLiteFilePath] &&
std::rename(
std::string([appGroupSQLiteFilePath UTF8String]).c_str(),
sqliteFilePath.c_str())) {
throw std::runtime_error(
"Failed to move SQLite database from app group to default location");
}
comm::SQLiteQueryExecutor::initialize(sqliteFilePath);
}
- (void)moveMessagesToDatabase {
TemporaryMessageStorage *temporaryStorage =
[[TemporaryMessageStorage alloc] init];
NSArray<NSString *> *messages = [temporaryStorage readAndClearMessages];
for (NSString *message in messages) {
std::string messageInfos = std::string([message UTF8String]);
comm::GlobalDBSingleton::instance.scheduleOrRun([messageInfos]() mutable {
comm::MessageOperationsUtilities::storeMessageInfos(messageInfos);
});
}
}
// Copied from
// ReactAndroid/src/main/java/com/facebook/hermes/reactexecutor/OnLoad.cpp
static ::hermes::vm::RuntimeConfig
makeRuntimeConfig(::hermes::vm::gcheapsize_t heapSizeMB) {
namespace vm = ::hermes::vm;
auto gcConfigBuilder =
vm::GCConfig::Builder()
.withName("RN")
// For the next two arguments: avoid GC before TTI by initializing the
// runtime to allocate directly in the old generation, but revert to
// normal operation when we reach the (first) TTI point.
.withAllocInYoung(false)
.withRevertToYGAtTTI(true);
if (heapSizeMB > 0) {
gcConfigBuilder.withMaxHeapSize(heapSizeMB << 20);
}
return vm::RuntimeConfig::Builder()
.withGCConfig(gcConfigBuilder.build())
.build();
}
@end
diff --git a/native/ios/Comm/CommSecureStoreIOSWrapper.h b/native/ios/Comm/CommSecureStoreIOSWrapper.h
index ef7b40166..9406e5b9e 100644
--- a/native/ios/Comm/CommSecureStoreIOSWrapper.h
+++ b/native/ios/Comm/CommSecureStoreIOSWrapper.h
@@ -1,12 +1,13 @@
#pragma once
#import <EXSecureStore/EXSecureStore.h>
#import <Foundation/Foundation.h>
@interface CommSecureStoreIOSWrapper : NSObject
+ (id)sharedInstance;
- (void)set:(NSString *)key value:(NSString *)value;
- (NSString *)get:(NSString *)key;
+- (void)migrateOptionsForKey:(NSString *)key withVersion:(NSString *)version;
@end
diff --git a/native/ios/Comm/CommSecureStoreIOSWrapper.mm b/native/ios/Comm/CommSecureStoreIOSWrapper.mm
index c309fd23a..c8a5f8ce4 100644
--- a/native/ios/Comm/CommSecureStoreIOSWrapper.mm
+++ b/native/ios/Comm/CommSecureStoreIOSWrapper.mm
@@ -1,67 +1,99 @@
#import "CommSecureStoreIOSWrapper.h"
#import "CommSecureStoreIOSWrapper.h"
#import <ExpoModulesCore/EXModuleRegistryProvider.h>
@interface CommSecureStoreIOSWrapper ()
@property(nonatomic, strong) EXSecureStore *secureStore;
@property(nonatomic, strong) NSDictionary *options;
@end
@interface EXSecureStore (CommEXSecureStore)
- (BOOL)_setValue:(NSString *)value
withKey:(NSString *)key
withOptions:(NSDictionary *)options
error:(NSError **)error;
- (NSString *)_getValueWithKey:(NSString *)key
withOptions:(NSDictionary *)options
error:(NSError **)error;
+- (void)_deleteValueWithKey:(NSString *)key withOptions:(NSDictionary *)options;
@end
@implementation CommSecureStoreIOSWrapper
#pragma mark Singleton Methods
+ (id)sharedInstance {
static CommSecureStoreIOSWrapper *shared = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shared = [[self alloc] init];
EXModuleRegistryProvider *moduleRegistryProvider =
[[EXModuleRegistryProvider alloc] init];
EXSecureStore *secureStore =
(EXSecureStore *)[[moduleRegistryProvider moduleRegistry]
getExportedModuleOfClass:EXSecureStore.class];
shared.secureStore = secureStore;
+ shared.options =
+ @{@"keychainAccessible" : @(EXSecureStoreAccessibleAfterFirstUnlock)};
});
return shared;
}
- (void)set:(NSString *)key value:(NSString *)value {
if ([self secureStore] == nil) {
[NSException raise:@"secure store error"
format:@"secure store has not been initialized"];
}
NSError *error;
[[self secureStore] _setValue:value
withKey:key
withOptions:[self options]
error:&error];
if (error != nil) {
[NSException raise:@"secure store error"
format:@"error occured when setting data"];
}
}
- (NSString *)get:(NSString *)key {
if ([self secureStore] == nil) {
[NSException raise:@"secure store error"
format:@"secure store has not been initialized"];
}
NSError *error;
return [[self secureStore] _getValueWithKey:key
withOptions:[self options]
error:&error];
}
+- (void)migrateOptionsForKey:(NSString *)key withVersion:(NSString *)version {
+ NSString *secureStoreKeyVersionID = [key stringByAppendingString:@".version"];
+ NSString *failureProtectionCopyKey = [key stringByAppendingString:@".copy"];
+
+ NSString *secureStoreKeyVersion = [self get:secureStoreKeyVersionID];
+ if (secureStoreKeyVersion &&
+ [secureStoreKeyVersion isEqualToString:version]) {
+ return;
+ }
+
+ NSString *value = [self get:key];
+ NSString *valueCopy = [self get:failureProtectionCopyKey];
+
+ if (value) {
+ [self set:failureProtectionCopyKey value:value];
+ [[self secureStore] _deleteValueWithKey:key withOptions:[self options]];
+ } else if (valueCopy) {
+ value = valueCopy;
+ } else {
+ [self set:secureStoreKeyVersionID value:version];
+ return;
+ }
+
+ [self set:key value:value];
+ [self set:secureStoreKeyVersionID value:version];
+ [[self secureStore] _deleteValueWithKey:failureProtectionCopyKey
+ withOptions:[self options]];
+}
+
@end

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 23, 12:38 AM (3 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2675865
Default Alt Text
(18 KB)

Event Timeline