From 56c93f20798379b51ea12fd5ef5cc83d7bdbb422 Mon Sep 17 00:00:00 2001 From: COVIDSafe Support <64945427+covidsafe-support@users.noreply.github.com> Date: Mon, 18 May 2020 12:43:53 +1000 Subject: [PATCH] COVIDSafe code from version 1.3 (#2) --- CovidSafe.xcodeproj/project.pbxproj | 48 +++++++++------- CovidSafe/AppDelegate.swift | 68 +++++++++++++++++------ CovidSafe/CentralController.swift | 6 +- CovidSafe/Encounter+EncounterRecord.swift | 1 + CovidSafe/PushNotificationConstants.swift | 5 ++ README.md | 2 +- 6 files changed, 88 insertions(+), 42 deletions(-) diff --git a/CovidSafe.xcodeproj/project.pbxproj b/CovidSafe.xcodeproj/project.pbxproj index 96d4ec6..89e46d9 100644 --- a/CovidSafe.xcodeproj/project.pbxproj +++ b/CovidSafe.xcodeproj/project.pbxproj @@ -52,6 +52,8 @@ 590C99332432C1C400A5EC71 /* UploadDataHomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B69E7E82430C22E00561DD9 /* UploadDataHomeViewController.swift */; }; 592CBB802441A583001FFCE9 /* PersonalDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 592CBB7F2441A583001FFCE9 /* PersonalDetailsViewController.swift */; }; 592CBB812441A583001FFCE9 /* PersonalDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 592CBB7F2441A583001FFCE9 /* PersonalDetailsViewController.swift */; }; + 5956CD8F246D44EA00EA4D4A /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5956CD8E246D44EA00EA4D4A /* CoreBluetooth.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 5956CD90246D44F100EA4D4A /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5956CD8E246D44EA00EA4D4A /* CoreBluetooth.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 5957EB67244E936E002F5388 /* UnderSixteenViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B7ABF27244D6BE100BB249B /* UnderSixteenViewController.swift */; }; 596B189924496D32003E190F /* Encounter+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 596B189824496D32003E190F /* Encounter+Util.swift */; }; 596B189A24496D32003E190F /* Encounter+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 596B189824496D32003E190F /* Encounter+Util.swift */; }; @@ -275,6 +277,7 @@ 46D0C3F015CA753BB4D4787D /* Pods-CovidSafe-staging.covid-production.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CovidSafe-staging.covid-production.xcconfig"; path = "Target Support Files/Pods-CovidSafe-staging/Pods-CovidSafe-staging.covid-production.xcconfig"; sourceTree = ""; }; 5909E4AA245043C400D41C26 /* CovidPersistentContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CovidPersistentContainer.swift; sourceTree = ""; }; 592CBB7F2441A583001FFCE9 /* PersonalDetailsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonalDetailsViewController.swift; sourceTree = ""; }; + 5956CD8E246D44EA00EA4D4A /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; }; 596B189824496D32003E190F /* Encounter+Util.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Encounter+Util.swift"; sourceTree = ""; }; 596B189B24499591003E190F /* UploadHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadHelper.swift; sourceTree = ""; }; 59898602245173C200966E61 /* URLHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLHelper.swift; sourceTree = ""; }; @@ -384,7 +387,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - AC1B51D6C926C60CCC1FB565 /* Pods_CovidSafe_staging.framework in Frameworks */, + 5956CD8F246D44EA00EA4D4A /* CoreBluetooth.framework in Frameworks */, + AC1B51D6C926C60CCC1FB565 /* Pods_CovidCare_staging.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -392,8 +396,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 469DD4CFF262D29768A8CBEF /* Pods_CovidSafe.framework in Frameworks */, - 7AB66BCCCA27E969EE126F9F /* Pods_CovidSafe.framework in Frameworks */, + 5956CD90246D44F100EA4D4A /* CoreBluetooth.framework in Frameworks */, + 469DD4CFF262D29768A8CBEF /* Pods_CovidCare.framework in Frameworks */, + 7AB66BCCCA27E969EE126F9F /* Pods_CovidCare.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -694,8 +699,9 @@ A8070984118AE80B4E052641 /* Frameworks */ = { isa = PBXGroup; children = ( - 5BE2A0527997C5042B9E2A41 /* Pods_CovidSafe.framework */, - D0A3F236B583DE5A31A50F1F /* Pods_CovidSafe_staging.framework */, + 5956CD8E246D44EA00EA4D4A /* CoreBluetooth.framework */, + 5BE2A0527997C5042B9E2A41 /* Pods_CovidCare.framework */, + D0A3F236B583DE5A31A50F1F /* Pods_CovidCare_staging.framework */, ); name = Frameworks; sourceTree = ""; @@ -1308,7 +1314,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 18; + CURRENT_PROJECT_VERSION = 20; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = CovidSafe/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -1316,7 +1322,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2; + MARKETING_VERSION = 1.3; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; PRODUCT_NAME = COVIDSafe; @@ -1391,7 +1397,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 18; + CURRENT_PROJECT_VERSION = 20; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = CovidSafe/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -1399,7 +1405,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2; + MARKETING_VERSION = 1.3; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; PRODUCT_NAME = COVIDSafe; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1419,7 +1425,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 18; + CURRENT_PROJECT_VERSION = 19; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = CovidSafe/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -1427,7 +1433,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2; + MARKETING_VERSION = 1.3; ONLY_ACTIVE_ARCH = YES; OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; @@ -1448,7 +1454,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 18; + CURRENT_PROJECT_VERSION = 19; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = CovidSafe/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -1456,7 +1462,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2; + MARKETING_VERSION = 1.3; ONLY_ACTIVE_ARCH = YES; OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; @@ -1477,7 +1483,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 18; + CURRENT_PROJECT_VERSION = 19; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = CovidSafe/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -1485,7 +1491,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2; + MARKETING_VERSION = 1.3; OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; PRODUCT_NAME = "COVIDSafe-staging"; @@ -1506,7 +1512,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 18; + CURRENT_PROJECT_VERSION = 19; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = CovidSafe/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -1514,7 +1520,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2; + MARKETING_VERSION = 1.3; OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D DEBUG"; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; PRODUCT_NAME = "COVIDSafe-staging"; @@ -1651,7 +1657,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 18; + CURRENT_PROJECT_VERSION = 20; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = CovidSafe/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -1659,7 +1665,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2; + MARKETING_VERSION = 1.3; ONLY_ACTIVE_ARCH = YES; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; PRODUCT_NAME = COVIDSafe; @@ -1679,7 +1685,7 @@ CODE_SIGN_ENTITLEMENTS = "CovidSafe/Project Bluetrace.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 18; + CURRENT_PROJECT_VERSION = 20; DEVELOPMENT_TEAM = 45792XH5L8; INFOPLIST_FILE = CovidSafe/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 10.0; @@ -1687,7 +1693,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2; + MARKETING_VERSION = 1.3; PRODUCT_BUNDLE_IDENTIFIER = au.gov.health.covidsafe; PRODUCT_NAME = COVIDSafe; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/CovidSafe/AppDelegate.swift b/CovidSafe/AppDelegate.swift index 07bfb51..303ee9b 100644 --- a/CovidSafe/AppDelegate.swift +++ b/CovidSafe/AppDelegate.swift @@ -40,6 +40,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { UNUserNotificationCenter.current().delegate = self NotificationCenter.default.addObserver(self, selector:#selector(jwtExpired(_:)),name: .jwtExpired, object: nil) + NotificationCenter.default.addObserver(self, selector:#selector(deferReminderNotifications(_:)),name: .encounterRecorded, object: nil) setupBluetoothPNStatusCallback() @@ -103,23 +104,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } } - fileprivate func triggerCalendarLocalPushNotifications(pnContent: [String : String], identifier: String) { - - let center = UNUserNotificationCenter.current() - - let content = UNMutableNotificationContent() - content.title = pnContent["contentTitle"]! - content.body = pnContent["contentBody"]! - - var dateComponents = DateComponents() - dateComponents.hour = 9 - - let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true) - - let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger) - center.add(request) + fileprivate func cancelPreviouslyScheduledNotifications() { + UNUserNotificationCenter.current().removeAllPendingNotificationRequests() } - + fileprivate func triggerIntervalLocalPushNotifications(pnContent: [String : String], identifier: String) { let center = UNUserNotificationCenter.current() @@ -133,6 +121,48 @@ class AppDelegate: UIResponder, UIApplicationDelegate { let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger) center.add(request) } + + + #if DEBUG + let intervals: [TimeInterval] = [60, 15 * 60, 30 * 60, 60 * 60, 120 * 60] + #else + let intervals: [TimeInterval] = [TimeInterval(60 * 60 * 48)] + #endif + + fileprivate func scheduleReminderNotifications() { + + let reminderContent = PushNotificationConstants.reminderPushNotifContents + guard + let title = reminderContent["contentTitle"], + let body = reminderContent["contentBody"] else { + return + } + + let notificationCenter = UNUserNotificationCenter.current() + + for interval in intervals { + let content = UNMutableNotificationContent() + + #if DEBUG + content.title = "\(title) \(interval / 60) min" + #else + content.title = title + #endif + + content.body = body + + let trigger = UNTimeIntervalNotificationTrigger(timeInterval: interval, repeats: false) + + let request = UNNotificationRequest(identifier: "reminder-\(interval)", content: content, trigger: trigger) + notificationCenter.add(request) + } + } + + @objc + func deferReminderNotifications(_ notification: Notification) { + cancelPreviouslyScheduledNotifications() + scheduleReminderNotifications() + } // MARK: - Core Data stack @@ -164,6 +194,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { DLog("applicationWillResignActive") // Retry in case it failed on become active clearOldDataInContext() + scheduleReminderNotifications() } func applicationDidEnterBackground(_ application: UIApplication) { @@ -171,14 +202,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate { Encounter.timestamp(for: .appEnteredBackground) self.dismissBlackscreen() - stopAccelerometerUpdates() + stopAccelerometerUpdates() } func applicationWillEnterForeground(_ application: UIApplication) { DLog("applicationWillEnterForeground") self.dismissBlackscreen() - UNUserNotificationCenter.current().removeAllPendingNotificationRequests() + cancelPreviouslyScheduledNotifications() } func applicationWillTerminate(_ application: UIApplication) { @@ -350,6 +381,7 @@ extension Notification.Name { static let disableUserInteraction = Notification.Name("disableUserInteraction") static let enableUserInteraction = Notification.Name("enableUserInteraction") static let jwtExpired = Notification.Name("jwtExpired") + static let encounterRecorded = Notification.Name("encounterRecorded") } @available(iOS 10, *) diff --git a/CovidSafe/CentralController.swift b/CovidSafe/CentralController.swift index 35872b6..4397096 100644 --- a/CovidSafe/CentralController.swift +++ b/CovidSafe/CentralController.swift @@ -228,8 +228,10 @@ extension CentralController: CBCentralManagerDelegate { func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { DLog("CC didDisconnectPeripheral \(peripheral) , \(error != nil ? "error: \(error.debugDescription)" : "" )") - let options = [CBConnectPeripheralOptionStartDelayKey: NSNumber(15)] - central.connect(peripheral, options: options) + if #available(iOS 12, *) { + let options = [CBConnectPeripheralOptionStartDelayKey: NSNumber(15)] + central.connect(peripheral, options: options) + } } func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) { diff --git a/CovidSafe/Encounter+EncounterRecord.swift b/CovidSafe/Encounter+EncounterRecord.swift index d1ce522..5d9f379 100644 --- a/CovidSafe/Encounter+EncounterRecord.swift +++ b/CovidSafe/Encounter+EncounterRecord.swift @@ -25,6 +25,7 @@ extension EncounterRecord { } catch { print("Could not save. \(error)") } + NotificationCenter.default.post(name: .encounterRecorded, object: nil) } } diff --git a/CovidSafe/PushNotificationConstants.swift b/CovidSafe/PushNotificationConstants.swift index d168abc..f7c0368 100644 --- a/CovidSafe/PushNotificationConstants.swift +++ b/CovidSafe/PushNotificationConstants.swift @@ -13,4 +13,9 @@ struct PushNotificationConstants { "contentBody": "Help stop the spread of COVID-19 by keeping your phone’s Bluetooth on until the outbreak is over." ] ] + + static let reminderPushNotifContents = [ + "contentTitle": "Reminder: COVIDSafe app has not been active in the past 48 hours", + "contentBody": "Tap to open the app and keep Bluetooth enabled." + ] } diff --git a/README.md b/README.md index 712299e..b537a03 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # COVIDSafe app -# Please report any security vulnerabilities using the details from [https://covidsafe.gov.au/.well-known/security.txt](https://covidsafe.gov.au/.well-known/security.txt) +# Please report any security vulnerabilities using the details from [https://covidsafe.gov.au/.well-known/security.txt](https://covidsafe.gov.au/.well-known/security.txt) # [Terms and Conditions for access to COVIDSafe App code](https://github.com/AU-COVIDSafe/mobile-ios/blob/master/LICENSE.md) By accessing the App Code I accept and agree to the following terms: