AppDelegate.m 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. //
  2. // AppDelegate.m
  3. // Nextcloud
  4. //
  5. // Created by Marino Faggiana on 04/09/14.
  6. // Copyright (c) 2014 Marino Faggiana. All rights reserved.
  7. //
  8. // Author Marino Faggiana <marino.faggiana@nextcloud.com>
  9. //
  10. // This program is free software: you can redistribute it and/or modify
  11. // it under the terms of the GNU General Public License as published by
  12. // the Free Software Foundation, either version 3 of the License, or
  13. // (at your option) any later version.
  14. //
  15. // This program is distributed in the hope that it will be useful,
  16. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. // GNU General Public License for more details.
  19. //
  20. // You should have received a copy of the GNU General Public License
  21. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. //
  23. #import "AppDelegate.h"
  24. #import "NCBridgeSwift.h"
  25. #import "NSNotificationCenter+MainThread.h"
  26. #import "NCPushNotification.h"
  27. #import <QuartzCore/QuartzCore.h>
  28. @import Firebase;
  29. @class NCViewerRichdocument;
  30. @interface AppDelegate() <TOPasscodeViewControllerDelegate>
  31. @end
  32. @implementation AppDelegate
  33. + (void)initialize
  34. {
  35. [[NSUserDefaults standardUserDefaults] registerDefaults:@{@"UserAgent": [CCUtility getUserAgent]}];
  36. }
  37. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  38. {
  39. BOOL isSimulatorOrTestFlight = [[NCUtility shared] isSimulatorOrTestFlight];
  40. if (![CCUtility getDisableCrashservice] && NCBrandOptions.shared.disable_crash_service == false) {
  41. [FIRApp configure];
  42. }
  43. [CCUtility createDirectoryStandard];
  44. [CCUtility emptyTemporaryDirectory];
  45. // Networking
  46. [[NCCommunicationCommon shared] setupWithDelegate:[NCNetworking shared]];
  47. [[NCCommunicationCommon shared] setupWithUserAgent:[CCUtility getUserAgent]];
  48. NSInteger logLevel = [CCUtility getLogLevel];
  49. [[NCCommunicationCommon shared] setFileLogWithLevel:logLevel];
  50. NSString *versionApp = [NSString stringWithFormat:@"%@.%@", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"], [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]];
  51. NSString *versionNextcloudiOS = [NSString stringWithFormat:[NCBrandOptions shared].textCopyrightNextcloudiOS, versionApp];
  52. if (isSimulatorOrTestFlight) {
  53. [[NCCommunicationCommon shared] writeLog:[NSString stringWithFormat:@"Start session with level %lu %@ (Simulator / TestFlight)", (unsigned long)logLevel, versionNextcloudiOS]];
  54. } else {
  55. [[NCCommunicationCommon shared] writeLog:[NSString stringWithFormat:@"Start session with level %lu %@", (unsigned long)logLevel, versionNextcloudiOS]];
  56. }
  57. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(initializeMain:) name:NCBrandGlobal.shared.notificationCenterInitializeMain object:nil];
  58. // Set account, if no exists clear all
  59. tableAccount *tableAccount = [[NCManageDatabase shared] getAccountActive];
  60. if (tableAccount == nil) {
  61. // remove all the keys Chain
  62. [CCUtility deleteAllChainStore];
  63. // remove all the App group key
  64. [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]];
  65. } else {
  66. // FIX 3.0.5 lost urlbase
  67. if (tableAccount.urlBase.length == 0) {
  68. NSString *user = [tableAccount.user stringByAppendingString:@" "];
  69. NSString *urlBase = [tableAccount.account stringByReplacingOccurrencesOfString:user withString:@""];
  70. tableAccount.urlBase = urlBase;
  71. [[NCManageDatabase shared] updateAccount:tableAccount];
  72. tableAccount = [[NCManageDatabase shared] getAccountActive];
  73. }
  74. [self settingAccount:tableAccount.account urlBase:tableAccount.urlBase user:tableAccount.user userID:tableAccount.userID password:[CCUtility getPassword:tableAccount.account]];
  75. }
  76. // UserDefaults
  77. self.ncUserDefaults = [[NSUserDefaults alloc] initWithSuiteName:[NCBrandOptions shared].capabilitiesGroups];
  78. // Background Fetch
  79. [application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
  80. self.listProgressMetadata = [NSMutableDictionary new];
  81. self.listFilesVC = [NSMutableDictionary new];
  82. self.listFavoriteVC = [NSMutableDictionary new];
  83. self.listOfflineVC = [NSMutableDictionary new];
  84. self.pasteboardOcIds = [NSMutableArray new];
  85. // Push Notification
  86. [application registerForRemoteNotifications];
  87. // Display notification
  88. [UNUserNotificationCenter currentNotificationCenter].delegate = self;
  89. UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
  90. [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) { }];
  91. //AV Session
  92. [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:nil];
  93. [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
  94. // Start Timer
  95. [self startTimerErrorNetworking];
  96. // Store review
  97. if ([[NCUtility shared] isSimulatorOrTestFlight] == false) {
  98. NCStoreReview *review = [NCStoreReview new];
  99. [review incrementAppRuns];
  100. [review showStoreReview];
  101. }
  102. // Detect Dark mode
  103. if (@available(iOS 13.0, *)) {
  104. if ([CCUtility getDarkModeDetect]) {
  105. if ([[UITraitCollection currentTraitCollection] userInterfaceStyle] == UIUserInterfaceStyleDark) {
  106. [CCUtility setDarkMode:YES];
  107. } else {
  108. [CCUtility setDarkMode:NO];
  109. }
  110. }
  111. }
  112. if ([NCBrandOptions shared].disable_intro) {
  113. [CCUtility setIntro:YES];
  114. if (self.account == nil || self.account.length == 0) {
  115. [self openLoginView:nil selector:NCBrandGlobal.shared.introLogin openLoginWeb:false];
  116. }
  117. } else {
  118. if ([CCUtility getIntro] == NO) {
  119. UIViewController *introViewController = [[UIStoryboard storyboardWithName:@"NCIntro" bundle:[NSBundle mainBundle]] instantiateInitialViewController];
  120. UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController: introViewController];
  121. self.window.rootViewController = navController;
  122. [self.window makeKeyAndVisible];
  123. }
  124. }
  125. // init home
  126. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCBrandGlobal.shared.notificationCenterInitializeMain object:nil userInfo:nil];
  127. // Passcode
  128. dispatch_async(dispatch_get_main_queue(), ^{
  129. [self passcodeWithAutomaticallyPromptForBiometricValidation:true];
  130. });
  131. // Auto upload
  132. self.networkingAutoUpload = [NCNetworkingAutoUpload new];
  133. // Background task
  134. if (@available(iOS 13.0, *)) {
  135. [[BGTaskScheduler sharedScheduler] registerForTaskWithIdentifier:NCBrandGlobal.shared.backgroudTask usingQueue:nil launchHandler:^(BGTask *task) {
  136. [self handleBackgroundTask:task];
  137. }];
  138. }
  139. return YES;
  140. }
  141. //
  142. // L' applicazione si dimetterà dallo stato di attivo
  143. //
  144. - (void)applicationWillResignActive:(UIApplication *)application
  145. {
  146. if (self.account == nil || self.account.length == 0) { return; }
  147. // Dismiss FileViewInFolder
  148. if (self.activeFileViewInFolder != nil ) {
  149. [self.activeFileViewInFolder dismissViewControllerAnimated:false completion:^{
  150. self.activeFileViewInFolder = nil;
  151. }];
  152. }
  153. }
  154. //
  155. // L' applicazione entrerà in primo piano (attivo solo dopo il background)
  156. //
  157. - (void)applicationWillEnterForeground:(UIApplication *)application
  158. {
  159. if (self.account == nil || self.account.length == 0) { return; }
  160. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCBrandGlobal.shared.notificationCenterApplicationWillEnterForeground object:nil];
  161. // Request Passcode
  162. [self passcodeWithAutomaticallyPromptForBiometricValidation:true];
  163. // Initialize Auto upload
  164. [[NCAutoUpload shared] initAutoUploadWithViewController:nil];
  165. // Read active directory
  166. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCBrandGlobal.shared.notificationCenterReloadDataSourceNetworkForced object:nil];
  167. // Required unsubscribing / subscribing
  168. [[NCPushNotification shared] pushNotification];
  169. // RichDocument
  170. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCBrandGlobal.shared.notificationCenterRichdocumentGrabFocus object:nil];
  171. // Request Service Server Nextcloud
  172. [[NCService shared] startRequestServicesServer];
  173. }
  174. //
  175. // L' applicazione entrerà in primo piano (attivo sempre)
  176. //
  177. - (void)applicationDidBecomeActive:(UIApplication *)application
  178. {
  179. if (self.account == nil || self.account.length == 0) { return; }
  180. // Brand
  181. #if defined(HC)
  182. tableAccount *account = [[NCManageDatabase shared] getAccountActive];
  183. if (account.hcIsTrial == true || account.hcTrialExpired == true || account.hcNextGroupExpirationGroupExpired == true) {
  184. HCTrial *vc = [[UIStoryboard storyboardWithName:@"HCTrial" bundle:nil] instantiateInitialViewController];
  185. vc.account = account;
  186. [self.window.rootViewController presentViewController:vc animated:YES completion:nil];
  187. }
  188. #endif
  189. [[NCNetworking shared] verifyUploadZombie];
  190. }
  191. //
  192. // L' applicazione è entrata nello sfondo
  193. //
  194. - (void)applicationDidEnterBackground:(UIApplication *)application
  195. {
  196. if (self.account == nil || self.account.length == 0) { return; }
  197. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCBrandGlobal.shared.notificationCenterApplicationDidEnterBackground object:nil];
  198. [self passcodeWithAutomaticallyPromptForBiometricValidation:false];
  199. if (@available(iOS 13.0, *)) {
  200. [self scheduleBackgroundTask];
  201. }
  202. }
  203. //
  204. // L'applicazione terminerà
  205. //
  206. - (void)applicationWillTerminate:(UIApplication *)application
  207. {
  208. [[NCCommunicationCommon shared] writeLog:@"bye bye"];
  209. }
  210. // NotificationCenter
  211. - (void)initializeMain:(NSNotification *)notification
  212. {
  213. if (self.account == nil || self.account.length == 0) { return; }
  214. // Clear error certificate
  215. [CCUtility setCertificateError:self.account error:NO];
  216. // Setting Theming
  217. [[NCBrandColor shared] settingThemingColorWithAccount:self.account];
  218. // close detail
  219. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCBrandGlobal.shared.notificationCenterMenuDetailClose object:nil];
  220. // Start Auto Upload
  221. [[NCAutoUpload shared] initAutoUploadWithViewController:nil];
  222. // Start services
  223. [[NCService shared] startRequestServicesServer];
  224. // Registeration push notification
  225. [[NCPushNotification shared] pushNotification];
  226. // Registeration domain File Provider
  227. //FileProviderDomain *fileProviderDomain = [FileProviderDomain new];
  228. //[fileProviderDomain removeAllDomains];
  229. //[fileProviderDomain registerDomains];
  230. [[NCCommunicationCommon shared] writeLog:@"initialize Main"];
  231. }
  232. #pragma mark Login / checkErrorNetworking
  233. - (void)checkErrorNetworking
  234. {
  235. if (self.account == nil || self.account.length == 0) { return; }
  236. // check unauthorized server (401)
  237. if ([CCUtility getPassword:self.account].length == 0) {
  238. [self openLoginView:self.window.rootViewController selector:NCBrandGlobal.shared.introLogin openLoginWeb:true];
  239. }
  240. // check certificate untrusted (-1202)
  241. if ([CCUtility getCertificateError:self.account]) {
  242. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"_ssl_certificate_untrusted_", nil) message:NSLocalizedString(@"_connect_server_anyway_", nil) preferredStyle:UIAlertControllerStyleAlert];
  243. [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_yes_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
  244. [[NCNetworking shared] wrtiteCertificateWithDirectoryCertificate:[CCUtility getDirectoryCerificates]];
  245. [self startTimerErrorNetworking];
  246. }]];
  247. [alertController addAction: [UIAlertAction actionWithTitle:NSLocalizedString(@"_no_", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
  248. [self startTimerErrorNetworking];
  249. }]];
  250. [self.window.rootViewController presentViewController:alertController animated:YES completion:^{
  251. // Stop timer error network
  252. [self.timerErrorNetworking invalidate];
  253. }];
  254. }
  255. }
  256. - (void)openLoginView:(UIViewController *)viewController selector:(NSInteger)selector openLoginWeb:(BOOL)openLoginWeb
  257. {
  258. // use appConfig [MDM]
  259. if ([NCBrandOptions shared].use_configuration) {
  260. if (!(_appConfigView.isViewLoaded && _appConfigView.view.window)) {
  261. self.appConfigView = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"NCAppConfigView"];
  262. [self showLoginViewController:self.appConfigView forContext:viewController];
  263. }
  264. return;
  265. }
  266. // only for personalized LoginWeb [customer]
  267. if ([NCBrandOptions shared].use_login_web_personalized) {
  268. if (!(_activeLoginWeb.isViewLoaded && _activeLoginWeb.view.window)) {
  269. self.activeLoginWeb = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"NCLoginWeb"];
  270. self.activeLoginWeb.urlBase = [[NCBrandOptions shared] loginBaseUrl];
  271. [self showLoginViewController:self.activeLoginWeb forContext:viewController];
  272. }
  273. return;
  274. }
  275. // normal login
  276. if (selector == NCBrandGlobal.shared.introSignup) {
  277. if (!(_activeLoginWeb.isViewLoaded && _activeLoginWeb.view.window)) {
  278. self.activeLoginWeb = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"NCLoginWeb"];
  279. if (selector == NCBrandGlobal.shared.introSignup) {
  280. self.activeLoginWeb.urlBase = [[NCBrandOptions shared] linkloginPreferredProviders];
  281. } else {
  282. self.activeLoginWeb.urlBase = self.urlBase;
  283. }
  284. [self showLoginViewController:self.activeLoginWeb forContext:viewController];
  285. }
  286. } else if ([NCBrandOptions shared].disable_intro && [NCBrandOptions shared].disable_request_login_url) {
  287. self.activeLoginWeb = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"NCLoginWeb"];
  288. self.activeLoginWeb.urlBase = [[NCBrandOptions shared] loginBaseUrl];
  289. [self showLoginViewController:self.activeLoginWeb forContext:viewController];
  290. } else if (openLoginWeb) {
  291. if (!(_activeLoginWeb.isViewLoaded && _activeLoginWeb.view.window)) {
  292. self.activeLoginWeb = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"NCLoginWeb"];
  293. self.activeLoginWeb.urlBase = self.urlBase;
  294. [self showLoginViewController:self.activeLoginWeb forContext:viewController];
  295. }
  296. } else {
  297. if (!(_activeLogin.isViewLoaded && _activeLogin.view.window)) {
  298. _activeLogin = [[UIStoryboard storyboardWithName:@"CCLogin" bundle:nil] instantiateViewControllerWithIdentifier:@"CCLoginNextcloud"];
  299. [self showLoginViewController:_activeLogin forContext:viewController];
  300. }
  301. }
  302. }
  303. -(void)showLoginViewController:(UIViewController *)viewController forContext:(UIViewController *)contextViewController
  304. {
  305. if (contextViewController == NULL) {
  306. UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
  307. navigationController.navigationBar.barStyle = UIBarStyleBlack;
  308. navigationController.navigationBar.tintColor = NCBrandColor.shared.customerText;
  309. navigationController.navigationBar.barTintColor = NCBrandColor.shared.customer;
  310. [navigationController.navigationBar setTranslucent:false];
  311. self.window.rootViewController = navigationController;
  312. [self.window makeKeyAndVisible];
  313. } else if ([contextViewController isKindOfClass:[UINavigationController class]]) {
  314. UINavigationController *navigationController = ((UINavigationController *)contextViewController);
  315. [navigationController pushViewController:viewController animated:true];
  316. } else {
  317. UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
  318. navigationController.modalPresentationStyle = UIModalPresentationFullScreen;
  319. navigationController.navigationBar.barStyle = UIBarStyleBlack;
  320. navigationController.navigationBar.tintColor = NCBrandColor.shared.customerText;
  321. navigationController.navigationBar.barTintColor = NCBrandColor.shared.customer;
  322. [navigationController.navigationBar setTranslucent:false];
  323. [contextViewController presentViewController:navigationController animated:true completion:nil];
  324. }
  325. }
  326. - (void)startTimerErrorNetworking
  327. {
  328. self.timerErrorNetworking = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(checkErrorNetworking) userInfo:nil repeats:YES];
  329. }
  330. #pragma mark Account & Communication
  331. - (void)settingAccount:(NSString *)account urlBase:(NSString *)urlBase user:(NSString *)user userID:(NSString *)userID password:(NSString *)password
  332. {
  333. self.account = account;
  334. self.urlBase = urlBase;
  335. self.user = user;
  336. self.userID = userID;
  337. self.password = password;
  338. (void)[NCNetworkingNotificationCenter shared];
  339. [[NCCommunicationCommon shared] setupWithAccount:account user:user userId:userID password:password urlBase:urlBase];
  340. NSInteger serverVersionMajor = [[NCManageDatabase shared] getCapabilitiesServerIntWithAccount:account elements:NCElementsJSON.shared.capabilitiesVersionMajor];
  341. if (serverVersionMajor > 0) {
  342. [[NCCommunicationCommon shared] setupWithNextcloudVersion:serverVersionMajor];
  343. }
  344. [[NCCommunicationCommon shared] setupWithWebDav:[[NCUtilityFileSystem shared] getWebDAVWithAccount:account]];
  345. [[NCCommunicationCommon shared] setupWithDav:[[NCUtilityFileSystem shared] getDAV]];
  346. }
  347. - (void)deleteAccount:(NSString *)account wipe:(BOOL)wipe
  348. {
  349. // Push Notification
  350. tableAccount *accountPN = [[NCManageDatabase shared] getAccountWithPredicate:[NSPredicate predicateWithFormat:@"account == %@", account]];
  351. [[NCPushNotification shared] unsubscribingNextcloudServerPushNotification:accountPN.account urlBase:accountPN.urlBase user:accountPN.user withSubscribing:false];
  352. [self settingAccount:nil urlBase:nil user:nil userID:nil password:nil];
  353. /* DELETE ALL FILES LOCAL FS */
  354. NSArray *results = [[NCManageDatabase shared] getTableLocalFilesWithPredicate:[NSPredicate predicateWithFormat:@"account == %@", account] sorted:@"ocId" ascending:NO];
  355. for (tableLocalFile *result in results) {
  356. [CCUtility removeFileAtPath:[CCUtility getDirectoryProviderStorageOcId:result.ocId]];
  357. }
  358. // Clear database
  359. [[NCManageDatabase shared] clearDatabaseWithAccount:account removeAccount:true];
  360. [CCUtility clearAllKeysEndToEnd:account];
  361. [CCUtility clearAllKeysPushNotification:account];
  362. [CCUtility setCertificateError:account error:false];
  363. [CCUtility setPassword:account password:nil];
  364. if (wipe) {
  365. NSArray *listAccount = [[NCManageDatabase shared] getAccounts];
  366. if ([listAccount count] > 0) {
  367. NSString *newAccount = listAccount[0];
  368. tableAccount *tableAccount = [[NCManageDatabase shared] setAccountActive:newAccount];
  369. [self settingAccount:newAccount urlBase:tableAccount.urlBase user:tableAccount.user userID:tableAccount.userID password:[CCUtility getPassword:tableAccount.account]];
  370. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCBrandGlobal.shared.notificationCenterInitializeMain object:nil userInfo:nil];
  371. } else {
  372. [self openLoginView:self.window.rootViewController selector:NCBrandGlobal.shared.introLogin openLoginWeb:false];
  373. }
  374. }
  375. }
  376. #pragma mark Push Notifications
  377. -(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
  378. {
  379. completionHandler(UNNotificationPresentationOptionAlert);
  380. }
  381. -(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(nonnull UNNotificationResponse *)response withCompletionHandler:(nonnull void (^)(void))completionHandler
  382. {
  383. completionHandler();
  384. }
  385. - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
  386. {
  387. [[NCPushNotification shared] registerForRemoteNotificationsWithDeviceToken:deviceToken];
  388. }
  389. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
  390. {
  391. [[NCPushNotification shared] applicationdidReceiveRemoteNotification:userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result) {
  392. completionHandler(result);
  393. }];
  394. }
  395. #pragma mark Background Task
  396. -(void)scheduleBackgroundTask
  397. {
  398. if (@available(iOS 13.0, *)) {
  399. NSError *error = NULL;
  400. // cancel existing task (if any)
  401. [BGTaskScheduler.sharedScheduler cancelTaskRequestWithIdentifier:NCBrandGlobal.shared.backgroudTask];
  402. // new task
  403. BGProcessingTaskRequest *request = [[BGProcessingTaskRequest alloc] initWithIdentifier:NCBrandGlobal.shared.backgroudTask];
  404. request.requiresNetworkConnectivity = YES;
  405. request.requiresExternalPower = NO;
  406. request.earliestBeginDate = [NSDate dateWithTimeIntervalSinceNow:5];
  407. BOOL success = [[BGTaskScheduler sharedScheduler] submitTaskRequest:request error:&error];
  408. if (!success) {
  409. /*
  410. Here are possible error codes for Domain=BGTaskSchedulerErrorDomain extracted from ObjC headers with some explanation.
  411. BGTaskSchedulerErrorCodeUnavailable = 1 // Background task scheduling functionality is not available for this app/extension. Background App Refresh may have been disabled in Settings.
  412. BGTaskSchedulerErrorCodeTooManyPendingTaskRequests = 2 // The task request could not be submitted because there are too many pending task requests of this type. Cancel some existing task requests before trying again.
  413. BGTaskSchedulerErrorCodeNotPermitted = 3 // The task request could not be submitted because the appropriate background mode is not included in the UIBackgroundModes array, or its identifier was not present in the BGTaskSchedulerPermittedIdentifiers array in the app's Info.plist.
  414. */
  415. [[NCCommunicationCommon shared] writeLog:[NSString stringWithFormat:@"Background task failed to submit request: %@", error]];
  416. } else {
  417. [[NCCommunicationCommon shared] writeLog:[NSString stringWithFormat:@"Background task success submit request %@", request]];
  418. }
  419. }
  420. }
  421. -(void)handleBackgroundTask:(BGTask *)task API_AVAILABLE(ios(13.0))
  422. {
  423. if (self.account == nil || self.account.length == 0) {
  424. return;
  425. }
  426. //do things with task
  427. [[NCCommunicationCommon shared] writeLog:@"Start handler background task"];
  428. // Verify new photo
  429. [[NCAutoUpload shared] initAutoUploadWithViewController:nil];
  430. // after 20 sec
  431. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 20 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
  432. [[NCCommunicationCommon shared] writeLog:@"End 20 sec. handler background task"];
  433. });
  434. }
  435. #pragma mark Fetch
  436. - (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
  437. {
  438. if (self.account == nil || self.account.length == 0) {
  439. completionHandler(UIBackgroundFetchResultNoData);
  440. return;
  441. }
  442. [[NCCommunicationCommon shared] writeLog:@"Start perform Fetch"];
  443. // Verify new photo
  444. [[NCAutoUpload shared] initAutoUploadWithViewController:nil];
  445. // after 20 sec
  446. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 20 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
  447. [[NCCommunicationCommon shared] writeLog:@"End 20 sec. perform Fetch"];
  448. completionHandler(UIBackgroundFetchResultNoData);
  449. });
  450. }
  451. #pragma mark Operation Networking & Session
  452. //
  453. // Method called by the system when all the background task has end
  454. //
  455. - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler
  456. {
  457. [[NCCommunicationCommon shared] writeLog:[NSString stringWithFormat:@"Start handle Events For Background URLSession: %@", identifier]];
  458. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 20 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
  459. self.backgroundSessionCompletionHandler = completionHandler;
  460. void (^completionHandler)() = self.backgroundSessionCompletionHandler;
  461. self.backgroundSessionCompletionHandler = nil;
  462. completionHandler();
  463. });
  464. }
  465. #pragma mark OpenURL
  466. - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options
  467. {
  468. if (self.account == nil || self.account.length == 0) { return YES; }
  469. NSString *scheme = url.scheme;
  470. NSString *fileName;
  471. NSString *serverUrl;
  472. if ([scheme isEqualToString:@"nextcloud"]) {
  473. NSString *action = url.host;
  474. if ([action isEqualToString:@"open-file"]) {
  475. NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
  476. NSArray *queryItems = urlComponents.queryItems;
  477. NSString *user = [CCUtility valueForKey:@"user" fromQueryItems:queryItems];
  478. NSString *path = [CCUtility valueForKey:@"path" fromQueryItems:queryItems];
  479. NSString *link = [CCUtility valueForKey:@"link" fromQueryItems:queryItems];
  480. tableAccount *matchedAccount = nil;
  481. // verify parameter
  482. if (user.length == 0 || path.length == 0 || [[NSURL URLWithString:link] host].length == 0) {
  483. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"_error_", nil) message:NSLocalizedString(@"_error_parameter_schema_", nil) preferredStyle:UIAlertControllerStyleAlert];
  484. UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"_ok_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {}];
  485. [alertController addAction:okAction];
  486. [self.window.rootViewController presentViewController:alertController animated:YES completion:nil];
  487. } else {
  488. tableAccount *account = [[NCManageDatabase shared] getAccountActive];
  489. if (account) {
  490. NSURL *accountURL = [NSURL URLWithString:account.urlBase];
  491. NSString *accountUser = account.user;
  492. if ([link containsString:accountURL.host] && [user isEqualToString:accountUser]) {
  493. matchedAccount = account;
  494. } else {
  495. NSArray *accounts = [[NCManageDatabase shared] getAllAccount];
  496. for (tableAccount *account in accounts) {
  497. NSURL *accountURL = [NSURL URLWithString:account.urlBase];
  498. NSString *accountUser = account.user;
  499. if ([link containsString:accountURL.host] && [user isEqualToString:accountUser]) {
  500. matchedAccount = [[NCManageDatabase shared] setAccountActive:account.account];
  501. [self settingAccount:matchedAccount.account urlBase:matchedAccount.urlBase user:matchedAccount.user userID:matchedAccount.userID password:[CCUtility getPassword:matchedAccount.account]];
  502. [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCBrandGlobal.shared.notificationCenterInitializeMain object:nil userInfo:nil];
  503. }
  504. }
  505. }
  506. if (matchedAccount) {
  507. NSString *webDAV = [[NCUtilityFileSystem shared] getWebDAVWithAccount:self.account];
  508. if ([path containsString:@"/"]) {
  509. fileName = [path lastPathComponent];
  510. serverUrl = [NSString stringWithFormat:@"%@/%@/%@", matchedAccount.urlBase, webDAV, [path stringByDeletingLastPathComponent]];
  511. } else {
  512. fileName = path;
  513. serverUrl = [NSString stringWithFormat:@"%@/%@", matchedAccount.urlBase, webDAV];
  514. }
  515. [[NCCollectionCommon shared] openFileViewInFolderWithServerUrl:serverUrl fileName:fileName];
  516. } else {
  517. NSString *domain = [[NSURL URLWithString:link] host];
  518. NSString *fileName = [path lastPathComponent];
  519. NSString *message = [NSString stringWithFormat:NSLocalizedString(@"_account_not_available_", nil), user, domain, fileName];
  520. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"_info_", nil) message:message preferredStyle:UIAlertControllerStyleAlert];
  521. UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"_ok_", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {}];
  522. [alertController addAction:okAction];
  523. [self.window.rootViewController presentViewController:alertController animated:YES completion:nil];
  524. }
  525. }
  526. }
  527. }
  528. return YES;
  529. }
  530. return YES;
  531. }
  532. #pragma mark Passcode + Delegate
  533. - (void)passcodeWithAutomaticallyPromptForBiometricValidation:(BOOL)automaticallyPromptForBiometricValidation
  534. {
  535. LAContext *laContext = [LAContext new];
  536. NSError *error;
  537. BOOL isBiometryAvailable = false;
  538. if ([[CCUtility getPasscode] length] == 0 || [self.account length] == 0 || [CCUtility getNotPasscodeAtStart]) return;
  539. if (self.passcodeViewController == nil) {
  540. self.passcodeViewController = [[TOPasscodeViewController alloc] initWithStyle:TOPasscodeViewStyleTranslucentLight passcodeType:TOPasscodeTypeSixDigits];
  541. if (@available(iOS 13.0, *)) {
  542. if ([[UITraitCollection currentTraitCollection] userInterfaceStyle] == UIUserInterfaceStyleDark) {
  543. self.passcodeViewController.style = TOPasscodeViewStyleTranslucentDark;
  544. }
  545. }
  546. self.passcodeViewController.delegate = self;
  547. self.passcodeViewController.keypadButtonShowLettering = false;
  548. if (CCUtility.getEnableTouchFaceID && [laContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
  549. if (error == NULL) {
  550. if (laContext.biometryType == LABiometryTypeFaceID) {
  551. self.passcodeViewController.biometryType = TOPasscodeBiometryTypeFaceID;
  552. self.passcodeViewController.allowBiometricValidation = true;
  553. isBiometryAvailable = true;
  554. } else if (laContext.biometryType == LABiometryTypeTouchID) {
  555. self.passcodeViewController.biometryType = TOPasscodeBiometryTypeTouchID;
  556. self.passcodeViewController.allowBiometricValidation = true;
  557. isBiometryAvailable = true;
  558. } else {
  559. isBiometryAvailable = false;
  560. NSLog(@"No Biometric support");
  561. }
  562. }
  563. }
  564. [self.window.rootViewController presentViewController:self.passcodeViewController animated:YES completion:^{
  565. [self enableTouchFaceID:automaticallyPromptForBiometricValidation];
  566. }];
  567. } else {
  568. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
  569. [self enableTouchFaceID:automaticallyPromptForBiometricValidation];
  570. });
  571. }
  572. }
  573. - (void)didInputCorrectPasscodeInPasscodeViewController:(TOPasscodeViewController *)passcodeViewController
  574. {
  575. [passcodeViewController dismissViewControllerAnimated:YES completion:^{
  576. self.passcodeViewController = nil;
  577. }];
  578. }
  579. - (BOOL)passcodeViewController:(TOPasscodeViewController *)passcodeViewController isCorrectCode:(NSString *)code
  580. {
  581. return [code isEqualToString:[CCUtility getPasscode]];
  582. }
  583. - (void)didPerformBiometricValidationRequestInPasscodeViewController:(TOPasscodeViewController *)passcodeViewController
  584. {
  585. [[LAContext new] evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:[[NCBrandOptions shared] brand] reply:^(BOOL success, NSError * _Nullable error) {
  586. if (success) {
  587. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
  588. [passcodeViewController dismissViewControllerAnimated:YES completion:^{
  589. self.passcodeViewController = nil;
  590. }];
  591. });
  592. }
  593. }];
  594. }
  595. - (void)enableTouchFaceID:(BOOL)automaticallyPromptForBiometricValidation
  596. {
  597. if (CCUtility.getEnableTouchFaceID && automaticallyPromptForBiometricValidation && self.passcodeViewController.view.window) {
  598. [[LAContext new] evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:[[NCBrandOptions shared] brand] reply:^(BOOL success, NSError * _Nullable error) {
  599. if (success) {
  600. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^(void) {
  601. [self.passcodeViewController dismissViewControllerAnimated:YES completion:^{
  602. self.passcodeViewController = nil;
  603. }];
  604. });
  605. }
  606. }];
  607. }
  608. }
  609. @end