Browse Source

clear code [move out the push notification]

marinofaggiana 4 years ago
parent
commit
48b27fea23

+ 22 - 8
Nextcloud.xcodeproj/project.pbxproj

@@ -55,6 +55,7 @@
 		F710D20024057E5E00A6033D /* NCActionSheetHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F710D1FD24057E5E00A6033D /* NCActionSheetHeaderView.xib */; };
 		F710D2022405826100A6033D /* NCViewer+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F710D2012405826100A6033D /* NCViewer+Menu.swift */; };
 		F710E8111EF95C9C00DC2427 /* ImagesIntro.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F710E80F1EF95C9C00DC2427 /* ImagesIntro.xcassets */; };
+		F7134186259747BA00768D21 /* NCPushNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = F7134185259747BA00768D21 /* NCPushNotification.m */; };
 		F713FF002472764100214AF6 /* UIImage+animatedGIF.m in Sources */ = {isa = PBXBuildFile; fileRef = F713FEFF2472764100214AF6 /* UIImage+animatedGIF.m */; };
 		F71459C21D12E3B700CAFEEC /* ShareViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F7C0F46F1C8880540059EC54 /* ShareViewController.m */; };
 		F71459D21D12E3B700CAFEEC /* CCUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = F7053E3D1C639DF500741EA5 /* CCUtility.m */; };
@@ -405,6 +406,8 @@
 		F710D1FD24057E5E00A6033D /* NCActionSheetHeaderView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCActionSheetHeaderView.xib; sourceTree = "<group>"; };
 		F710D2012405826100A6033D /* NCViewer+Menu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCViewer+Menu.swift"; sourceTree = "<group>"; };
 		F710E80F1EF95C9C00DC2427 /* ImagesIntro.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = ImagesIntro.xcassets; sourceTree = "<group>"; };
+		F7134184259747BA00768D21 /* NCPushNotification.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NCPushNotification.h; sourceTree = "<group>"; };
+		F7134185259747BA00768D21 /* NCPushNotification.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NCPushNotification.m; sourceTree = "<group>"; };
 		F713FEFE2472764000214AF6 /* UIImage+animatedGIF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+animatedGIF.h"; sourceTree = "<group>"; };
 		F713FEFF2472764100214AF6 /* UIImage+animatedGIF.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+animatedGIF.m"; sourceTree = "<group>"; };
 		F7151A811D477A4B00E6AF45 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -876,6 +879,15 @@
 			path = Intro;
 			sourceTree = "<group>";
 		};
+		F713418B2597513800768D21 /* PushNotification */ = {
+			isa = PBXGroup;
+			children = (
+				F7134184259747BA00768D21 /* NCPushNotification.h */,
+				F7134185259747BA00768D21 /* NCPushNotification.m */,
+			);
+			path = PushNotification;
+			sourceTree = "<group>";
+		};
 		F7169A161EE590930086BD69 /* Shares */ = {
 			isa = PBXGroup;
 			children = (
@@ -1476,6 +1488,7 @@
 				F74D3DB81BAC1941000BAE4B /* Networking */,
 				F7381ED9218218A4000B1560 /* Offline */,
 				F7FCFFD51D70798C000E6E29 /* PeekPop */,
+				F713418B2597513800768D21 /* PushNotification */,
 				F765F72E25237E3F00391DBE /* Recent */,
 				F7CADB3D23CCDDA1000EEC78 /* RichWorkspace */,
 				F758B41E212C516300515F55 /* ScanDocument */,
@@ -2132,6 +2145,7 @@
 				F7DFB7F4219C5CA800680748 /* NCCreateFormUploadScanDocument.swift in Sources */,
 				F710D1FF24057E5E00A6033D /* NCActionSheetHeaderView.swift in Sources */,
 				F7020FCE2233D7F700B7297D /* NCCreateFormUploadVoiceNote.swift in Sources */,
+				F7134186259747BA00768D21 /* NCPushNotification.m in Sources */,
 				F7F4B1D823C74B3E00D82A6E /* NCRichWorkspace.swift in Sources */,
 				F726EEEC1FED1C820030B9C8 /* NCEndToEndInitialize.swift in Sources */,
 				F79A65C62191D95E00FF6DCC /* NCSelect.swift in Sources */,
@@ -2261,7 +2275,7 @@
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 11;
+				CURRENT_PROJECT_VERSION = 12;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEVELOPMENT_TEAM = 6JLRKY9ZV7;
 				FRAMEWORK_SEARCH_PATHS = (
@@ -2316,7 +2330,7 @@
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 11;
+				CURRENT_PROJECT_VERSION = 12;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEVELOPMENT_TEAM = 6JLRKY9ZV7;
 				FRAMEWORK_SEARCH_PATHS = (
@@ -2363,7 +2377,7 @@
 				CODE_SIGN_ENTITLEMENTS = iOSClient/Brand/Share.entitlements;
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				CURRENT_PROJECT_VERSION = 11;
+				CURRENT_PROJECT_VERSION = 12;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEVELOPMENT_TEAM = 6JLRKY9ZV7;
 				FRAMEWORK_SEARCH_PATHS = (
@@ -2411,7 +2425,7 @@
 				CODE_SIGN_ENTITLEMENTS = iOSClient/Brand/Share.entitlements;
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				CURRENT_PROJECT_VERSION = 11;
+				CURRENT_PROJECT_VERSION = 12;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEVELOPMENT_TEAM = 6JLRKY9ZV7;
 				FRAMEWORK_SEARCH_PATHS = (
@@ -2465,7 +2479,7 @@
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 11;
+				CURRENT_PROJECT_VERSION = 12;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEVELOPMENT_TEAM = 6JLRKY9ZV7;
 				FRAMEWORK_SEARCH_PATHS = (
@@ -2519,7 +2533,7 @@
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 11;
+				CURRENT_PROJECT_VERSION = 12;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				DEVELOPMENT_TEAM = 6JLRKY9ZV7;
 				FRAMEWORK_SEARCH_PATHS = (
@@ -2565,7 +2579,7 @@
 				CODE_SIGN_ENTITLEMENTS = iOSClient/Brand/iOSClient.entitlements;
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
-				CURRENT_PROJECT_VERSION = 11;
+				CURRENT_PROJECT_VERSION = 12;
 				DEVELOPMENT_TEAM = 6JLRKY9ZV7;
 				ENABLE_BITCODE = YES;
 				FRAMEWORK_SEARCH_PATHS = (
@@ -2614,7 +2628,7 @@
 				CODE_SIGN_IDENTITY = "iPhone Developer";
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 11;
+				CURRENT_PROJECT_VERSION = 12;
 				DEVELOPMENT_TEAM = 6JLRKY9ZV7;
 				ENABLE_BITCODE = YES;
 				FRAMEWORK_SEARCH_PATHS = (

+ 0 - 6
iOSClient/AppDelegate.h

@@ -72,9 +72,6 @@
 // Passcode lockDirectory
 @property (nonatomic, strong) NSDate *sessionePasscodeLock;
 
-// Push Norification Token
-@property (nonatomic, strong) NSString *pushKitToken;
-
 @property (nonatomic, retain) TOPasscodeViewController *passcodeViewController;
 
 @property (nonatomic, retain) NSString *activeServerUrl;
@@ -122,8 +119,5 @@
 - (void)deleteAccount:(NSString *)account wipe:(BOOL)wipe;
 - (void)settingSetupCommunication:(NSString *)account;
 
-// Push Notification
-- (void)pushNotification;
-
 @end
 

+ 14 - 183
iOSClient/AppDelegate.m

@@ -24,8 +24,8 @@
 #import "AppDelegate.h"
 #import "NCBridgeSwift.h"
 #import "NCAutoUpload.h"
-#import "NCPushNotificationEncryption.h"
 #import "NSNotificationCenter+MainThread.h"
+#import "NCPushNotification.h"
 #import <QuartzCore/QuartzCore.h>
 
 @import Firebase;
@@ -199,7 +199,7 @@
     [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCBrandGlobal.shared.notificationCenterReloadDataSourceNetworkForced object:nil];
     
     // Required unsubscribing / subscribing
-    [self pushNotification];
+    [[NCPushNotification shared] pushNotification];
     
     // RichDocument
     [[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:NCBrandGlobal.shared.notificationCenterRichdocumentGrabFocus object:nil];
@@ -277,7 +277,7 @@
     [[NCService shared] startRequestServicesServer];
     
     // Registeration push notification
-    [self pushNotification];
+    [[NCPushNotification shared] pushNotification];
     
     // Registeration domain File Provider
     //FileProviderDomain *fileProviderDomain = [FileProviderDomain new];
@@ -287,9 +287,7 @@
     [[NCCommunicationCommon shared] writeLog:@"initialize Main"];
 }
 
-#pragma --------------------------------------------------------------------------------------------
-#pragma mark ===== Login / checkErrorNetworking =====
-#pragma --------------------------------------------------------------------------------------------
+#pragma mark Login / checkErrorNetworking
 
 - (void)checkErrorNetworking
 {
@@ -428,9 +426,7 @@
     self.timerErrorNetworking = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(checkErrorNetworking) userInfo:nil repeats:YES];
 }
 
-#pragma --------------------------------------------------------------------------------------------
-#pragma mark ===== Account & Communication =====
-#pragma --------------------------------------------------------------------------------------------
+#pragma mark Account & Communication
 
 - (void)settingAccount:(NSString *)account urlBase:(NSString *)urlBase user:(NSString *)user userID:(NSString *)userID password:(NSString *)password
 {
@@ -450,7 +446,7 @@
 {
     // Push Notification
     tableAccount *accountPN = [[NCManageDatabase shared] getAccountWithPredicate:[NSPredicate predicateWithFormat:@"account == %@", account]];
-    [self unsubscribingNextcloudServerPushNotification:accountPN.account urlBase:accountPN.urlBase user:accountPN.user withSubscribing:false];
+    [[NCPushNotification shared] unsubscribingNextcloudServerPushNotification:accountPN.account urlBase:accountPN.urlBase user:accountPN.user withSubscribing:false];
 
     [self settingAccount:nil urlBase:nil user:nil userID:nil password:nil];
     
@@ -491,94 +487,10 @@
     [[NCCommunicationCommon shared] setupWithDav:[[NCUtilityFileSystem shared] getDAV]];
 }
 
-#pragma --------------------------------------------------------------------------------------------
-#pragma mark ===== Push Notifications =====
-#pragma --------------------------------------------------------------------------------------------
-
-- (void)pushNotification
-{
-    if (self.account.length == 0 || self.pushKitToken.length == 0) { return; }
-    
-    for (tableAccount *result in [[NCManageDatabase shared] getAllAccount]) {
-        
-        NSString *token = [CCUtility getPushNotificationToken:result.account];
-        
-        if (![token isEqualToString:self.pushKitToken]) {
-            if (token != nil) {
-                // unsubscribing + subscribing
-                [self unsubscribingNextcloudServerPushNotification:result.account urlBase:result.urlBase user:result.user withSubscribing:true];
-            } else {
-                [self subscribingNextcloudServerPushNotification:result.account urlBase:result.urlBase user:result.user];
-            }
-        }
-    }
-}
-
-- (void)subscribingNextcloudServerPushNotification:(NSString *)account urlBase:(NSString *)urlBase user:(NSString *)user
-{
-    if (self.account.length == 0 || self.pushKitToken.length == 0) { return; }
-    
-    [[NCPushNotificationEncryption shared] generatePushNotificationsKeyPair:account];
-
-    NSString *pushTokenHash = [[NCEndToEndEncryption sharedManager] createSHA512:self.pushKitToken];
-    NSData *pushPublicKey = [CCUtility getPushNotificationPublicKey:account];
-    NSString *pushDevicePublicKey = [[NSString alloc] initWithData:pushPublicKey encoding:NSUTF8StringEncoding];
-    NSString *proxyServerPath = [NCBrandOptions shared].pushNotificationServerProxy;
-    
-    [[NCCommunication shared] subscribingPushNotificationWithServerUrl:urlBase account:account user:user password:[CCUtility getPassword:account] pushTokenHash:pushTokenHash devicePublicKey:pushDevicePublicKey proxyServerUrl:proxyServerPath customUserAgent:nil addCustomHeaders:nil completionHandler:^(NSString *account, NSString *deviceIdentifier, NSString *signature, NSString *publicKey, NSInteger errorCode, NSString *errorDescription) {
-        if (errorCode == 0) {
-            NSString *userAgent = [NSString stringWithFormat:@"%@  (Strict VoIP)", [CCUtility getUserAgent]];
-            [[NCCommunication shared] subscribingPushProxyWithProxyServerUrl:proxyServerPath pushToken:self.pushKitToken deviceIdentifier:deviceIdentifier signature:signature publicKey:publicKey userAgent:userAgent completionHandler:^(NSInteger errorCode, NSString *errorDescription) {
-                if (errorCode == 0) {
-                    
-                    [[NCCommunicationCommon shared] writeLog:@"Subscribed to Push Notification server & proxy successfully"];
-
-                    [CCUtility setPushNotificationToken:account token:self.pushKitToken];
-                    [CCUtility setPushNotificationDeviceIdentifier:account deviceIdentifier:deviceIdentifier];
-                    [CCUtility setPushNotificationDeviceIdentifierSignature:account deviceIdentifierSignature:signature];
-                    [CCUtility setPushNotificationSubscribingPublicKey:account publicKey:publicKey];
-                }
-            }];
-        }
-    }];
-}
-
-- (void)unsubscribingNextcloudServerPushNotification:(NSString *)account urlBase:(NSString *)urlBase user:(NSString *)user withSubscribing:(BOOL)subscribing
-{
-    if (self.account.length == 0) { return; }
-    
-    NSString *deviceIdentifier = [CCUtility getPushNotificationDeviceIdentifier:account];
-    NSString *signature = [CCUtility getPushNotificationDeviceIdentifierSignature:account];
-    NSString *publicKey = [CCUtility getPushNotificationSubscribingPublicKey:account];
-
-    [[NCCommunication shared] unsubscribingPushNotificationWithServerUrl:urlBase account:account user:user password:[CCUtility getPassword:account] customUserAgent:nil addCustomHeaders:nil completionHandler:^(NSString *account, NSInteger errorCode, NSString *errorDescription) {
-        if (errorCode == 0) {
-            NSString *userAgent = [NSString stringWithFormat:@"%@  (Strict VoIP)", [CCUtility getUserAgent]];
-            NSString *proxyServerPath = [NCBrandOptions shared].pushNotificationServerProxy;
-            [[NCCommunication shared] unsubscribingPushProxyWithProxyServerUrl:proxyServerPath deviceIdentifier:deviceIdentifier signature:signature publicKey:publicKey userAgent:userAgent completionHandler:^(NSInteger errorCode, NSString *errorDescription) {
-                if (errorCode == 0) {
-                
-                    [[NCCommunicationCommon shared] writeLog:@"Unsubscribed to Push Notification server & proxy successfully."];
-                    
-                    [CCUtility setPushNotificationPublicKey:account data:nil];
-                    [CCUtility setPushNotificationSubscribingPublicKey:account publicKey:nil];
-                    [CCUtility setPushNotificationPrivateKey:account data:nil];
-                    [CCUtility setPushNotificationToken:account token:nil];
-                    [CCUtility setPushNotificationDeviceIdentifier:account deviceIdentifier:nil];
-                    [CCUtility setPushNotificationDeviceIdentifierSignature:account deviceIdentifierSignature:nil];
-                    
-                    if (self.pushKitToken != nil && subscribing) {
-                        [self subscribingNextcloudServerPushNotification:account urlBase:urlBase user:user];
-                    }
-                }
-            }];
-        }
-    }];
-}
+#pragma mark Push Notifications
 
 -(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
 {
-    //Called when a notification is delivered to a foreground app.
     completionHandler(UNNotificationPresentationOptionAlert);
 }
 
@@ -589,92 +501,17 @@
 
 - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
 {
-    self.pushKitToken = [self stringWithDeviceToken:deviceToken];
-
-    [self pushNotification];
+    [[NCPushNotification shared] registerForRemoteNotificationsWithDeviceToken:deviceToken];
 }
 
 - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
 {
-    NSString *message = [userInfo objectForKey:@"subject"];
-    if (message) {
-        NSArray *results = [[NCManageDatabase shared] getAllAccount];
-        for (tableAccount *result in results) {
-            if ([CCUtility getPushNotificationPrivateKey:result.account]) {
-                NSData *decryptionKey = [CCUtility getPushNotificationPrivateKey:result.account];
-                NSString *decryptedMessage = [[NCPushNotificationEncryption shared] decryptPushNotification:message withDevicePrivateKey:decryptionKey];
-                if (decryptedMessage) {
-                    NSData *data = [decryptedMessage dataUsingEncoding:NSUTF8StringEncoding];
-                    NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
-                    NSInteger nid = [[json objectForKey:@"nid"] integerValue];
-                    BOOL delete = [[json objectForKey:@"delete"] boolValue];
-                    BOOL deleteAll = [[json objectForKey:@"delete-all"] boolValue];
-                    if (delete) {
-                        [self removeNotificationWithNotificationId:nid usingDecryptionKey:decryptionKey];
-                    } else if (deleteAll) {
-                        [self cleanAllNotifications];
-                    }
-                }
-            }
-        }
-    }
-    completionHandler(UIBackgroundFetchResultNoData);
-}
-
-- (void)cleanAllNotifications
-{
-    [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications];
-}
-
-- (void)removeNotificationWithNotificationId:(NSInteger)notificationId usingDecryptionKey:(NSData *)key
-{
-    // Check in pending notifications
-    [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray<UNNotificationRequest *> * _Nonnull requests) {
-        for (UNNotificationRequest *notificationRequest in requests) {
-            NSString *message = [notificationRequest.content.userInfo objectForKey:@"subject"];
-            NSString *decryptedMessage = [[NCPushNotificationEncryption shared] decryptPushNotification:message withDevicePrivateKey:key];
-            if (decryptedMessage) {
-                NSData *data = [decryptedMessage dataUsingEncoding:NSUTF8StringEncoding];
-                NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
-                NSInteger nid = [[json objectForKey:@"nid"] integerValue];
-                if (nid == notificationId) {
-                    [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[notificationRequest.identifier]];
-                }
-            }
-        }
-    }];
-    // Check in delivered notifications
-    [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
-        for (UNNotification *notification in notifications) {
-            NSString *message = [notification.request.content.userInfo objectForKey:@"subject"];
-            NSString *decryptedMessage = [[NCPushNotificationEncryption shared] decryptPushNotification:message withDevicePrivateKey:key];
-            if (decryptedMessage) {
-                NSData *data = [decryptedMessage dataUsingEncoding:NSUTF8StringEncoding];
-                NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
-                NSInteger nid = [[json objectForKey:@"nid"] integerValue];
-                if (nid == notificationId) {
-                    [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:@[notification.request.identifier]];
-                }
-            }
-        }
+    [[NCPushNotification shared] applicationdidReceiveRemoteNotification:userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result) {
+        completionHandler(result);
     }];
 }
 
-- (NSString *)stringWithDeviceToken:(NSData *)deviceToken
-{
-    const char *data = [deviceToken bytes];
-    NSMutableString *token = [NSMutableString string];
-    
-    for (NSUInteger i = 0; i < [deviceToken length]; i++) {
-        [token appendFormat:@"%02.2hhX", data[i]];
-    }
-    
-    return [token copy];
-}
-
-#pragma --------------------------------------------------------------------------------------------
-#pragma mark ===== Fetch =====
-#pragma --------------------------------------------------------------------------------------------
+#pragma mark Fetch
 
 - (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
 {
@@ -695,9 +532,7 @@
     });
 }
 
-#pragma --------------------------------------------------------------------------------------------
-#pragma mark ===== Operation Networking & Session =====
-#pragma --------------------------------------------------------------------------------------------
+#pragma mark Operation Networking & Session
 
 //
 // Method called by the system when all the background task has end
@@ -714,9 +549,7 @@
     });
 }
 
-#pragma --------------------------------------------------------------------------------------------
-#pragma mark ===== OpenURL  =====
-#pragma --------------------------------------------------------------------------------------------
+#pragma mark OpenURL
 
 // Method called from iOS system to send a file from other app.
 - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options
@@ -825,9 +658,7 @@
     return YES;
 }
 
-#pragma --------------------------------------------------------------------------------------------
-#pragma mark ===== Passcode + Delegate =====
-#pragma --------------------------------------------------------------------------------------------
+#pragma mark Passcode + Delegate
 
 - (void)passcodeWithAutomaticallyPromptForBiometricValidation:(BOOL)automaticallyPromptForBiometricValidation
 {

+ 41 - 0
iOSClient/PushNotification/NCPushNotification.h

@@ -0,0 +1,41 @@
+//
+//  NCPushNotification.h
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 26/12/20.
+//  Copyright © 2020 Marino Faggiana. All rights reserved.
+//
+//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface NCPushNotification : NSObject
+
++ (instancetype)shared;
+@property (nonatomic, strong) NSString *pushKitToken;
+
+- (void)pushNotification;
+- (void)applicationdidReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
+- (void)unsubscribingNextcloudServerPushNotification:(NSString *)account urlBase:(NSString *)urlBase user:(NSString *)user withSubscribing:(BOOL)subscribing;
+- (void)removeNotificationWithNotificationId:(NSInteger)notificationId usingDecryptionKey:(NSData *)key;
+- (void)registerForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 214 - 0
iOSClient/PushNotification/NCPushNotification.m

@@ -0,0 +1,214 @@
+//
+//  NCPushNotification.m
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 26/12/20.
+//  Copyright © 2020 Marino Faggiana. All rights reserved.
+//
+//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+#import "AppDelegate.h"
+#import "NCBridgeSwift.h"
+#import "NCPushNotification.h"
+#import "NCPushNotificationEncryption.h"
+
+@interface NCPushNotification ()
+{
+    AppDelegate *appDelegate;
+}
+@end
+
+@implementation NCPushNotification
+
++ (instancetype)shared {
+    static NCPushNotification *pushNotification = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        pushNotification = [self new];
+        pushNotification->appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
+
+    });
+    return pushNotification;
+}
+
+- (void)pushNotification
+{
+    if (appDelegate.account.length == 0 || self.pushKitToken.length == 0) { return; }
+    
+    for (tableAccount *result in [[NCManageDatabase shared] getAllAccount]) {
+        
+        NSString *token = [CCUtility getPushNotificationToken:result.account];
+        
+        if (![token isEqualToString:self.pushKitToken]) {
+            if (token != nil) {
+                // unsubscribing + subscribing
+                [self unsubscribingNextcloudServerPushNotification:result.account urlBase:result.urlBase user:result.user withSubscribing:true];
+            } else {
+                [self subscribingNextcloudServerPushNotification:result.account urlBase:result.urlBase user:result.user];
+            }
+        }
+    }
+}
+
+- (void)applicationdidReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
+    
+    NSString *message = [userInfo objectForKey:@"subject"];
+    if (message) {
+        NSArray *results = [[NCManageDatabase shared] getAllAccount];
+        for (tableAccount *result in results) {
+            if ([CCUtility getPushNotificationPrivateKey:result.account]) {
+                NSData *decryptionKey = [CCUtility getPushNotificationPrivateKey:result.account];
+                NSString *decryptedMessage = [[NCPushNotificationEncryption shared] decryptPushNotification:message withDevicePrivateKey:decryptionKey];
+                if (decryptedMessage) {
+                    NSData *data = [decryptedMessage dataUsingEncoding:NSUTF8StringEncoding];
+                    NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
+                    NSInteger nid = [[json objectForKey:@"nid"] integerValue];
+                    BOOL delete = [[json objectForKey:@"delete"] boolValue];
+                    BOOL deleteAll = [[json objectForKey:@"delete-all"] boolValue];
+                    if (delete) {
+                        [[NCPushNotification shared] removeNotificationWithNotificationId:nid usingDecryptionKey:decryptionKey];
+                    } else if (deleteAll) {
+                        [[NCPushNotification shared] cleanAllNotifications];
+                    }
+                }
+            }
+        }
+    }
+    
+    completionHandler(UIBackgroundFetchResultNoData);
+}
+
+- (void)subscribingNextcloudServerPushNotification:(NSString *)account urlBase:(NSString *)urlBase user:(NSString *)user
+{
+    if (appDelegate.account.length == 0 || self.pushKitToken.length == 0) { return; }
+    
+    [[NCPushNotificationEncryption shared] generatePushNotificationsKeyPair:account];
+
+    NSString *pushTokenHash = [[NCEndToEndEncryption sharedManager] createSHA512:self.pushKitToken];
+    NSData *pushPublicKey = [CCUtility getPushNotificationPublicKey:account];
+    NSString *pushDevicePublicKey = [[NSString alloc] initWithData:pushPublicKey encoding:NSUTF8StringEncoding];
+    NSString *proxyServerPath = [NCBrandOptions shared].pushNotificationServerProxy;
+    
+    [[NCCommunication shared] subscribingPushNotificationWithServerUrl:urlBase account:account user:user password:[CCUtility getPassword:account] pushTokenHash:pushTokenHash devicePublicKey:pushDevicePublicKey proxyServerUrl:proxyServerPath customUserAgent:nil addCustomHeaders:nil completionHandler:^(NSString *account, NSString *deviceIdentifier, NSString *signature, NSString *publicKey, NSInteger errorCode, NSString *errorDescription) {
+        if (errorCode == 0) {
+            NSString *userAgent = [NSString stringWithFormat:@"%@  (Strict VoIP)", [CCUtility getUserAgent]];
+            [[NCCommunication shared] subscribingPushProxyWithProxyServerUrl:proxyServerPath pushToken:self.pushKitToken deviceIdentifier:deviceIdentifier signature:signature publicKey:publicKey userAgent:userAgent completionHandler:^(NSInteger errorCode, NSString *errorDescription) {
+                if (errorCode == 0) {
+                    
+                    [[NCCommunicationCommon shared] writeLog:@"Subscribed to Push Notification server & proxy successfully"];
+
+                    [CCUtility setPushNotificationToken:account token:self.pushKitToken];
+                    [CCUtility setPushNotificationDeviceIdentifier:account deviceIdentifier:deviceIdentifier];
+                    [CCUtility setPushNotificationDeviceIdentifierSignature:account deviceIdentifierSignature:signature];
+                    [CCUtility setPushNotificationSubscribingPublicKey:account publicKey:publicKey];
+                }
+            }];
+        }
+    }];
+}
+
+- (void)unsubscribingNextcloudServerPushNotification:(NSString *)account urlBase:(NSString *)urlBase user:(NSString *)user withSubscribing:(BOOL)subscribing
+{
+    if (appDelegate.account.length == 0) { return; }
+    
+    NSString *deviceIdentifier = [CCUtility getPushNotificationDeviceIdentifier:account];
+    NSString *signature = [CCUtility getPushNotificationDeviceIdentifierSignature:account];
+    NSString *publicKey = [CCUtility getPushNotificationSubscribingPublicKey:account];
+
+    [[NCCommunication shared] unsubscribingPushNotificationWithServerUrl:urlBase account:account user:user password:[CCUtility getPassword:account] customUserAgent:nil addCustomHeaders:nil completionHandler:^(NSString *account, NSInteger errorCode, NSString *errorDescription) {
+        if (errorCode == 0) {
+            NSString *userAgent = [NSString stringWithFormat:@"%@  (Strict VoIP)", [CCUtility getUserAgent]];
+            NSString *proxyServerPath = [NCBrandOptions shared].pushNotificationServerProxy;
+            [[NCCommunication shared] unsubscribingPushProxyWithProxyServerUrl:proxyServerPath deviceIdentifier:deviceIdentifier signature:signature publicKey:publicKey userAgent:userAgent completionHandler:^(NSInteger errorCode, NSString *errorDescription) {
+                if (errorCode == 0) {
+                
+                    [[NCCommunicationCommon shared] writeLog:@"Unsubscribed to Push Notification server & proxy successfully."];
+                    
+                    [CCUtility setPushNotificationPublicKey:account data:nil];
+                    [CCUtility setPushNotificationSubscribingPublicKey:account publicKey:nil];
+                    [CCUtility setPushNotificationPrivateKey:account data:nil];
+                    [CCUtility setPushNotificationToken:account token:nil];
+                    [CCUtility setPushNotificationDeviceIdentifier:account deviceIdentifier:nil];
+                    [CCUtility setPushNotificationDeviceIdentifierSignature:account deviceIdentifierSignature:nil];
+                    
+                    if (self.pushKitToken != nil && subscribing) {
+                        [self subscribingNextcloudServerPushNotification:account urlBase:urlBase user:user];
+                    }
+                }
+            }];
+        }
+    }];
+}
+
+- (void)cleanAllNotifications
+{
+    [[UNUserNotificationCenter currentNotificationCenter] removeAllDeliveredNotifications];
+}
+
+- (void)removeNotificationWithNotificationId:(NSInteger)notificationId usingDecryptionKey:(NSData *)key
+{
+    // Check in pending notifications
+    [[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray<UNNotificationRequest *> * _Nonnull requests) {
+        for (UNNotificationRequest *notificationRequest in requests) {
+            NSString *message = [notificationRequest.content.userInfo objectForKey:@"subject"];
+            NSString *decryptedMessage = [[NCPushNotificationEncryption shared] decryptPushNotification:message withDevicePrivateKey:key];
+            if (decryptedMessage) {
+                NSData *data = [decryptedMessage dataUsingEncoding:NSUTF8StringEncoding];
+                NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
+                NSInteger nid = [[json objectForKey:@"nid"] integerValue];
+                if (nid == notificationId) {
+                    [[UNUserNotificationCenter currentNotificationCenter] removePendingNotificationRequestsWithIdentifiers:@[notificationRequest.identifier]];
+                }
+            }
+        }
+    }];
+    // Check in delivered notifications
+    [[UNUserNotificationCenter currentNotificationCenter] getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
+        for (UNNotification *notification in notifications) {
+            NSString *message = [notification.request.content.userInfo objectForKey:@"subject"];
+            NSString *decryptedMessage = [[NCPushNotificationEncryption shared] decryptPushNotification:message withDevicePrivateKey:key];
+            if (decryptedMessage) {
+                NSData *data = [decryptedMessage dataUsingEncoding:NSUTF8StringEncoding];
+                NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
+                NSInteger nid = [[json objectForKey:@"nid"] integerValue];
+                if (nid == notificationId) {
+                    [[UNUserNotificationCenter currentNotificationCenter] removeDeliveredNotificationsWithIdentifiers:@[notification.request.identifier]];
+                }
+            }
+        }
+    }];
+}
+
+- (void)registerForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
+{
+    self.pushKitToken = [self stringWithDeviceToken:deviceToken];
+    [self pushNotification];
+}
+
+- (NSString *)stringWithDeviceToken:(NSData *)deviceToken
+{
+    const char *data = [deviceToken bytes];
+    NSMutableString *token = [NSMutableString string];
+    
+    for (NSUInteger i = 0; i < [deviceToken length]; i++) {
+        [token appendFormat:@"%02.2hhX", data[i]];
+    }
+    
+    return [token copy];
+}
+
+@end