RLMUser.mm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 Realm Inc.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. ////////////////////////////////////////////////////////////////////////////
  18. #import "RLMUser_Private.hpp"
  19. #import "RLMAPIKeyAuth.h"
  20. #import "RLMApp_Private.hpp"
  21. #import "RLMBSON_Private.hpp"
  22. #import "RLMCredentials_Private.hpp"
  23. #import "RLMMongoClient_Private.hpp"
  24. #import "RLMRealmConfiguration_Private.h"
  25. #import "RLMSyncConfiguration_Private.hpp"
  26. #import "RLMSyncSession_Private.hpp"
  27. #import "RLMUtil.hpp"
  28. #import <realm/object-store/sync/sync_manager.hpp>
  29. #import <realm/object-store/sync/sync_session.hpp>
  30. #import <realm/object-store/sync/sync_user.hpp>
  31. #import <realm/object-store/util/bson/bson.hpp>
  32. using namespace realm;
  33. @interface RLMUser () {
  34. std::shared_ptr<SyncUser> _user;
  35. }
  36. @end
  37. @implementation RLMUserSubscriptionToken {
  38. std::shared_ptr<SyncUser> _user;
  39. std::optional<realm::Subscribable<SyncUser>::Token> _token;
  40. }
  41. - (instancetype)initWithUser:(std::shared_ptr<SyncUser>)user token:(realm::Subscribable<SyncUser>::Token&&)token {
  42. if (self = [super init]) {
  43. _user = std::move(user);
  44. _token = std::move(token);
  45. }
  46. return self;
  47. }
  48. - (void)unsubscribe {
  49. _token.reset();
  50. _user.reset();
  51. }
  52. @end
  53. @implementation RLMUser
  54. #pragma mark - API
  55. - (instancetype)initWithUser:(std::shared_ptr<SyncUser>)user
  56. app:(RLMApp *)app {
  57. if (self = [super init]) {
  58. _user = user;
  59. _app = app;
  60. return self;
  61. }
  62. return nil;
  63. }
  64. - (BOOL)isEqual:(id)object {
  65. if (![object isKindOfClass:[RLMUser class]]) {
  66. return NO;
  67. }
  68. return _user == ((RLMUser *)object)->_user;
  69. }
  70. - (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id<RLMBSON>)partitionValue {
  71. return [self configurationWithPartitionValue:partitionValue clientResetMode:RLMClientResetModeRecoverUnsyncedChanges];
  72. }
  73. - (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id<RLMBSON>)partitionValue
  74. clientResetMode:(RLMClientResetMode)clientResetMode {
  75. auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self
  76. partitionValue:partitionValue];
  77. syncConfig.clientResetMode = clientResetMode;
  78. RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
  79. config.syncConfiguration = syncConfig;
  80. return config;
  81. }
  82. - (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id<RLMBSON>)partitionValue
  83. clientResetMode:(RLMClientResetMode)clientResetMode
  84. notifyBeforeReset:(nullable RLMClientResetBeforeBlock)beforeResetBlock
  85. notifyAfterReset:(nullable RLMClientResetAfterBlock)afterResetBlock {
  86. auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self
  87. partitionValue:partitionValue];
  88. syncConfig.clientResetMode = clientResetMode;
  89. syncConfig.beforeClientReset = beforeResetBlock;
  90. syncConfig.afterClientReset = afterResetBlock;
  91. RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
  92. config.syncConfiguration = syncConfig;
  93. return config;
  94. }
  95. - (RLMRealmConfiguration *)configurationWithPartitionValue:(nullable id<RLMBSON>)partitionValue
  96. clientResetMode:(RLMClientResetMode)clientResetMode
  97. manualClientResetHandler:(nullable RLMSyncErrorReportingBlock)manualClientResetHandler {
  98. auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self
  99. partitionValue:partitionValue];
  100. syncConfig.clientResetMode = clientResetMode;
  101. syncConfig.manualClientResetHandler = manualClientResetHandler;
  102. RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
  103. config.syncConfiguration = syncConfig;
  104. return config;
  105. }
  106. - (RLMRealmConfiguration *)flexibleSyncConfiguration {
  107. RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
  108. config.syncConfiguration = [[RLMSyncConfiguration alloc] initWithUser:self];
  109. return config;
  110. }
  111. - (RLMRealmConfiguration *)flexibleSyncConfigurationWithClientResetMode:(RLMClientResetMode)clientResetMode
  112. notifyBeforeReset:(nullable RLMClientResetBeforeBlock)beforeResetBlock
  113. notifyAfterReset:(nullable RLMClientResetAfterBlock)afterResetBlock {
  114. auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self];
  115. RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
  116. syncConfig.clientResetMode = clientResetMode;
  117. syncConfig.beforeClientReset = beforeResetBlock;
  118. syncConfig.afterClientReset = afterResetBlock;
  119. config.syncConfiguration = syncConfig;
  120. return config;
  121. }
  122. - (RLMRealmConfiguration *)flexibleSyncConfigurationWithClientResetMode:(RLMClientResetMode)clientResetMode
  123. manualClientResetHandler:(nullable RLMSyncErrorReportingBlock)manualClientResetHandler {
  124. auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self];
  125. RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
  126. syncConfig.clientResetMode = clientResetMode;
  127. syncConfig.manualClientResetHandler = manualClientResetHandler;
  128. config.syncConfiguration = syncConfig;
  129. return config;
  130. }
  131. - (RLMRealmConfiguration *)flexibleSyncConfigurationWithInitialSubscriptions:(RLMFlexibleSyncInitialSubscriptionsBlock)initialSubscriptions
  132. rerunOnOpen:(BOOL)rerunOnOpen {
  133. auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self];
  134. RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
  135. config.initialSubscriptions = initialSubscriptions;
  136. config.rerunOnOpen = rerunOnOpen;
  137. config.syncConfiguration = syncConfig;
  138. return config;
  139. }
  140. - (RLMRealmConfiguration *)flexibleSyncConfigurationWithInitialSubscriptions:(RLMFlexibleSyncInitialSubscriptionsBlock)initialSubscriptions
  141. rerunOnOpen:(BOOL)rerunOnOpen
  142. clientResetMode:(RLMClientResetMode)clientResetMode
  143. notifyBeforeReset:(nullable RLMClientResetBeforeBlock)beforeResetBlock
  144. notifyAfterReset:(nullable RLMClientResetAfterBlock)afterResetBlock {
  145. auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self];
  146. RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
  147. syncConfig.clientResetMode = clientResetMode;
  148. syncConfig.beforeClientReset = beforeResetBlock;
  149. syncConfig.afterClientReset = afterResetBlock;
  150. config.initialSubscriptions = initialSubscriptions;
  151. config.rerunOnOpen = rerunOnOpen;
  152. config.syncConfiguration = syncConfig;
  153. return config;
  154. }
  155. - (RLMRealmConfiguration *)flexibleSyncConfigurationWithInitialSubscriptions:(RLMFlexibleSyncInitialSubscriptionsBlock)initialSubscriptions
  156. rerunOnOpen:(BOOL)rerunOnOpen
  157. clientResetMode:(RLMClientResetMode)clientResetMode
  158. manualClientResetHandler:(nullable RLMSyncErrorReportingBlock)manualClientResetHandler {
  159. auto syncConfig = [[RLMSyncConfiguration alloc] initWithUser:self];
  160. RLMRealmConfiguration *config = [[RLMRealmConfiguration alloc] init];
  161. syncConfig.clientResetMode = clientResetMode;
  162. syncConfig.manualClientResetHandler = manualClientResetHandler;
  163. config.initialSubscriptions = initialSubscriptions;
  164. config.rerunOnOpen = rerunOnOpen;
  165. config.syncConfiguration = syncConfig;
  166. return config;
  167. }
  168. - (void)logOut {
  169. if (!_user) {
  170. return;
  171. }
  172. _user->log_out();
  173. }
  174. - (BOOL)isLoggedIn {
  175. return _user->is_logged_in();
  176. }
  177. - (void)invalidate {
  178. if (!_user) {
  179. return;
  180. }
  181. _user = nullptr;
  182. }
  183. - (std::string)pathForPartitionValue:(std::string const&)value {
  184. if (!_user) {
  185. return "";
  186. }
  187. SyncConfig config(_user, value);
  188. auto path = _user->sync_manager()->path_for_realm(config, value);
  189. if ([NSFileManager.defaultManager fileExistsAtPath:@(path.c_str())]) {
  190. return path;
  191. }
  192. // Previous versions converted the partition value to a path *twice*,
  193. // so if the file resulting from that exists open it instead
  194. NSString *encodedPartitionValue = [@(value.data())
  195. stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]];
  196. NSString *overEncodedRealmName = [[NSString alloc] initWithFormat:@"%@/%@", self.identifier, encodedPartitionValue];
  197. auto legacyPath = _user->sync_manager()->path_for_realm(config, std::string(overEncodedRealmName.UTF8String));
  198. if ([NSFileManager.defaultManager fileExistsAtPath:@(legacyPath.c_str())]) {
  199. return legacyPath;
  200. }
  201. return path;
  202. }
  203. - (std::string)pathForFlexibleSync {
  204. if (!_user) {
  205. @throw RLMException(@"This is an exceptional state, `RLMUser` cannot be initialised without a reference to `SyncUser`");
  206. }
  207. SyncConfig config(_user, SyncConfig::FLXSyncEnabled{});
  208. return _user->sync_manager()->path_for_realm(config, realm::none);
  209. }
  210. - (nullable RLMSyncSession *)sessionForPartitionValue:(id<RLMBSON>)partitionValue {
  211. if (!_user) {
  212. return nil;
  213. }
  214. std::stringstream s;
  215. s << RLMConvertRLMBSONToBson(partitionValue);
  216. auto path = [self pathForPartitionValue:s.str()];
  217. if (auto session = _user->session_for_on_disk_path(path)) {
  218. return [[RLMSyncSession alloc] initWithSyncSession:session];
  219. }
  220. return nil;
  221. }
  222. - (NSArray<RLMSyncSession *> *)allSessions {
  223. if (!_user) {
  224. return @[];
  225. }
  226. NSMutableArray<RLMSyncSession *> *buffer = [NSMutableArray array];
  227. auto sessions = _user->all_sessions();
  228. for (auto session : sessions) {
  229. [buffer addObject:[[RLMSyncSession alloc] initWithSyncSession:std::move(session)]];
  230. }
  231. return [buffer copy];
  232. }
  233. - (NSString *)identifier {
  234. if (!_user) {
  235. return @"";
  236. }
  237. return @(_user->identity().c_str());
  238. }
  239. - (NSArray<RLMUserIdentity *> *)identities {
  240. if (!_user) {
  241. return @[];
  242. }
  243. NSMutableArray<RLMUserIdentity *> *buffer = [NSMutableArray array];
  244. auto identities = _user->identities();
  245. for (auto& identity : identities) {
  246. [buffer addObject: [[RLMUserIdentity alloc] initUserIdentityWithProviderType:@(identity.provider_type.c_str())
  247. identifier:@(identity.id.c_str())]];
  248. }
  249. return [buffer copy];
  250. }
  251. - (RLMUserState)state {
  252. if (!_user) {
  253. return RLMUserStateRemoved;
  254. }
  255. switch (_user->state()) {
  256. case SyncUser::State::LoggedIn:
  257. return RLMUserStateLoggedIn;
  258. case SyncUser::State::LoggedOut:
  259. return RLMUserStateLoggedOut;
  260. case SyncUser::State::Removed:
  261. return RLMUserStateRemoved;
  262. }
  263. }
  264. - (void)refreshCustomDataWithCompletion:(RLMUserCustomDataBlock)completion {
  265. _user->refresh_custom_data([completion, self](std::optional<app::AppError> error) {
  266. if (!error) {
  267. return completion([self customData], nil);
  268. }
  269. completion(nil, makeError(*error));
  270. });
  271. }
  272. - (void)linkUserWithCredentials:(RLMCredentials *)credentials
  273. completion:(RLMOptionalUserBlock)completion {
  274. _app._realmApp->link_user(_user, credentials.appCredentials,
  275. ^(std::shared_ptr<SyncUser> user, std::optional<app::AppError> error) {
  276. if (error) {
  277. return completion(nil, makeError(*error));
  278. }
  279. completion([[RLMUser alloc] initWithUser:user app:_app], nil);
  280. });
  281. }
  282. - (void)removeWithCompletion:(RLMOptionalErrorBlock)completion {
  283. _app._realmApp->remove_user(_user, ^(std::optional<app::AppError> error) {
  284. [self handleResponse:error completion:completion];
  285. });
  286. }
  287. - (void)deleteWithCompletion:(RLMUserOptionalErrorBlock)completion {
  288. _app._realmApp->delete_user(_user, ^(std::optional<app::AppError> error) {
  289. [self handleResponse:error completion:completion];
  290. });
  291. }
  292. - (void)logOutWithCompletion:(RLMOptionalErrorBlock)completion {
  293. _app._realmApp->log_out(_user, ^(std::optional<app::AppError> error) {
  294. [self handleResponse:error completion:completion];
  295. });
  296. }
  297. - (RLMAPIKeyAuth *)apiKeysAuth {
  298. return [[RLMAPIKeyAuth alloc] initWithApp:_app];
  299. }
  300. - (RLMMongoClient *)mongoClientWithServiceName:(NSString *)serviceName {
  301. return [[RLMMongoClient alloc] initWithUser:self serviceName:serviceName];
  302. }
  303. - (void)callFunctionNamed:(NSString *)name
  304. arguments:(NSArray<id<RLMBSON>> *)arguments
  305. completionBlock:(RLMCallFunctionCompletionBlock)completionBlock {
  306. bson::BsonArray args;
  307. for (id<RLMBSON> argument in arguments) {
  308. args.push_back(RLMConvertRLMBSONToBson(argument));
  309. }
  310. _app._realmApp->call_function(_user, name.UTF8String, args,
  311. [completionBlock](std::optional<bson::Bson>&& response,
  312. std::optional<app::AppError> error) {
  313. if (error) {
  314. return completionBlock(nil, makeError(*error));
  315. }
  316. completionBlock(RLMConvertBsonToRLMBSON(*response), nil);
  317. });
  318. }
  319. - (void)handleResponse:(std::optional<realm::app::AppError>)error
  320. completion:(RLMOptionalErrorBlock)completion {
  321. if (error) {
  322. return completion(makeError(*error));
  323. }
  324. completion(nil);
  325. }
  326. #pragma mark - Private API
  327. + (void)_setUpBindingContextFactory {
  328. SyncUser::set_binding_context_factory([] {
  329. return std::make_shared<CocoaSyncUserContext>();
  330. });
  331. }
  332. - (NSString *)refreshToken {
  333. if (!_user || _user->refresh_token().empty()) {
  334. return nil;
  335. }
  336. return @(_user->refresh_token().c_str());
  337. }
  338. - (NSString *)accessToken {
  339. if (!_user || _user->access_token().empty()) {
  340. return nil;
  341. }
  342. return @(_user->access_token().c_str());
  343. }
  344. - (NSDictionary *)customData {
  345. if (!_user || !_user->custom_data()) {
  346. return @{};
  347. }
  348. return (NSDictionary *)RLMConvertBsonToRLMBSON(*_user->custom_data());
  349. }
  350. - (RLMUserProfile *)profile {
  351. if (!_user) {
  352. return [RLMUserProfile new];
  353. }
  354. return [[RLMUserProfile alloc] initWithUserProfile:_user->user_profile()];
  355. }
  356. - (std::shared_ptr<SyncUser>)_syncUser {
  357. return _user;
  358. }
  359. - (RLMUserSubscriptionToken *)subscribe:(RLMUserNotificationBlock)block {
  360. return [[RLMUserSubscriptionToken alloc] initWithUser:_user token:_user->subscribe([block, self] (auto&) {
  361. block(self);
  362. })];
  363. }
  364. @end
  365. #pragma mark - RLMUserIdentity
  366. @implementation RLMUserIdentity
  367. - (instancetype)initUserIdentityWithProviderType:(NSString *)providerType
  368. identifier:(NSString *)identifier {
  369. if (self = [super init]) {
  370. _providerType = providerType;
  371. _identifier = identifier;
  372. }
  373. return self;
  374. }
  375. @end
  376. #pragma mark - RLMUserProfile
  377. @interface RLMUserProfile () {
  378. SyncUserProfile _userProfile;
  379. }
  380. @end
  381. static NSString* userProfileMemberToNSString(const std::optional<std::string>& member) {
  382. if (member == util::none) {
  383. return nil;
  384. }
  385. return @(member->c_str());
  386. }
  387. @implementation RLMUserProfile
  388. using UserProfileMember = std::optional<std::string> (SyncUserProfile::*)() const;
  389. - (instancetype)initWithUserProfile:(SyncUserProfile)userProfile {
  390. if (self = [super init]) {
  391. _userProfile = std::move(userProfile);
  392. }
  393. return self;
  394. }
  395. - (NSString *)name {
  396. return userProfileMemberToNSString(_userProfile.name());
  397. }
  398. - (NSString *)email {
  399. return userProfileMemberToNSString(_userProfile.email());
  400. }
  401. - (NSString *)pictureURL {
  402. return userProfileMemberToNSString(_userProfile.picture_url());
  403. }
  404. - (NSString *)firstName {
  405. return userProfileMemberToNSString(_userProfile.first_name());
  406. }
  407. - (NSString *)lastName {
  408. return userProfileMemberToNSString(_userProfile.last_name());;
  409. }
  410. - (NSString *)gender {
  411. return userProfileMemberToNSString(_userProfile.gender());
  412. }
  413. - (NSString *)birthday {
  414. return userProfileMemberToNSString(_userProfile.birthday());
  415. }
  416. - (NSString *)minAge {
  417. return userProfileMemberToNSString(_userProfile.min_age());
  418. }
  419. - (NSString *)maxAge {
  420. return userProfileMemberToNSString(_userProfile.max_age());
  421. }
  422. - (NSDictionary *)metadata {
  423. return (NSDictionary *)RLMConvertBsonToRLMBSON(_userProfile.data());
  424. }
  425. @end