TrioRemoteControl.swift 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import CoreData
  2. import Foundation
  3. import Swinject
  4. class TrioRemoteControl: Injectable {
  5. static let shared = TrioRemoteControl()
  6. @Injected() internal var tempTargetsStorage: TempTargetsStorage!
  7. @Injected() internal var carbsStorage: CarbsStorage!
  8. @Injected() internal var nightscoutManager: NightscoutManager!
  9. @Injected() internal var overrideStorage: OverrideStorage!
  10. @Injected() internal var settings: SettingsManager!
  11. private let timeWindow: TimeInterval = 600 // Defines how old messages that are accepted, 10 minutes
  12. internal let pumpHistoryFetchContext: NSManagedObjectContext
  13. internal let viewContext: NSManagedObjectContext
  14. private init() {
  15. pumpHistoryFetchContext = CoreDataStack.shared.newTaskContext()
  16. viewContext = CoreDataStack.shared.persistentContainer.viewContext
  17. injectServices(FreeAPSApp.resolver)
  18. }
  19. func handleRemoteNotification(pushMessage: PushMessage) async {
  20. let isTrioRemoteControlEnabled = UserDefaults.standard.bool(forKey: "isTrioRemoteControlEnabled")
  21. guard isTrioRemoteControlEnabled else {
  22. await logError("Remote command received, but remote control is disabled in settings. Ignoring the command.")
  23. return
  24. }
  25. let currentTime = Date().timeIntervalSince1970
  26. let timeDifference = currentTime - pushMessage.timestamp
  27. if timeDifference > timeWindow {
  28. await logError(
  29. "Command rejected: the message is too old (sent \(Int(timeDifference)) seconds ago, which exceeds the allowed limit).",
  30. pushMessage: pushMessage
  31. )
  32. return
  33. } else if timeDifference < -timeWindow {
  34. await logError(
  35. "Command rejected: the message has an invalid future timestamp (timestamp is \(Int(-timeDifference)) seconds ahead of the current time).",
  36. pushMessage: pushMessage
  37. )
  38. return
  39. }
  40. debug(.remoteControl, "Command received with acceptable time difference: \(Int(timeDifference)) seconds.")
  41. let storedSecret = UserDefaults.standard.string(forKey: "trioRemoteControlSharedSecret") ?? ""
  42. guard !storedSecret.isEmpty else {
  43. await logError(
  44. "Command rejected: shared secret is missing in settings. Cannot authenticate the command.",
  45. pushMessage: pushMessage
  46. )
  47. return
  48. }
  49. guard pushMessage.sharedSecret == storedSecret else {
  50. await logError(
  51. "Command rejected: shared secret does not match. Cannot authenticate the command.",
  52. pushMessage: pushMessage
  53. )
  54. return
  55. }
  56. switch pushMessage.commandType {
  57. case .bolus:
  58. await handleBolusCommand(pushMessage)
  59. case .tempTarget:
  60. await handleTempTargetCommand(pushMessage)
  61. case .cancelTempTarget:
  62. await cancelTempTarget(pushMessage)
  63. case .meal:
  64. await handleMealCommand(pushMessage)
  65. case .startOverride:
  66. await handleStartOverrideCommand(pushMessage)
  67. case .cancelOverride:
  68. await handleCancelOverrideCommand(pushMessage)
  69. }
  70. }
  71. }
  72. // MARK: - CommandType Enum
  73. extension TrioRemoteControl {
  74. enum CommandType: String, Codable {
  75. case bolus
  76. case tempTarget = "temp_target"
  77. case cancelTempTarget = "cancel_temp_target"
  78. case meal
  79. case startOverride = "start_override"
  80. case cancelOverride = "cancel_override"
  81. var description: String {
  82. switch self {
  83. case .bolus:
  84. return "Bolus"
  85. case .tempTarget:
  86. return "Temporary Target"
  87. case .cancelTempTarget:
  88. return "Cancel Temporary Target"
  89. case .meal:
  90. return "Meal"
  91. case .startOverride:
  92. return "Start Override"
  93. case .cancelOverride:
  94. return "Cancel Override"
  95. }
  96. }
  97. }
  98. }