Commit 38f2e4eb authored by stopcovid@lunabee.com's avatar stopcovid@lunabee.com

Code cleaning + Interface updates + NSError and Data extensions added.

parent 9724df58
......@@ -24,5 +24,10 @@ extension Data {
CCHmac(CCHmacAlgorithm(kCCHmacAlgSHA256), keyString, keyLength, string, stringLength, &result)
return Data(result)
}
mutating func wipeData() {
guard let range = Range(NSMakeRange(0, count)) else { return }
resetBytes(in: range)
}
}
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//
// NSError+RBExtension.swift
// STOP-COVID
//
// Created by Lunabee Studio / Date - 29/04/2020 - for the STOP-COVID project.
//
import Foundation
extension NSError {
static func rbLocalizedError(message: String, code: Int) -> Error {
return NSError(domain: "Robert-SDK", code: code, userInfo: [NSLocalizedDescriptionKey: message])
}
}
......@@ -21,10 +21,10 @@ final class RBMessageGenerator {
private static func generateMessage(for epoch: RBEpoch, ntpTimestamp: Int) throws -> Data {
guard let ecc = Data(base64Encoded: epoch.ecc) else {
throw NSError.localizedError(message: "Malformed ECC in epoch", code: 0)
throw NSError.rbLocalizedError(message: "Malformed ECC in epoch", code: 0)
}
guard let ebid = Data(base64Encoded: epoch.ebid) else {
throw NSError.localizedError(message: "Malformed EBID in epoch", code: 0)
throw NSError.rbLocalizedError(message: "Malformed EBID in epoch", code: 0)
}
let time: UInt16 = UInt16(truncating: NSNumber(integerLiteral: ntpTimestamp)).bigEndian
let data: Data = withUnsafeBytes(of: time) { Data($0) }
......@@ -46,7 +46,7 @@ final class RBMessageGenerator {
private static func generateStatusMessageMAC(key: Data, epoch: RBEpoch, timeData: Data) throws -> Data {
guard let ebid = Data(base64Encoded: epoch.ebid) else {
throw NSError.localizedError(message: "Malformed EBID in epoch", code: 0)
throw NSError.rbLocalizedError(message: "Malformed EBID in epoch", code: 0)
}
let totalMessage: Data = Data([RBConstants.Prefix.c2]) + ebid + timeData
return totalMessage.hmac(key: key)
......@@ -62,7 +62,7 @@ final class RBMessageGenerator {
private static func generateUnregisterMessageMAC(key: Data, epoch: RBEpoch, timeData: Data) throws -> Data {
guard let ebid = Data(base64Encoded: epoch.ebid) else {
throw NSError.localizedError(message: "Malformed EBID in epoch", code: 0)
throw NSError.rbLocalizedError(message: "Malformed EBID in epoch", code: 0)
}
let totalMessage: Data = Data([RBConstants.Prefix.c3]) + ebid + timeData
return totalMessage.hmac(key: key)
......@@ -78,7 +78,7 @@ final class RBMessageGenerator {
private static func generateDeleteExposureHistoryMessageMAC(key: Data, epoch: RBEpoch, timeData: Data) throws -> Data {
guard let ebid = Data(base64Encoded: epoch.ebid) else {
throw NSError.localizedError(message: "Malformed EBID in epoch", code: 0)
throw NSError.rbLocalizedError(message: "Malformed EBID in epoch", code: 0)
}
let totalMessage: Data = Data([RBConstants.Prefix.c4]) + ebid + timeData
return totalMessage.hmac(key: key)
......
......@@ -12,8 +12,8 @@ import UIKit
struct RBDeleteExposureHistoryMessage {
var ebid: String
var time: String
var mac: String
let ebid: String
let time: String
let mac: String
}
......@@ -12,8 +12,8 @@ import UIKit
struct RBEpoch: RBStorable {
var id: Int
var ebid: String
var ecc: String
let id: Int
let ebid: String
let ecc: String
}
......@@ -12,12 +12,12 @@ import UIKit
struct RBLocalProximity {
var ecc: String
var ebid: String
var mac: String
var timeFromHelloMessage: UInt16
var timeCollectedOnDevice: Int
var rssiRaw: Int
var rssiCalibrated: Int
let ecc: String
let ebid: String
let mac: String
let timeFromHelloMessage: UInt16
let timeCollectedOnDevice: Int
let rssiRaw: Int
let rssiCalibrated: Int
}
......@@ -12,9 +12,9 @@ import UIKit
struct RBReceivedProximity {
var data: Data
var timeCollectedOnDevice: Int
var rssiRaw: Int
var rssiCalibrated: Int
let data: Data
let timeCollectedOnDevice: Int
let rssiRaw: Int
let rssiCalibrated: Int
}
......@@ -12,8 +12,8 @@ import UIKit
struct RBRegisterResponse {
var key: String
var epochs: [RBEpoch]
var timeStart: Int
let key: String
let epochs: [RBEpoch]
let timeStart: Int
}
......@@ -12,8 +12,8 @@ import UIKit
struct RBStatusMessage {
var ebid: String
var time: String
var mac: String
let ebid: String
let time: String
let mac: String
}
......@@ -9,8 +9,8 @@ import UIKit
struct RBStatusResponse {
var atRisk: Bool
var lastExposureTimeFrame: Int?
var epochs: [RBEpoch]
let atRisk: Bool
let lastExposureTimeFrame: Int?
let epochs: [RBEpoch]
}
......@@ -12,8 +12,8 @@ import UIKit
struct RBUnregisterMessage {
var ebid: String
var time: String
var mac: String
let ebid: String
let time: String
let mac: String
}
......@@ -14,7 +14,7 @@ protocol RBBluetooth {
func start(helloMessageCreationHandler: @escaping () -> Data,
ebidExtractionHandler: @escaping (_ data: Data) -> Data,
didReceiveProximity: @escaping (_ proximities: [RBReceivedProximity]) -> ())
didReceiveProximity: @escaping (_ proximity: RBReceivedProximity) -> ())
func stop()
}
......@@ -35,7 +35,7 @@ protocol RBStorage {
func isProximityActivated() -> Bool
// MARK: - Local Proximity -
func save(localProximities: [RBLocalProximity])
func save(localProximity: RBLocalProximity)
func getLocalProximityList() -> [RBLocalProximity]
// MARK: - Status: isAtRisk -
......@@ -54,13 +54,9 @@ protocol RBStorage {
func save(isSick: Bool)
func isSick() -> Bool
// MARK: - Positive to symptoms -
func save(positiveToSymptoms: Bool?)
func positiveToSymptoms() -> Bool?
// MARK: - Data cleraing -
func clearLocalEpochs()
func clearLocalProximityList()
func clearAll()
func clearAll(includingDBKey: Bool)
}
......@@ -37,10 +37,7 @@ final class RBManager {
set { storage.saveLastStatusReceivedDate(newValue) }
}
var currentEpoch: RBEpoch? { storage.getCurrentEpoch() }
var localProximityList: [RBLocalProximity] {
get { storage.getLocalProximityList() }
set { storage.save(localProximities: newValue) }
}
var localProximityList: [RBLocalProximity] { storage.getLocalProximityList() }
func start(server: RBServer, storage: RBStorage, bluetooth: RBBluetooth) {
self.server = server
......@@ -69,26 +66,22 @@ final class RBManager {
}
}, ebidExtractionHandler: { helloMessage -> Data in
RBMessageParser.getEbid(from: helloMessage) ?? Data()
}, didReceiveProximity: { [weak self] receivedProximities in
let localProximities: [RBLocalProximity] = receivedProximities.compactMap {
let eccString: String? = RBMessageParser.getEcc(from: $0.data)?.base64EncodedString()
let ebidString: String? = RBMessageParser.getEbid(from: $0.data)?.base64EncodedString()
let timeInt: UInt16? = RBMessageParser.getTime(from: $0.data)
let macString: String? = RBMessageParser.getMac(from: $0.data)?.base64EncodedString()
guard let ecc = eccString, let ebid = ebidString, let time = timeInt, let mac = macString else {
print("Proximity message ignored because it is malformed.")
return nil
}
let localProximity: RBLocalProximity = RBLocalProximity(ecc: ecc,
ebid: ebid,
mac: mac,
timeFromHelloMessage: time,
timeCollectedOnDevice: $0.timeCollectedOnDevice,
rssiRaw: $0.rssiRaw,
rssiCalibrated: $0.rssiCalibrated)
return localProximity
}, didReceiveProximity: { [weak self] receivedProximity in
let eccString: String? = RBMessageParser.getEcc(from: receivedProximity.data)?.base64EncodedString()
let ebidString: String? = RBMessageParser.getEbid(from: receivedProximity.data)?.base64EncodedString()
let timeInt: UInt16? = RBMessageParser.getTime(from: receivedProximity.data)
let macString: String? = RBMessageParser.getMac(from: receivedProximity.data)?.base64EncodedString()
guard let ecc = eccString, let ebid = ebidString, let time = timeInt, let mac = macString else {
return
}
self?.storage.save(localProximities: localProximities)
let localProximity: RBLocalProximity = RBLocalProximity(ecc: ecc,
ebid: ebid,
mac: mac,
timeFromHelloMessage: time,
timeCollectedOnDevice: receivedProximity.timeCollectedOnDevice,
rssiRaw: receivedProximity.rssiRaw,
rssiCalibrated: receivedProximity.rssiCalibrated)
self?.storage.save(localProximity: localProximity)
})
}
......@@ -99,20 +92,16 @@ final class RBManager {
private func loadKey() {
if let key = storage.getKey() {
ka = key
print("Storage - Shared Key loaded")
} else {
print("Storage - No shared key to load")
}
}
private func wipeKey() {
ka?.wipe()
ka?.wipeData()
}
@objc private func applicationWillTerminate() {
wipeKey()
storage.stop()
print("Keys wiping - Did wipe shared key and db key")
}
}
......@@ -122,11 +111,11 @@ extension RBManager {
func status(_ completion: @escaping (_ error: Error?) -> ()) {
guard let ka = ka else {
completion(NSError.localizedError(message: "No key found to make request", code: 0))
completion(NSError.rbLocalizedError(message: "No key found to make request", code: 0))
return
}
guard let epoch = storage.getCurrentEpoch() else {
completion(NSError.localizedError(message: "No epoch found to make request", code: 0))
completion(NSError.rbLocalizedError(message: "No epoch found to make request", code: 0))
return
}
do {
......@@ -199,11 +188,11 @@ extension RBManager {
return
}
guard let ka = ka else {
completion(NSError.localizedError(message: "No key found to make request", code: 0))
completion(NSError.rbLocalizedError(message: "No key found to make request", code: 0))
return
}
guard let epoch = storage.getCurrentEpoch() else {
completion(NSError.localizedError(message: "No epoch found to make request", code: 0))
completion(NSError.rbLocalizedError(message: "No epoch found to make request", code: 0))
return
}
do {
......@@ -224,17 +213,17 @@ extension RBManager {
func deleteExposureHistory(_ completion: @escaping (_ error: Error?) -> ()) {
guard let ka = ka else {
completion(NSError.localizedError(message: "No key found to make request", code: 0))
completion(NSError.rbLocalizedError(message: "No key found to make request", code: 0))
return
}
guard let epoch = storage.getCurrentEpoch() else {
completion(NSError.localizedError(message: "No epoch found to make request", code: 0))
completion(NSError.rbLocalizedError(message: "No epoch found to make request", code: 0))
return
}
do {
let ntpTimestamp: Int = Int(Date().timeIntervalSince1900)
let statusMessage: RBDeleteExposureHistoryMessage = try RBMessageGenerator.generateDeleteExposureHistoryMessage(for: epoch, ntpTimestamp: ntpTimestamp, key: ka)
server.unregister(ebid: statusMessage.ebid, time: statusMessage.time, mac: statusMessage.mac, completion: { error in
server.deleteExposureHistory(ebid: statusMessage.ebid, time: statusMessage.time, mac: statusMessage.mac, completion: { error in
if let error = error {
completion(error)
} else {
......@@ -260,12 +249,12 @@ extension RBManager {
}
func clearAllLocalData() {
storage.clearAll()
storage.clearAll(includingDBKey: false)
clearKey()
}
func clearKey() {
ka?.wipe()
ka?.wipeData()
ka = nil
}
......@@ -275,7 +264,7 @@ extension RBManager {
private func processRegisterResponse(_ response: RBRegisterResponse) throws {
guard let data = Data(base64Encoded: response.key) else {
throw NSError.localizedError(message: "The provided key is not a valid base64 string", code: 0)
throw NSError.rbLocalizedError(message: "The provided key is not a valid base64 string", code: 0)
}
storage.save(key: data)
ka = data
......@@ -283,7 +272,6 @@ extension RBManager {
if !response.epochs.isEmpty {
clearLocalEpochs()
storage.save(epochs: response.epochs)
print("Stored \(response.epochs.count) epochs")
}
}
......@@ -293,7 +281,6 @@ extension RBManager {
if !response.epochs.isEmpty {
clearLocalEpochs()
storage.save(epochs: response.epochs)
print("Stored \(response.epochs.count) epochs")
}
lastStatusReceivedDate = Date()
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment