diff options
author | marinofaggiana <marino@marinofaggiana.com> | 2020-12-26 14:19:40 +0300 |
---|---|---|
committer | marinofaggiana <marino@marinofaggiana.com> | 2020-12-26 14:19:40 +0300 |
commit | 48b27fea23f77d890fba4a5572173562eecd7fb9 (patch) | |
tree | d8ef379046246d5319c2f6176edd8821bff96821 /iOSClient/PushNotification | |
parent | 0f60ef95202dcf6ed3e756a5d41cd2318993a389 (diff) |
clear code [move out the push notification]
Diffstat (limited to 'iOSClient/PushNotification')
-rw-r--r-- | iOSClient/PushNotification/NCPushNotification.h | 41 | ||||
-rw-r--r-- | iOSClient/PushNotification/NCPushNotification.m | 214 |
2 files changed, 255 insertions, 0 deletions
diff --git a/iOSClient/PushNotification/NCPushNotification.h b/iOSClient/PushNotification/NCPushNotification.h new file mode 100644 index 000000000..ee6d8f401 --- /dev/null +++ b/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 diff --git a/iOSClient/PushNotification/NCPushNotification.m b/iOSClient/PushNotification/NCPushNotification.m new file mode 100644 index 000000000..29d2d6c1d --- /dev/null +++ b/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 |