MDMSetup.m 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  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 "MDMSetup.h"
  21. #import "LicenseStore.h"
  22. #import "UserSettings.h"
  23. #import "MyIdentityStore.h"
  24. #import "ServerAPIConnector.h"
  25. #import "ValidationLogger.h"
  26. #import <ThreemaFramework/ThreemaFramework-Swift.h>
  27. #ifdef DEBUG
  28. static const DDLogLevel ddLogLevel = DDLogLevelAll;
  29. #else
  30. static const DDLogLevel ddLogLevel = DDLogLevelNotice;
  31. #endif
  32. NSString * const MDM_CONFIGURATION_KEY = @"com.apple.configuration.managed"; // Company MDM persists in user defaults
  33. NSString * const MDM_FEEDBACK_KEY = @"com.apple.feedback.managed";
  34. NSString * const MDM_THREEMA_CONFIGURATION_KEY = @"threema_mdm_configuration"; // Threema MDM persists in user defaults
  35. NSString * const MDM_KEY_LICENSE_USERNAME = @"th_license_username"; // String
  36. NSString * const MDM_KEY_LICENSE_PASSWORD = @"th_license_password"; // String
  37. NSString * const MDM_KEY_NICKNAME = @"th_nickname"; // String max 32
  38. NSString * const MDM_KEY_LINKED_EMAIL = @"th_linked_email"; // String
  39. NSString * const MDM_KEY_LINKED_PHONE = @"th_linked_phone"; // String
  40. NSString * const MDM_KEY_FIRST_NAME = @"th_firstname"; // String
  41. NSString * const MDM_KEY_LAST_NAME = @"th_lastname"; // String
  42. NSString * const MDM_KEY_CSI = @"th_csi"; // String
  43. NSString * const MDM_KEY_CATEGORY = @"th_category"; // String
  44. NSString * const MDM_KEY_CONTACT_SYNC = @"th_contact_sync"; // Bool
  45. NSString * const MDM_KEY_READONLY_PROFILE = @"th_readonly_profile"; // Bool
  46. NSString * const MDM_KEY_ID_BACKUP = @"th_id_backup"; // String
  47. NSString * const MDM_KEY_ID_BACKUP_PASSWORD = @"th_id_backup_password"; // String
  48. NSString * const MDM_KEY_BLOCK_UNKNOWN = @"th_block_unknown"; // Bool
  49. NSString * const MDM_KEY_HIDE_INACTIVE_IDS = @"th_hide_inactive_ids"; // Bool
  50. NSString * const MDM_KEY_DISABLE_SAVE_TO_GALLERY = @"th_disable_save_to_gallery"; // Bool
  51. NSString * const MDM_KEY_DISABLE_ADD_CONTACT = @"th_disable_add_contact"; // Bool
  52. NSString * const MDM_KEY_DISABLE_EXPORT = @"th_disable_export"; // Bool
  53. NSString * const MDM_KEY_DISABLE_BACKUPS = @"th_disable_backups"; // Bool
  54. NSString * const MDM_KEY_DISABLE_ID_EXPORT = @"th_disable_id_export"; // Bool
  55. NSString * const MDM_KEY_DISABLE_SYSTEM_BACKUPS = @"th_disable_system_backups"; // Bool
  56. NSString * const MDM_KEY_DISABLE_MESSAGE_PREVIEW = @"th_disable_message_preview"; // Bool
  57. NSString * const MDM_KEY_DISABLE_SEND_PROFILE_PICTURE = @"th_disable_send_profile_picture"; // Bool
  58. NSString * const MDM_KEY_DISABLE_CALLS = @"th_disable_calls"; // Bool
  59. NSString * const MDM_KEY_DISABLE_VIDEO_CALLS = @"th_disable_video_calls"; // String
  60. NSString * const MDM_KEY_DISABLE_CREATE_GROUP = @"th_disable_create_group"; // Bool
  61. NSString * const MDM_KEY_SKIP_WIZARD = @"th_skip_wizard"; // Bool
  62. NSString * const MDM_KEY_DISABLE_WEB = @"th_disable_web"; // Bool
  63. NSString * const MDM_KEY_WEB_HOSTS = @"th_web_hosts"; // String
  64. NSString * const MDM_KEY_DISABLE_SHARE_MEDIA = @"th_disable_share_media"; // Bool
  65. NSString * const MDM_KEY_SAFE_ENABLE = @"th_safe_enable"; // Bool
  66. NSString * const MDM_KEY_SAFE_PASSWORD = @"th_safe_password"; // String min. 8, max. 4096
  67. NSString * const MDM_KEY_SAFE_SERVER_URL = @"th_safe_server_url"; // String
  68. NSString * const MDM_KEY_SAFE_SERVER_USERNAME = @"th_safe_server_username"; // String
  69. NSString * const MDM_KEY_SAFE_SERVER_PASSWORD = @"th_safe_server_password"; // String
  70. NSString * const MDM_KEY_SAFE_RESTORE_ENABLE = @"th_safe_restore_enable"; // Bool
  71. NSString * const MDM_KEY_SAFE_RESTORE_ID = @"th_safe_restore_id"; // String 8
  72. NSString * const MDM_KEY_SAFE_PASSWORD_PATTERN = @"th_safe_password_pattern"; // String
  73. NSString * const MDM_KEY_SAFE_PASSWORD_MESSAGE = @"th_safe_password_message"; // String
  74. NSString * const MDM_KEY_THREEMA_CONFIGURATION = @"mdm";
  75. NSString * const MDM_KEY_THREEMA_OVERRIDE = @"override";
  76. NSString * const MDM_KEY_THREEMA_PARAMS = @"params";
  77. static NSDictionary *_mdmCache;
  78. static NSDictionary *_mdmCacheSetup;
  79. @implementation MDMSetup
  80. - (MDMSetup*)initWithSetup:(BOOL)setup {
  81. self = [super init];
  82. if (self) {
  83. isSetup = setup;
  84. isLicenseRequired = [[LicenseStore sharedLicenseStore] getRequiresLicenseKey] == YES;
  85. queue = dispatch_queue_create("ch.threema.MdmConfiguration", NULL);
  86. }
  87. return self;
  88. }
  89. + (void)clearMdmCache {
  90. _mdmCache = nil;
  91. _mdmCacheSetup = nil;
  92. }
  93. // MARK: MDM values
  94. - (BOOL)disableBackups {
  95. NSNumber *disableBackups = [self getMdmConfigurationBoolForKey:MDM_KEY_DISABLE_BACKUPS];
  96. return [disableBackups isKindOfClass:[NSNumber class]] ? disableBackups.boolValue : NO;
  97. }
  98. - (BOOL)disableIdExport {
  99. NSNumber *disableIdExport = [self getMdmConfigurationBoolForKey:MDM_KEY_DISABLE_ID_EXPORT];
  100. return [disableIdExport isKindOfClass:[NSNumber class]] ? disableIdExport.boolValue : NO;
  101. }
  102. - (BOOL)disableSystemBackups {
  103. NSNumber *disableSystemBackups = [self getMdmConfigurationBoolForKey:MDM_KEY_DISABLE_SYSTEM_BACKUPS];
  104. return [disableSystemBackups isKindOfClass:[NSNumber class]] ? disableSystemBackups.boolValue : NO;
  105. }
  106. - (BOOL)readonlyProfile {
  107. NSNumber *readonlyProfile = [self getMdmConfigurationBoolForKey:MDM_KEY_READONLY_PROFILE];
  108. return [readonlyProfile isKindOfClass:[NSNumber class]] ? readonlyProfile.boolValue : NO;
  109. }
  110. - (BOOL)disableAddContact {
  111. NSNumber *disableAddContact = [self getMdmConfigurationBoolForKey:MDM_KEY_DISABLE_ADD_CONTACT];
  112. return [disableAddContact isKindOfClass:[NSNumber class]] ? disableAddContact.boolValue : NO;
  113. }
  114. - (BOOL)disableSaveToGallery {
  115. NSNumber *disableSaveToGallery = [self getMdmConfigurationBoolForKey:MDM_KEY_DISABLE_SAVE_TO_GALLERY];
  116. return [disableSaveToGallery isKindOfClass:[NSNumber class]] ? disableSaveToGallery.boolValue : NO;
  117. }
  118. - (BOOL)disableExport {
  119. NSNumber *disableExport = [self getMdmConfigurationBoolForKey:MDM_KEY_DISABLE_EXPORT];
  120. return [disableExport isKindOfClass:[NSNumber class]] ? disableExport.boolValue : NO;
  121. }
  122. - (BOOL)disableMessagePreview {
  123. NSNumber *disableMessagePreview = [self getMdmConfigurationBoolForKey:MDM_KEY_DISABLE_MESSAGE_PREVIEW];
  124. return [disableMessagePreview isKindOfClass:[NSNumber class]] ? disableMessagePreview.boolValue : NO;
  125. }
  126. - (BOOL)disableCalls {
  127. NSNumber *disableCalls = [self getMdmConfigurationBoolForKey:MDM_KEY_DISABLE_CALLS];
  128. return [disableCalls isKindOfClass:[NSNumber class]] ? disableCalls.boolValue : NO;
  129. }
  130. - (BOOL)disableVideoCalls {
  131. NSNumber *disableVideoCalls = [self getMdmConfigurationBoolForKey:MDM_KEY_DISABLE_VIDEO_CALLS];
  132. return [disableVideoCalls isKindOfClass:[NSNumber class]] ? disableVideoCalls.boolValue : NO;
  133. }
  134. - (BOOL)disableWeb {
  135. NSNumber *disableWeb = [self getMdmConfigurationBoolForKey:MDM_KEY_DISABLE_WEB];
  136. return [disableWeb isKindOfClass:[NSNumber class]] ? disableWeb.boolValue : NO;
  137. }
  138. - (NSString *)webHosts {
  139. NSString *webHosts = [self getMdmConfigurationValueForKey:MDM_KEY_WEB_HOSTS];
  140. return [webHosts isKindOfClass:[NSString class]] ? webHosts : nil;
  141. }
  142. - (BOOL)disableCreateGroup {
  143. NSNumber *disableCreateGroup = [self getMdmConfigurationBoolForKey:MDM_KEY_DISABLE_CREATE_GROUP];
  144. return [disableCreateGroup isKindOfClass:[NSNumber class]] ? disableCreateGroup.boolValue : NO;
  145. }
  146. - (BOOL)disableSendProfilePicture {
  147. NSNumber *disableSendProfilePicture = [self getMdmConfigurationBoolForKey:MDM_KEY_DISABLE_SEND_PROFILE_PICTURE];
  148. return [disableSendProfilePicture isKindOfClass:[NSNumber class]] ? disableSendProfilePicture.boolValue : NO;
  149. }
  150. - (BOOL)skipWizard {
  151. NSNumber *skipWizard = [self getMdmConfigurationBoolForKey:MDM_KEY_SKIP_WIZARD];
  152. return [skipWizard isKindOfClass:[NSNumber class]] ? skipWizard.boolValue : NO;
  153. }
  154. - (BOOL)disableShareMedia {
  155. NSNumber *disableShareMedia = [self getMdmConfigurationBoolForKey:MDM_KEY_DISABLE_SHARE_MEDIA];
  156. return [disableShareMedia isKindOfClass:[NSNumber class]] ? disableShareMedia.boolValue : NO;
  157. }
  158. - (BOOL)disableHideStaleContacts {
  159. NSNumber *disableHideInactiveIds = [self getMdmConfigurationBoolForKey:MDM_KEY_HIDE_INACTIVE_IDS];
  160. return [disableHideInactiveIds isKindOfClass:[NSNumber class]] ? YES : NO;
  161. }
  162. - (NSNumber*)safeEnable {
  163. NSNumber *safeEnable = [self getMdmConfigurationValueForKey:MDM_KEY_SAFE_ENABLE];
  164. return [safeEnable isKindOfClass:[NSNumber class]] ? safeEnable : nil;
  165. }
  166. - (NSString*)safePassword {
  167. NSString *safePassword = [self getMdmConfigurationValueForKey:MDM_KEY_SAFE_PASSWORD];
  168. return [safePassword isKindOfClass:[NSString class]] ? safePassword : nil;
  169. }
  170. - (NSString*)safeServerUrl {
  171. NSString *safeServerUrl = [self getMdmConfigurationValueForKey:MDM_KEY_SAFE_SERVER_URL];
  172. return [safeServerUrl isKindOfClass:[NSString class]] ? safeServerUrl : nil;
  173. }
  174. - (NSString*)safeServerUsername {
  175. NSString *safeServerUsername = [self getMdmConfigurationValueForKey:MDM_KEY_SAFE_SERVER_USERNAME];
  176. return [safeServerUsername isKindOfClass:[NSString class]] ? safeServerUsername : nil;
  177. }
  178. - (NSString*)safeServerPassword {
  179. NSString *safeServerPassword = [self getMdmConfigurationValueForKey:MDM_KEY_SAFE_SERVER_PASSWORD];
  180. return [safeServerPassword isKindOfClass:[NSString class]] ? safeServerPassword : nil;
  181. }
  182. - (BOOL)safeRestoreEnable {
  183. NSNumber *safeRestoreEnable = [self getMdmConfigurationBoolForKey:MDM_KEY_SAFE_RESTORE_ENABLE];
  184. return [safeRestoreEnable isKindOfClass:[NSNumber class]] ? safeRestoreEnable.boolValue : YES;
  185. }
  186. - (NSString*)safeRestoreId {
  187. NSString *safeRestoreId = [self getMdmConfigurationValueForKey:MDM_KEY_SAFE_RESTORE_ID];
  188. return [safeRestoreId isKindOfClass:[NSString class]] ? safeRestoreId : nil;
  189. }
  190. - (NSString *)safePasswordPattern {
  191. NSString *safePasswordPattern = [self getMdmConfigurationValueForKey:MDM_KEY_SAFE_PASSWORD_PATTERN];
  192. return [safePasswordPattern isKindOfClass:[NSString class]] ? safePasswordPattern : nil;
  193. }
  194. - (NSString *)safePasswordMessage {
  195. NSString *safePasswordMessage = [self getMdmConfigurationValueForKey:MDM_KEY_SAFE_PASSWORD_MESSAGE];
  196. return [safePasswordMessage isKindOfClass:[NSString class]] ? safePasswordMessage : nil;
  197. }
  198. // MARK: Threema Safe status
  199. - (BOOL)isSafeBackupDisable {
  200. return [[self safeSetupWork] isSafeBackupStatusSetWithSafeState:SafeSetupWork.backupDisable];
  201. }
  202. - (BOOL)isSafeBackupForce {
  203. return [[self safeSetupWork] isSafeBackupStatusSetWithSafeState:SafeSetupWork.backupForce];
  204. }
  205. - (BOOL)isSafeBackupPasswordPreset {
  206. return [[self safeSetupWork] isSafeBackupStatusSetWithSafeState:SafeSetupWork.passwordPreset];
  207. }
  208. - (BOOL)isSafeBackupServerPreset {
  209. return [[self safeSetupWork] isSafeBackupStatusSetWithSafeState:SafeSetupWork.serverPreset];
  210. }
  211. - (BOOL)isSafeRestoreDisable {
  212. return [[self safeSetupWork] isSafeRestoreStatusSetWithSafeState:SafeSetupWork.restoreDisable];
  213. }
  214. - (BOOL)isSafeRestoreForce {
  215. return [[self safeSetupWork] isSafeRestoreStatusSetWithSafeState:SafeSetupWork.restoreForce];
  216. }
  217. - (BOOL)isSafeRestorePasswordPreset {
  218. return [[self safeSetupWork] isSafeRestoreStatusSetWithSafeState:SafeSetupWork.passwordPreset];
  219. }
  220. - (BOOL)isSafeRestoreServerPreset {
  221. return [[self safeSetupWork] isSafeRestoreStatusSetWithSafeState:SafeSetupWork.serverPreset];
  222. }
  223. - (SafeSetupWork*)safeSetupWork {
  224. return [[SafeSetupWork alloc] initWithMdmSetup:self];
  225. }
  226. // MARK: apply MDM to user settings, identity
  227. - (void)loadRenewableValues {
  228. if (![self isManaged]) {
  229. return;
  230. }
  231. [self loadLicenseInfo];
  232. UserSettings *userSettings = [UserSettings sharedUserSettings];
  233. NSNumber *blockUnknown = [self getMdmConfigurationBoolForKey:MDM_KEY_BLOCK_UNKNOWN];
  234. if ([blockUnknown isKindOfClass:[NSNumber class]]) {
  235. userSettings.blockUnknown = blockUnknown.boolValue;
  236. }
  237. NSNumber *hideInactiveIds = [self getMdmConfigurationBoolForKey:MDM_KEY_HIDE_INACTIVE_IDS];
  238. if ([hideInactiveIds isKindOfClass:[NSNumber class]]) {
  239. userSettings.hideStaleContacts = hideInactiveIds.boolValue;
  240. }
  241. NSNumber *contactSync = [self getMdmConfigurationBoolForKey:MDM_KEY_CONTACT_SYNC];
  242. if ([contactSync isKindOfClass:[NSNumber class]]) {
  243. userSettings.syncContacts = contactSync.boolValue;
  244. }
  245. if ([self existsMdmKey:MDM_KEY_DISABLE_SAVE_TO_GALLERY]) {
  246. userSettings.autoSaveMedia = ![self disableSaveToGallery];
  247. }
  248. if ([self existsMdmKey:MDM_KEY_DISABLE_MESSAGE_PREVIEW]) {
  249. userSettings.pushDecrypt = ![self disableMessagePreview];
  250. }
  251. if ([self existsMdmKey:MDM_KEY_DISABLE_CALLS]) {
  252. userSettings.enableThreemaCall = ![self disableCalls];
  253. }
  254. if ([self existsMdmKey:MDM_KEY_DISABLE_VIDEO_CALLS]) {
  255. userSettings.enableVideoCall= ![self disableVideoCalls];
  256. }
  257. if ([self existsMdmKey:MDM_KEY_DISABLE_SEND_PROFILE_PICTURE]) {
  258. if ([self disableSendProfilePicture]) {
  259. [userSettings setSendProfilePicture:SendProfilePictureNone];
  260. }
  261. }
  262. }
  263. - (void)loadLicenseInfo {
  264. if (![self isManaged]) {
  265. return;
  266. }
  267. NSString *licenseUsername = [self getMdmConfigurationValueForKey:MDM_KEY_LICENSE_USERNAME];
  268. if ([licenseUsername isKindOfClass:[NSString class]] && licenseUsername.length > 0) {
  269. [LicenseStore sharedLicenseStore].licenseUsername = licenseUsername;
  270. }
  271. NSString *licensePassword = [self getMdmConfigurationValueForKey:MDM_KEY_LICENSE_PASSWORD];
  272. if ([licensePassword isKindOfClass:[NSString class]] && licensePassword.length > 0) {
  273. [LicenseStore sharedLicenseStore].licensePassword = licensePassword;
  274. }
  275. }
  276. - (void)loadIDCreationValues {
  277. if (![self isManaged]) {
  278. return;
  279. }
  280. MyIdentityStore *identityStore = [MyIdentityStore sharedMyIdentityStore];
  281. NSString *nickname = [self getMdmConfigurationValueForKey:MDM_KEY_NICKNAME];
  282. if ([nickname isKindOfClass:[NSString class]] && nickname.length > 0 && nickname.length < 32) {
  283. identityStore.pushFromName = nickname;
  284. }
  285. NSNumber *contactSync = [self getMdmConfigurationBoolForKey:MDM_KEY_CONTACT_SYNC];
  286. if ([contactSync isKindOfClass:[NSNumber class]]) {
  287. [UserSettings sharedUserSettings].syncContacts = contactSync.boolValue;
  288. }
  289. NSString *email = [self getMdmConfigurationValueForKey:MDM_KEY_LINKED_EMAIL];
  290. if ([email isKindOfClass:[NSString class]] && email.length > 0) {
  291. identityStore.createIDEmail = email;
  292. }
  293. NSString *phone = [self getMdmConfigurationValueForKey:MDM_KEY_LINKED_PHONE];
  294. if ([phone isKindOfClass:[NSString class]] && phone.length > 0) {
  295. identityStore.createIDPhone = phone;
  296. }
  297. NSString *firstName = [self getMdmConfigurationValueForKey:MDM_KEY_FIRST_NAME];
  298. if ([firstName isKindOfClass:[NSString class]]) {
  299. identityStore.firstName = firstName;
  300. }
  301. NSString *lastName = [self getMdmConfigurationValueForKey:MDM_KEY_LAST_NAME];
  302. if ([lastName isKindOfClass:[NSString class]]) {
  303. identityStore.lastName = lastName;
  304. }
  305. NSString *csi = [self getMdmConfigurationValueForKey:MDM_KEY_CSI];
  306. if ([csi isKindOfClass:[NSString class]]) {
  307. identityStore.csi = csi;
  308. }
  309. NSString *category = [self getMdmConfigurationValueForKey:MDM_KEY_CATEGORY];
  310. if ([category isKindOfClass:[NSString class]]) {
  311. identityStore.category = category;
  312. }
  313. [[LicenseStore sharedLicenseStore] performUpdateWorkInfo];
  314. }
  315. - (BOOL)hasIDBackup {
  316. if (![self isManaged]) {
  317. return NO;
  318. }
  319. _idBackup = [self getMdmConfigurationValueForKey:MDM_KEY_ID_BACKUP];
  320. if ([_idBackup isKindOfClass:[NSString class]] == NO || _idBackup.length < 1) {
  321. return NO;
  322. }
  323. _idBackupPassword = [self getMdmConfigurationValueForKey:MDM_KEY_ID_BACKUP_PASSWORD];
  324. return YES;
  325. }
  326. - (void)restoreIDBackupOnCompletion:(void(^)(void))onCompletion onError:(void(^)(NSError *error))onError {
  327. if ([self hasIDBackup] == NO) {
  328. return;
  329. }
  330. MyIdentityStore *identityStore = [MyIdentityStore sharedMyIdentityStore];
  331. identityStore.pendingCreateID = YES;
  332. [identityStore restoreFromBackup:_idBackup withPassword:_idBackupPassword onCompletion:^{
  333. ServerAPIConnector *apiConnector = [[ServerAPIConnector alloc] init];
  334. /* Obtain server group from server */
  335. [apiConnector updateMyIdentityStore:identityStore onCompletion:^{
  336. [identityStore storeInKeychain];
  337. onCompletion();
  338. } onError:^(NSError *error) {
  339. onError(error);
  340. }];
  341. } onError:^(NSError *error) {
  342. onError(error);
  343. }];
  344. }
  345. - (BOOL)isManaged {
  346. NSDictionary *mdm = [self getMdmConfiguration];
  347. return isLicenseRequired && mdm != nil && [mdm count] > 0;
  348. }
  349. - (BOOL)existsMdmKey:(NSString*)mdmKey {
  350. NSDictionary *mdm = [self getMdmConfiguration];
  351. return [[mdm allKeys] containsObject:mdmKey];
  352. }
  353. /// Apply Threema MDM parameters (workData) to company MDM
  354. - (void)applyThreemaMdm:(NSDictionary *)workData {
  355. if (!isLicenseRequired) {
  356. return;
  357. }
  358. dispatch_sync(queue, ^{
  359. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  360. if (workData != nil && [[workData allKeys] containsObject:MDM_KEY_THREEMA_CONFIGURATION]) {
  361. NSDictionary *threemaMdm = [defaults dictionaryForKey:MDM_THREEMA_CONFIGURATION_KEY];
  362. NSDictionary *newThreemaMdm = workData[MDM_KEY_THREEMA_CONFIGURATION];
  363. NSMutableDictionary *currentThreemaMdm = [[NSMutableDictionary alloc] initWithDictionary:threemaMdm];
  364. if (currentThreemaMdm == nil || [currentThreemaMdm count] == 0) {
  365. // use new Threema MDM
  366. threemaMdm = newThreemaMdm;
  367. } else if([currentThreemaMdm isEqualToDictionary:newThreemaMdm] == NO) {
  368. // remove missing Threema MDM parameters
  369. NSMutableArray *missingMdmKeys = [[NSMutableArray alloc] init];
  370. NSMutableDictionary *currentThreemaMdmParameters = [[NSMutableDictionary alloc] initWithDictionary:currentThreemaMdm[MDM_KEY_THREEMA_PARAMS]];
  371. [currentThreemaMdmParameters enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
  372. if ([[newThreemaMdm[MDM_KEY_THREEMA_PARAMS] allKeys] containsObject:key] == NO) {
  373. [missingMdmKeys addObject:key];
  374. }
  375. }];
  376. [currentThreemaMdmParameters removeObjectsForKeys:missingMdmKeys];
  377. [currentThreemaMdm setObject:currentThreemaMdmParameters forKey:MDM_KEY_THREEMA_PARAMS];
  378. // apply new Threema MDM parameters
  379. BOOL override = ((NSNumber *)newThreemaMdm[MDM_KEY_THREEMA_OVERRIDE]).boolValue;
  380. NSDictionary *newThreemaMdmParameters = [self applyMdmParameters:currentThreemaMdm[MDM_KEY_THREEMA_PARAMS] source:newThreemaMdm[MDM_KEY_THREEMA_PARAMS] override:override];
  381. NSMutableDictionary *newThreemaMdmConfiguration = [[NSMutableDictionary alloc] initWithDictionary:threemaMdm];
  382. [newThreemaMdmConfiguration setObject:newThreemaMdmParameters forKey:MDM_KEY_THREEMA_PARAMS];
  383. [newThreemaMdmConfiguration setObject:[NSNumber numberWithBool:override] forKey:MDM_KEY_THREEMA_OVERRIDE];
  384. threemaMdm = newThreemaMdmConfiguration;
  385. }
  386. // store Threema MDM
  387. [defaults setObject:threemaMdm forKey:MDM_THREEMA_CONFIGURATION_KEY];
  388. [defaults synchronize];
  389. } else {
  390. [defaults removeObjectForKey:MDM_THREEMA_CONFIGURATION_KEY];
  391. [defaults synchronize];
  392. }
  393. [MDMSetup clearMdmCache];
  394. });
  395. [self loadIDCreationValues];
  396. [self loadRenewableValues];
  397. }
  398. - (NSDictionary*)getMdmCompany {
  399. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  400. return [defaults dictionaryForKey:MDM_CONFIGURATION_KEY];
  401. /// fake company MDM parameters here
  402. // NSDictionary *companyMdm = [[NSDictionary alloc] initWithObjectsAndKeys:@1, MDM_KEY_READONLY_PROFILE, @"123456", MDM_KEY_LICENSE_PASSWORD, @"po", MDM_KEY_LICENSE_USERNAME, @"test@test.ch", MDM_KEY_LINKED_EMAIL, @"+41791112233", MDM_KEY_LINKED_PHONE, @"id_pass", MDM_KEY_ID_BACKUP_PASSWORD, @"safe_pass", MDM_KEY_SAFE_PASSWORD, @"server_pass", MDM_KEY_SAFE_SERVER_PASSWORD, @0, MDM_KEY_DISABLE_VIDEO_CALLS, nil];
  403. // return companyMdm;
  404. }
  405. - (NSDictionary*)getMdmConfiguration {
  406. __block NSDictionary *mdm;
  407. dispatch_sync(queue, ^{
  408. if (isLicenseRequired) {
  409. if (!isSetup) {
  410. if (_mdmCache == nil) {
  411. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  412. _mdmCache = [self getMdmParameters:[self getMdmCompany] threemMdm:[defaults dictionaryForKey:MDM_THREEMA_CONFIGURATION_KEY]];
  413. }
  414. mdm = _mdmCache;
  415. } else {
  416. if (_mdmCacheSetup == nil) {
  417. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  418. _mdmCacheSetup = [self getMdmParameters:[self getMdmCompany] threemMdm:[defaults dictionaryForKey:MDM_THREEMA_CONFIGURATION_KEY]];
  419. }
  420. mdm = _mdmCacheSetup;
  421. }
  422. } else {
  423. mdm = [[NSDictionary alloc] init];
  424. }
  425. });
  426. return mdm;
  427. }
  428. - (NSDictionary*)getMdmParameters:(NSDictionary*)companyMdm threemMdm:(NSDictionary*)threemaMdm {
  429. if (companyMdm != nil) {
  430. if (threemaMdm != nil) {
  431. // merge company and Threema MDM
  432. BOOL override = ((NSNumber *)threemaMdm[MDM_KEY_THREEMA_OVERRIDE]).boolValue;
  433. NSDictionary *newMdm = [self applyMdmParameters:companyMdm source:threemaMdm[MDM_KEY_THREEMA_PARAMS] override:override];
  434. DDLogNotice(@"\nCompany MDM");
  435. [self printMDMIntoDebugLog:companyMdm];
  436. DDLogNotice(@"\nThreema MDM");
  437. [self printMDMIntoDebugLog:threemaMdm];
  438. DDLogNotice(@"\nMerged Company and Threema MDM");
  439. [self printMDMIntoDebugLog:newMdm];
  440. return newMdm;
  441. } else {
  442. // use Company MDM
  443. DDLogNotice(@"\nCompany MDM");
  444. [self printMDMIntoDebugLog:companyMdm];
  445. return companyMdm;
  446. }
  447. } else if (threemaMdm != nil && [[threemaMdm allKeys] containsObject:MDM_KEY_THREEMA_PARAMS]) {
  448. // use Threema MDM
  449. NSDictionary *destinationMdm = [[NSDictionary alloc] init];
  450. BOOL override = ((NSNumber *)threemaMdm[MDM_KEY_THREEMA_OVERRIDE]).boolValue;
  451. NSDictionary *newMdm = [self applyMdmParameters:destinationMdm source:threemaMdm[MDM_KEY_THREEMA_PARAMS] override:override];
  452. DDLogNotice(@"\nThreema MDM");
  453. [self printMDMIntoDebugLog:newMdm];
  454. return newMdm;
  455. }
  456. // print empty mdm
  457. DDLogNotice(@"\nCompany and Threema MDM is empty");
  458. return [[NSDictionary alloc] init];
  459. }
  460. - (NSDictionary*)applyMdmParameters:(NSDictionary*)destination source:(NSDictionary*)source override:(BOOL)override {
  461. NSMutableDictionary *mdmParameters = [[NSMutableDictionary alloc] initWithDictionary:destination];
  462. // apply parameter if is override and renweable or missing
  463. [[source allKeys] enumerateObjectsUsingBlock:^(NSString *key, NSUInteger idx, BOOL * _Nonnull stop) {
  464. if (override == YES && [self isRenewable:key]) {
  465. if ([[mdmParameters allKeys] containsObject:key]) {
  466. [mdmParameters setValue:source[key] forKey:key];
  467. } else {
  468. [mdmParameters addEntriesFromDictionary:@{key: source[key]}];
  469. }
  470. }
  471. if (isSetup == YES && [[mdmParameters allKeys] containsObject:key] == NO) {
  472. [mdmParameters addEntriesFromDictionary:@{key: source[key]}];
  473. }
  474. else if (isSetup == YES && override == YES && [[mdmParameters allKeys] containsObject:key] == YES) {
  475. [mdmParameters setValue:source[key] forKey:key];
  476. }
  477. }];
  478. return mdmParameters;
  479. }
  480. - (void)deleteThreemaMdm {
  481. dispatch_sync(queue, ^{
  482. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  483. [defaults removeObjectForKey:MDM_THREEMA_CONFIGURATION_KEY];
  484. [defaults synchronize];
  485. [MDMSetup clearMdmCache];
  486. });
  487. }
  488. - (BOOL)isRenewable:(NSString *)mdmKey {
  489. NSArray *renewableKeys = @[MDM_KEY_LICENSE_USERNAME, MDM_KEY_LICENSE_PASSWORD, MDM_KEY_NICKNAME, MDM_KEY_FIRST_NAME, MDM_KEY_LAST_NAME, MDM_KEY_CSI, MDM_KEY_CATEGORY, MDM_KEY_READONLY_PROFILE, MDM_KEY_BLOCK_UNKNOWN, MDM_KEY_HIDE_INACTIVE_IDS, MDM_KEY_DISABLE_SAVE_TO_GALLERY, MDM_KEY_DISABLE_ADD_CONTACT, MDM_KEY_DISABLE_EXPORT, MDM_KEY_DISABLE_BACKUPS, MDM_KEY_DISABLE_ID_EXPORT, MDM_KEY_DISABLE_SYSTEM_BACKUPS, MDM_KEY_DISABLE_MESSAGE_PREVIEW, MDM_KEY_DISABLE_SEND_PROFILE_PICTURE, MDM_KEY_DISABLE_CALLS, MDM_KEY_DISABLE_CREATE_GROUP, MDM_KEY_DISABLE_WEB, MDM_KEY_WEB_HOSTS, MDM_KEY_SAFE_ENABLE, MDM_KEY_SAFE_PASSWORD, MDM_KEY_SAFE_SERVER_URL, MDM_KEY_SAFE_SERVER_USERNAME, MDM_KEY_SAFE_SERVER_PASSWORD, MDM_KEY_SAFE_PASSWORD_PATTERN, MDM_KEY_SAFE_PASSWORD_MESSAGE, MDM_KEY_DISABLE_SHARE_MEDIA, MDM_KEY_CONTACT_SYNC, MDM_KEY_DISABLE_VIDEO_CALLS];
  490. return [renewableKeys containsObject:mdmKey];
  491. }
  492. - (NSNumber*)getMdmConfigurationBoolForKey:(NSString*)key {
  493. // Some MDMs cannot send real booleans, so we support "true"/"1" and "false"/"0" as strings also
  494. id mdmVal = [self getMdmConfigurationValueForKey:key];
  495. if ([mdmVal isKindOfClass:[NSNumber class]]) {
  496. return mdmVal;
  497. } else if ([mdmVal isKindOfClass:[NSString class]]) {
  498. if ([mdmVal caseInsensitiveCompare:@"true"] == NSOrderedSame || [mdmVal isEqualToString:@"1"]) {
  499. return [NSNumber numberWithBool:YES];
  500. } else if ([mdmVal caseInsensitiveCompare:@"false"] == NSOrderedSame || [mdmVal isEqualToString:@"0"]) {
  501. return [NSNumber numberWithBool:NO];
  502. }
  503. }
  504. return nil;
  505. }
  506. - (id)getMdmConfigurationValueForKey:(NSString*)key {
  507. NSDictionary *mdm = [self getMdmConfiguration];
  508. return mdm[key];
  509. }
  510. - (void)printMDMIntoDebugLog:(NSDictionary *)mdm {
  511. if ([[mdm allKeys] containsObject:MDM_KEY_THREEMA_PARAMS]) {
  512. BOOL override = ((NSNumber *)mdm[MDM_KEY_THREEMA_OVERRIDE]).boolValue;
  513. DDLogNotice(@"%@: %@", MDM_KEY_THREEMA_OVERRIDE, override ? @"true" : @"false");
  514. for(NSString *key in mdm[MDM_KEY_THREEMA_PARAMS]) {
  515. [self checkIsPasswordAndLog:key value:[mdm[MDM_KEY_THREEMA_PARAMS] objectForKey:key]];
  516. }
  517. } else {
  518. for(NSString *key in mdm) {
  519. [self checkIsPasswordAndLog:key value:[mdm objectForKey:key]];
  520. }
  521. }
  522. }
  523. - (void)checkIsPasswordAndLog:(NSString *)key value:(NSString *)value {
  524. if (![key containsString:@"pass"] || [key isEqualToString:MDM_KEY_SAFE_PASSWORD_PATTERN] || [key isEqualToString:MDM_KEY_SAFE_PASSWORD_MESSAGE] || value == nil) {
  525. DDLogNotice(@"%@: %@", key, value);
  526. } else {
  527. DDLogNotice(@"%@: ***", key);
  528. }
  529. }
  530. @end