WorkDataFetcher.m 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2016-2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. #import "WorkDataFetcher.h"
  21. #import "AppGroup.h"
  22. #import "ServerAPIRequest.h"
  23. #import "MyIdentityStore.h"
  24. #import "LicenseStore.h"
  25. #import "ContactStore.h"
  26. #import "Contact.h"
  27. #import "EntityManager.h"
  28. #import "MDMSetup.h"
  29. #import "UserSettings.h"
  30. #ifdef DEBUG
  31. static const DDLogLevel ddLogLevel = DDLogLevelVerbose;
  32. #else
  33. static const DDLogLevel ddLogLevel = DDLogLevelWarning;
  34. #endif
  35. #define WORK_DEFAULT_CHECK_INTERVAL 86400
  36. @implementation WorkDataFetcher
  37. + (void)checkUpdateWorkDataForce:(BOOL)force onCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError*))onError {
  38. if (![LicenseStore requiresLicenseKey]) {
  39. if (onCompletion != nil)
  40. onCompletion();
  41. return;
  42. }
  43. NSUserDefaults *defaults = [AppGroup userDefaults];
  44. NSDate *lastWorkSync = [defaults objectForKey:@"WorkDataLastSync"];
  45. NSInteger checkInterval = [defaults integerForKey:@"WorkDataCheckInterval"];
  46. if (checkInterval == 0)
  47. checkInterval = WORK_DEFAULT_CHECK_INTERVAL;
  48. /* check if we are within the minimum interval */
  49. if (!force) {
  50. if (lastWorkSync != nil && -[lastWorkSync timeIntervalSinceNow] < checkInterval) {
  51. DDLogInfo(@"Still within work check interval - not syncing");
  52. return;
  53. }
  54. }
  55. if ([LicenseStore sharedLicenseStore].licenseUsername == nil) {
  56. if (onCompletion != nil)
  57. onCompletion();
  58. return;
  59. }
  60. // Send Work fetch request with license username/password and list of identities in local contact list
  61. NSArray *contactIds = [[ContactStore sharedContactStore] allIdentities];
  62. NSDictionary *request = @{
  63. @"username": [LicenseStore sharedLicenseStore].licenseUsername,
  64. @"password": [LicenseStore sharedLicenseStore].licensePassword,
  65. @"contacts": contactIds
  66. };
  67. [ServerAPIRequest postJSONToWorkAPIPath:@"fetch2" data:request onCompletion:^(id jsonObject) {
  68. NSDictionary *workData = (NSDictionary*)jsonObject;
  69. DDLogVerbose(@"Work data: %@", workData);
  70. MDMSetup *mdmSetup = [[MDMSetup alloc] initWithSetup:NO];
  71. [mdmSetup applyThreemaMdm:workData];
  72. /* Extract logo URL, if supplied */
  73. if (workData[@"logo"] != nil && [workData isKindOfClass:[NSDictionary class]]) {
  74. NSDictionary *logo = workData[@"logo"];
  75. NSString *oldLogoLightUrl = [MyIdentityStore sharedMyIdentityStore].licenseLogoLightUrl;
  76. NSString *oldLogoDarkUrl = [MyIdentityStore sharedMyIdentityStore].licenseLogoDarkUrl;
  77. if (logo[@"light"] == [NSNull null])
  78. [MyIdentityStore sharedMyIdentityStore].licenseLogoLightUrl = nil;
  79. else
  80. [MyIdentityStore sharedMyIdentityStore].licenseLogoLightUrl = logo[@"light"];
  81. if (logo[@"dark"] == [NSNull null])
  82. [MyIdentityStore sharedMyIdentityStore].licenseLogoDarkUrl = nil;
  83. else
  84. [MyIdentityStore sharedMyIdentityStore].licenseLogoDarkUrl = logo[@"dark"];
  85. if (oldLogoLightUrl != [MyIdentityStore sharedMyIdentityStore].licenseLogoLightUrl ||
  86. oldLogoDarkUrl != [MyIdentityStore sharedMyIdentityStore].licenseLogoDarkUrl) {
  87. [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationColorThemeChanged object:nil];
  88. }
  89. }
  90. /* Extract support URL, if supplied */
  91. if (workData[@"support"] == [NSNull null])
  92. [MyIdentityStore sharedMyIdentityStore].licenseSupportUrl = nil;
  93. else
  94. [MyIdentityStore sharedMyIdentityStore].licenseSupportUrl = workData[@"support"];
  95. /* Process supplied contacts */
  96. NSArray *workContacts = workData[@"contacts"];
  97. NSMutableSet *workContactIds = [NSMutableSet set];
  98. if (workContacts != nil) {
  99. for (NSDictionary *workContact in workContacts) {
  100. Contact *contact = [[ContactStore sharedContactStore] addContactWithIdentity:workContact[@"id"] publicKey:[[NSData alloc] initWithBase64EncodedString:workContact[@"pk"] options:0] cnContactId:nil verificationLevel:kVerificationLevelUnverified state:nil type:@1 featureMask:nil alerts:NO];
  101. if ((contact.firstName == nil && contact.lastName == nil) || contact.cnContactId == nil) {
  102. if (workContact[@"first"] != nil && workContact[@"first"] != [NSNull null] && workContact[@"last"] != nil && workContact[@"last"] != [NSNull null]) {
  103. NSString *first = workContact[@"first"];
  104. NSString *last = workContact[@"last"];
  105. if (first.length > 0 || last.length > 0) {
  106. EntityManager *entityManager = [[EntityManager alloc] init];
  107. [entityManager performSyncBlockAndSafe:^{
  108. contact.firstName = first;
  109. contact.lastName = last;
  110. }];
  111. }
  112. }
  113. }
  114. [workContactIds addObject:workContact[@"id"]];
  115. }
  116. }
  117. [[ContactStore sharedContactStore] updateFeatureMasksForIdentities:[workContactIds allObjects] onCompletion:^{
  118. } onError:^(NSError *error) {
  119. }];
  120. /* Get all work verified contacts from DB and set those that have not been supplied in this sync back to non-work */
  121. NSArray *allContacts = [[ContactStore sharedContactStore] allContacts];
  122. for (Contact *contact in allContacts) {
  123. BOOL isWorkContact = [workContactIds containsObject:contact.identity];
  124. if (contact.workContact == nil || contact.workContact.boolValue != isWorkContact) {
  125. [[ContactStore sharedContactStore] setWorkContact:contact workContact:isWorkContact];
  126. }
  127. }
  128. /* Extract check interval, if supplied */
  129. NSInteger checkInterval = WORK_DEFAULT_CHECK_INTERVAL;
  130. if ([workData[@"checkInterval"] isKindOfClass:[NSNumber class]]) {
  131. NSInteger serverCheckInterval = [((NSNumber*)workData[@"checkInterval"]) integerValue];
  132. DDLogVerbose(@"Server supplied check interval is %ld", (long)serverCheckInterval);
  133. if (serverCheckInterval > 0)
  134. checkInterval = serverCheckInterval;
  135. }
  136. BOOL refreshWorkContactTableView = false;
  137. /* Check if there is a company directory */
  138. if (workData[@"directory"] != [NSNull null]) {
  139. if (workData[@"directory"] != nil) {
  140. NSDictionary *directory = workData[@"directory"];
  141. BOOL enableWorkDirectory = [directory[@"enabled"] boolValue];
  142. if (enableWorkDirectory != [UserSettings sharedUserSettings].companyDirectory) {
  143. [UserSettings sharedUserSettings].companyDirectory = [directory[@"enabled"] boolValue];
  144. refreshWorkContactTableView = true;
  145. }
  146. [MyIdentityStore sharedMyIdentityStore].directoryCategories = directory[@"cat"];
  147. } else {
  148. [UserSettings sharedUserSettings].companyDirectory = false;
  149. }
  150. } else {
  151. [UserSettings sharedUserSettings].companyDirectory = false;
  152. }
  153. if (workData[@"org"] != [NSNull null]) {
  154. NSDictionary *org = workData[@"org"];
  155. if (org[@"name"] != [NSNull null]) {
  156. NSString *name = org[@"name"];
  157. if (![name isEqualToString:[MyIdentityStore sharedMyIdentityStore].companyName]) {
  158. [MyIdentityStore sharedMyIdentityStore].companyName = name;
  159. refreshWorkContactTableView = true;
  160. }
  161. }
  162. }
  163. if (refreshWorkContactTableView == true) {
  164. [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationRefreshWorkContactTableView object:nil];
  165. }
  166. [defaults setObject:[NSDate date] forKey:@"WorkDataLastSync"];
  167. [defaults setInteger:checkInterval forKey:@"WorkDataCheckInterval"];
  168. [defaults synchronize];
  169. if (onCompletion != nil)
  170. onCompletion();
  171. } onError:^(NSError *error) {
  172. DDLogError(@"Work API fetch failed: %@", error);
  173. if (onError != nil)
  174. onError(error);
  175. }];
  176. }
  177. + (void)checkUpdateThreemaMDM:(void(^)(void))onCompletion onError:(void(^)(NSError*))onError {
  178. NSString *username = [LicenseStore sharedLicenseStore].licenseUsername;
  179. NSString *password = [LicenseStore sharedLicenseStore].licensePassword;
  180. if (username != nil && password != nil) {
  181. NSDictionary *request = @{
  182. @"username": username,
  183. @"password": password,
  184. @"contacts": @[],
  185. };
  186. [ServerAPIRequest postJSONToWorkAPIPath:@"fetch2" data:request onCompletion:^(id jsonObject) {
  187. NSDictionary *workData = (NSDictionary*)jsonObject;
  188. MDMSetup *mdmSetup = [[MDMSetup alloc] initWithSetup:YES];
  189. [mdmSetup applyThreemaMdm:workData];
  190. onCompletion();
  191. } onError:^(NSError *error) {
  192. DDLogError(@"Work API fetch failed: %@", error);
  193. onError(error);
  194. }];
  195. } else {
  196. onError(nil);
  197. }
  198. }
  199. @end