From d99efa1c5730ff5d1f3b6b3296ff3bd30d2ca6f2 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 19 Feb 2020 16:45:38 +1100 Subject: [PATCH 1/2] Fix unsafe user defaults usage --- .../LokiPushNotificationManager.swift | 9 ++-- .../View Controllers/DeviceNameModal.swift | 2 +- Signal/src/Loki/View Controllers/HomeVC.swift | 9 ++-- .../src/Loki/View Controllers/LandingVC.swift | 5 +- .../View Controllers/NewPrivateChatVC.swift | 2 +- .../OpenGroupSuggestionSheet.swift | 2 +- .../src/Loki/View Controllers/QRCodeVC.swift | 2 +- .../Loki/View Controllers/RegisterVC.swift | 2 +- .../src/Loki/View Controllers/RestoreVC.swift | 2 +- .../src/Loki/View Controllers/SeedModal.swift | 2 +- Signal/src/Loki/View Controllers/SeedVC.swift | 2 +- .../Loki/View Controllers/SettingsVC.swift | 4 +- .../Loki/API/Multi Device/DeviceLink.swift | 2 +- .../src/Loki/Utilities/LKUserDefaults.swift | 53 +++++++++++++++++++ 14 files changed, 76 insertions(+), 22 deletions(-) create mode 100644 SignalServiceKit/src/Loki/Utilities/LKUserDefaults.swift diff --git a/Signal/src/Loki/Utilities/LokiPushNotificationManager.swift b/Signal/src/Loki/Utilities/LokiPushNotificationManager.swift index 19eb5977c..d11ff6891 100644 --- a/Signal/src/Loki/Utilities/LokiPushNotificationManager.swift +++ b/Signal/src/Loki/Utilities/LokiPushNotificationManager.swift @@ -12,8 +12,9 @@ final class LokiPushNotificationManager : NSObject { @objc(registerWithToken:) func register(with token: Data) { let hexEncodedToken = token.map { String(format: "%02.2hhx", $0) }.joined() - let oldToken = UserDefaults.standard.string(forKey: "deviceToken") - let lastUploadTime = UserDefaults.standard.double(forKey: "lastDeviceTokenUploadTime") + let userDefaults = UserDefaults.standard + let oldToken = userDefaults[.deviceToken] + let lastUploadTime = userDefaults[.lastDeviceTokenUpload] let now = Date().timeIntervalSince1970 if hexEncodedToken == oldToken && now - lastUploadTime < 2 * 24 * 60 * 60 { print("[Loki] Device token hasn't changed; no need to upload.") @@ -29,8 +30,8 @@ final class LokiPushNotificationManager : NSObject { guard json["code"] as? Int != 0 else { return print("[Loki] An error occured during device token registration: \(json["message"] as? String ?? "nil").") } - UserDefaults.standard.set(hexEncodedToken, forKey: "deviceToken") - UserDefaults.standard.set(now, forKey: "lastDeviceTokenUploadTime") + userDefaults[.deviceToken] = hexEncodedToken + userDefaults[.lastDeviceTokenUpload] = now }, failure: { _, error in print("[Loki] Couldn't register device token.") }) diff --git a/Signal/src/Loki/View Controllers/DeviceNameModal.swift b/Signal/src/Loki/View Controllers/DeviceNameModal.swift index 7e9bd7ded..432c92d35 100644 --- a/Signal/src/Loki/View Controllers/DeviceNameModal.swift +++ b/Signal/src/Loki/View Controllers/DeviceNameModal.swift @@ -92,7 +92,7 @@ final class DeviceNameModal : Modal { @objc private func changeName() { let name = nameTextField.text!.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) if !name.isEmpty { - UserDefaults.standard.set(name, forKey: "\(device.hexEncodedPublicKey)_display_name") + UserDefaults.standard[.slaveDeviceName(device.hexEncodedPublicKey)] = name delegate?.handleDeviceNameChanged(to: name, for: device) } else { let alert = UIAlertController(title: NSLocalizedString("Error", comment: ""), message: NSLocalizedString("Please pick a name", comment: ""), preferredStyle: .alert) diff --git a/Signal/src/Loki/View Controllers/HomeVC.swift b/Signal/src/Loki/View Controllers/HomeVC.swift index df587fff3..3e8efcab1 100644 --- a/Signal/src/Loki/View Controllers/HomeVC.swift +++ b/Signal/src/Loki/View Controllers/HomeVC.swift @@ -88,8 +88,9 @@ final class HomeVC : UIViewController, UITableViewDataSource, UITableViewDelegat titleLabel.font = .boldSystemFont(ofSize: Values.veryLargeFontSize) navigationItem.titleView = titleLabel // Set up seed reminder view if needed - let hasViewedSeed = UserDefaults.standard.bool(forKey: "hasViewedSeed") - let isMasterDevice = (UserDefaults.standard.string(forKey: "masterDeviceHexEncodedPublicKey") == nil) + let userDefaults = UserDefaults.standard + let hasViewedSeed = userDefaults[.hasViewedSeed] + let isMasterDevice = userDefaults.isMasterDevice if !hasViewedSeed && isMasterDevice { view.addSubview(seedReminderView) seedReminderView.pin(.leading, to: .leading, of: view) @@ -145,14 +146,14 @@ final class HomeVC : UIViewController, UITableViewDataSource, UITableViewDelegat override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) isViewVisible = true -// let hasSeenOpenGroupSuggestionSheet = UserDefaults.standard.bool(forKey: "hasSeenOpenGroupSuggestionSheet") +// let hasSeenOpenGroupSuggestionSheet = UserDefaults.standard[.hasSeenOpenGroupSuggestionSheet] // if !hasSeenOpenGroupSuggestionSheet { // let openGroupSuggestionSheet = OpenGroupSuggestionSheet() // openGroupSuggestionSheet.modalPresentationStyle = .overFullScreen // openGroupSuggestionSheet.modalTransitionStyle = .crossDissolve // present(openGroupSuggestionSheet, animated: true, completion: nil) // } - UserDefaults.standard.set(true, forKey: "hasLaunchedOnce") + UserDefaults.standard[.hasLaunchedOnce] = true } override func viewWillDisappear(_ animated: Bool) { diff --git a/Signal/src/Loki/View Controllers/LandingVC.swift b/Signal/src/Loki/View Controllers/LandingVC.swift index 3369edc3c..a27babeda 100644 --- a/Signal/src/Loki/View Controllers/LandingVC.swift +++ b/Signal/src/Loki/View Controllers/LandingVC.swift @@ -100,7 +100,7 @@ final class LandingVC : UIViewController, LinkDeviceVCDelegate, DeviceLinkingMod mainStackView.pin(to: view) topSpacer.heightAnchor.constraint(equalTo: bottomSpacer.heightAnchor, multiplier: 1).isActive = true // Show device unlinked alert if needed - if UserDefaults.standard.bool(forKey: "wasUnlinked") { + if UserDefaults.standard[.wasUnlinked] { let alert = UIAlertController(title: NSLocalizedString("Device Unlinked", comment: ""), message: NSLocalizedString("Your device was unlinked successfully", comment: ""), preferredStyle: .alert) alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), accessibilityIdentifier: nil, style: .default, handler: nil)) present(alert, animated: true, completion: nil) @@ -190,8 +190,7 @@ final class LandingVC : UIViewController, LinkDeviceVCDelegate, DeviceLinkingMod } func handleDeviceLinkAuthorized(_ deviceLink: DeviceLink) { - let userDefaults = UserDefaults.standard - userDefaults.set(deviceLink.master.hexEncodedPublicKey, forKey: "masterDeviceHexEncodedPublicKey") + UserDefaults.standard[.masterHexEncodedPublicKey] = deviceLink.master.hexEncodedPublicKey fakeChatViewContentOffset = fakeChatView.contentOffset DispatchQueue.main.async { self.fakeChatView.contentOffset = self.fakeChatViewContentOffset diff --git a/Signal/src/Loki/View Controllers/NewPrivateChatVC.swift b/Signal/src/Loki/View Controllers/NewPrivateChatVC.swift index 9fccf24f8..6ebe9711c 100644 --- a/Signal/src/Loki/View Controllers/NewPrivateChatVC.swift +++ b/Signal/src/Loki/View Controllers/NewPrivateChatVC.swift @@ -155,7 +155,7 @@ private final class EnterPublicKeyVC : UIViewController { weak var newPrivateChatVC: NewPrivateChatVC! private lazy var userHexEncodedPublicKey: String = { - if let masterHexEncodedPublicKey = UserDefaults.standard.string(forKey: "masterDeviceHexEncodedPublicKey") { + if let masterHexEncodedPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] { return masterHexEncodedPublicKey } else { return getUserHexEncodedPublicKey() diff --git a/Signal/src/Loki/View Controllers/OpenGroupSuggestionSheet.swift b/Signal/src/Loki/View Controllers/OpenGroupSuggestionSheet.swift index 09cce552d..a8d3da600 100644 --- a/Signal/src/Loki/View Controllers/OpenGroupSuggestionSheet.swift +++ b/Signal/src/Loki/View Controllers/OpenGroupSuggestionSheet.swift @@ -71,7 +71,7 @@ final class OpenGroupSuggestionSheet : Sheet { } override func close() { - UserDefaults.standard.set(true, forKey: "hasSeenOpenGroupSuggestionSheet") + UserDefaults.standard[.hasSeenOpenGroupSuggestionSheet] = true super.close() } } diff --git a/Signal/src/Loki/View Controllers/QRCodeVC.swift b/Signal/src/Loki/View Controllers/QRCodeVC.swift index cf11b829c..cd7a222cb 100644 --- a/Signal/src/Loki/View Controllers/QRCodeVC.swift +++ b/Signal/src/Loki/View Controllers/QRCodeVC.swift @@ -152,7 +152,7 @@ private final class ViewMyQRCodeVC : UIViewController { private var bottomConstraint: NSLayoutConstraint! private lazy var userHexEncodedPublicKey: String = { - if let masterHexEncodedPublicKey = UserDefaults.standard.string(forKey: "masterDeviceHexEncodedPublicKey") { + if let masterHexEncodedPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] { return masterHexEncodedPublicKey } else { return getUserHexEncodedPublicKey() diff --git a/Signal/src/Loki/View Controllers/RegisterVC.swift b/Signal/src/Loki/View Controllers/RegisterVC.swift index 217c05a65..2af6e4dbe 100644 --- a/Signal/src/Loki/View Controllers/RegisterVC.swift +++ b/Signal/src/Loki/View Controllers/RegisterVC.swift @@ -187,7 +187,7 @@ final class RegisterVC : UIViewController { databaseConnection.setObject(keyPair!, forKey: OWSPrimaryStorageIdentityKeyStoreIdentityKey, inCollection: OWSPrimaryStorageIdentityKeyStoreCollection) TSAccountManager.sharedInstance().phoneNumberAwaitingVerification = keyPair!.hexEncodedPublicKey OWSPrimaryStorage.shared().setRestorationTime(0) - UserDefaults.standard.set(false, forKey: "hasViewedSeed") + UserDefaults.standard[.hasViewedSeed] = false let displayNameVC = DisplayNameVC() navigationController!.pushViewController(displayNameVC, animated: true) } diff --git a/Signal/src/Loki/View Controllers/RestoreVC.swift b/Signal/src/Loki/View Controllers/RestoreVC.swift index 79b00667a..680a9617b 100644 --- a/Signal/src/Loki/View Controllers/RestoreVC.swift +++ b/Signal/src/Loki/View Controllers/RestoreVC.swift @@ -178,7 +178,7 @@ final class RestoreVC : UIViewController { databaseConnection.setObject(keyPair, forKey: OWSPrimaryStorageIdentityKeyStoreIdentityKey, inCollection: OWSPrimaryStorageIdentityKeyStoreCollection) TSAccountManager.sharedInstance().phoneNumberAwaitingVerification = keyPair.hexEncodedPublicKey OWSPrimaryStorage.shared().setRestorationTime(Date().timeIntervalSince1970) - UserDefaults.standard.set(true, forKey: "hasViewedSeed") + UserDefaults.standard[.hasViewedSeed] = true mnemonicTextField.resignFirstResponder() Timer.scheduledTimer(withTimeInterval: 0.25, repeats: false) { _ in let displayNameVC = DisplayNameVC() diff --git a/Signal/src/Loki/View Controllers/SeedModal.swift b/Signal/src/Loki/View Controllers/SeedModal.swift index 7f8049405..21bd3bb8d 100644 --- a/Signal/src/Loki/View Controllers/SeedModal.swift +++ b/Signal/src/Loki/View Controllers/SeedModal.swift @@ -62,7 +62,7 @@ final class SeedModal : Modal { contentView.pin(.trailing, to: .trailing, of: stackView, withInset: Values.largeSpacing) contentView.pin(.bottom, to: .bottom, of: stackView, withInset: Values.largeSpacing) // Mark seed as viewed - UserDefaults.standard.set(true, forKey: "hasViewedSeed") + UserDefaults.standard[.hasViewedSeed] = true NotificationCenter.default.post(name: .seedViewed, object: nil) } diff --git a/Signal/src/Loki/View Controllers/SeedVC.swift b/Signal/src/Loki/View Controllers/SeedVC.swift index a07518575..e0fd439a0 100644 --- a/Signal/src/Loki/View Controllers/SeedVC.swift +++ b/Signal/src/Loki/View Controllers/SeedVC.swift @@ -182,7 +182,7 @@ final class SeedVC : UIViewController { self.seedReminderView.subtitle = NSLocalizedString("Make sure to store your recovery phrase in a safe place", comment: "") }, completion: nil) seedReminderView.setProgress(1, animated: true) - UserDefaults.standard.set(true, forKey: "hasViewedSeed") + UserDefaults.standard[.hasViewedSeed] = true NotificationCenter.default.post(name: .seedViewed, object: nil) } diff --git a/Signal/src/Loki/View Controllers/SettingsVC.swift b/Signal/src/Loki/View Controllers/SettingsVC.swift index f2cf55625..e4adb62e2 100644 --- a/Signal/src/Loki/View Controllers/SettingsVC.swift +++ b/Signal/src/Loki/View Controllers/SettingsVC.swift @@ -5,7 +5,7 @@ final class SettingsVC : UIViewController, AvatarViewHelperDelegate { private var isEditingDisplayName = false { didSet { handleIsEditingDisplayNameChanged() } } private lazy var userHexEncodedPublicKey: String = { - if let masterHexEncodedPublicKey = UserDefaults.standard.string(forKey: "masterDeviceHexEncodedPublicKey") { + if let masterHexEncodedPublicKey = UserDefaults.standard[.masterHexEncodedPublicKey] { return masterHexEncodedPublicKey } else { return getUserHexEncodedPublicKey() @@ -180,7 +180,7 @@ final class SettingsVC : UIViewController, AvatarViewHelperDelegate { getSeparator(), getSettingButton(withTitle: NSLocalizedString("Notifications", comment: ""), color: Colors.text, action: #selector(showNotificationSettings)) ] - let isMasterDevice = (UserDefaults.standard.string(forKey: "masterDeviceHexEncodedPublicKey") == nil) + let isMasterDevice = UserDefaults.standard.isMasterDevice if isMasterDevice { result.append(getSeparator()) result.append(getSettingButton(withTitle: NSLocalizedString("Devices", comment: ""), color: Colors.text, action: #selector(showLinkedDevices))) diff --git a/SignalServiceKit/src/Loki/API/Multi Device/DeviceLink.swift b/SignalServiceKit/src/Loki/API/Multi Device/DeviceLink.swift index 76822e544..d9a4325de 100644 --- a/SignalServiceKit/src/Loki/API/Multi Device/DeviceLink.swift +++ b/SignalServiceKit/src/Loki/API/Multi Device/DeviceLink.swift @@ -18,7 +18,7 @@ public final class DeviceLink : NSObject, NSCoding { @objc public let signature: Data? @objc public var displayName: String { - if let customDisplayName = UserDefaults.standard.string(forKey: "\(hexEncodedPublicKey)_display_name") { + if let customDisplayName = UserDefaults.standard[.slaveDeviceName(hexEncodedPublicKey)] { return customDisplayName } else { return NSLocalizedString("Unnamed Device", comment: "") diff --git a/SignalServiceKit/src/Loki/Utilities/LKUserDefaults.swift b/SignalServiceKit/src/Loki/Utilities/LKUserDefaults.swift new file mode 100644 index 000000000..f1d426fd7 --- /dev/null +++ b/SignalServiceKit/src/Loki/Utilities/LKUserDefaults.swift @@ -0,0 +1,53 @@ +import Foundation + +public enum LKUserDefaults { + + public enum Bool : Swift.String { + case hasLaunchedOnce + case hasSeenOpenGroupSuggestionSheet + case hasViewedSeed + /// Whether the device was unlinked as a slave device (used to notify the user on the landing screen). + case wasUnlinked + } + + public enum Double : Swift.String { + case lastDeviceTokenUpload = "lastDeviceTokenUploadTime" + } + + public enum String { + case slaveDeviceName(Swift.String) + case deviceToken + /// `nil` if this is a master device or if the user hasn't linked a device. + case masterHexEncodedPublicKey + + public var key: Swift.String { + switch self { + case .slaveDeviceName(let hexEncodedPublicKey): return "\(hexEncodedPublicKey)_display_name" + case .deviceToken: return "deviceToken" + case .masterHexEncodedPublicKey: return "masterDeviceHexEncodedPublicKey" + } + } + } +} + +public extension UserDefaults { + + public subscript(bool: LKUserDefaults.Bool) -> Bool { + get { return self.bool(forKey: bool.rawValue) } + set { set(newValue, forKey: bool.rawValue) } + } + + public subscript(double: LKUserDefaults.Double) -> Double { + get { return self.double(forKey: double.rawValue) } + set { set(newValue, forKey: double.rawValue) } + } + + public subscript(string: LKUserDefaults.String) -> String? { + get { return self.string(forKey: string.key) } + set { set(newValue, forKey: string.key) } + } + + public var isMasterDevice: Bool { + return (self[.masterHexEncodedPublicKey] == nil) + } +} From cda609c02d1c568626955cb5fff865207221e5f8 Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Wed, 19 Feb 2020 16:46:19 +1100 Subject: [PATCH 2/2] Update Pods --- Pods | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pods b/Pods index 3fbdfaf01..67dbced37 160000 --- a/Pods +++ b/Pods @@ -1 +1 @@ -Subproject commit 3fbdfaf0158f182482961b8b989e27abef36fea1 +Subproject commit 67dbced37481e0011a3df1397ed57711384a4957