COVIDSafe code from version 1.14 (#27)

This commit is contained in:
COVIDSafe Support 2020-11-09 16:51:00 -08:00 committed by GitHub
parent 3ea83834f5
commit cf93ea43c0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 370 additions and 141 deletions

View file

@ -7,6 +7,7 @@
import Foundation
import Alamofire
import KeychainSwift
final class CovidServerTrustManager: ServerTrustManager {
override func serverTrustEvaluator(forHost host: String) throws -> ServerTrustEvaluating? {
@ -45,3 +46,44 @@ enum APIError: Error {
case ExpireSession
case ServerError
}
struct CovidSafeErrorResponse: Decodable {
let message: String?
}
enum CovidSafeAPIError: Error {
case RequestError
case ResponseError
case ServerError
case TokenExpiredError
case UnknownError
}
class CovidSafeAuthenticatedAPI {
static func authenticatedHeaders() throws -> HTTPHeaders? {
let keychain = KeychainSwift()
guard let token = keychain.get("JWT_TOKEN") else {
throw CovidSafeAPIError.TokenExpiredError
}
let headers: HTTPHeaders = [
"Authorization": "Bearer \(token)"
]
return headers
}
static func processUnauthorizedError(_ data: Data) -> CovidSafeAPIError {
var errorType = CovidSafeAPIError.RequestError
do {
let errorResponse = try JSONDecoder().decode(CovidSafeErrorResponse.self, from: data)
if errorResponse.message == "Unauthorized" {
errorType = .TokenExpiredError
}
} catch {
// unable to parse response
errorType = .ResponseError
}
return errorType
}
}

View file

@ -7,25 +7,20 @@
import Foundation
import Alamofire
import KeychainSwift
class GetTempIdAPI {
class GetTempIdAPI: CovidSafeAuthenticatedAPI {
private static let apiVersion = 2
static func getTempId(completion: @escaping (String?, Int?, Swift.Error?) -> Void) {
let keychain = KeychainSwift()
static func getTempId(completion: @escaping (String?, Int?, Swift.Error?, CovidSafeAPIError?) -> Void) {
guard let apiHost = PlistHelper.getvalueFromInfoPlist(withKey: "API_Host", plistName: "CovidSafe-config") else {
return
}
guard let token = keychain.get("JWT_TOKEN") else {
completion(nil, nil, nil)
guard let headers = try? authenticatedHeaders() else {
completion(nil, nil, nil, .TokenExpiredError)
return
}
let headers: HTTPHeaders = [
"Authorization": "Bearer \(token)"
]
let params = [
"version" : apiVersion
]
@ -37,9 +32,17 @@ class GetTempIdAPI {
switch response.result {
case .success:
guard let tempIdResponse = response.value else { return }
completion(tempIdResponse.tempId, tempIdResponse.expiryTime, nil)
completion(tempIdResponse.tempId, tempIdResponse.expiryTime, nil, nil)
case let .failure(error):
completion(nil, nil, error)
guard let statusCode = response.response?.statusCode else {
completion(nil, nil, error, .UnknownError)
return
}
if statusCode == 401, let respData = response.data {
completion(nil, nil, error, processUnauthorizedError(respData))
return
}
completion(nil, nil, error, .ServerError)
}
}
}

View file

@ -7,20 +7,19 @@
import Foundation
import Alamofire
import KeychainSwift
class MessageAPI {
class MessageAPI: CovidSafeAuthenticatedAPI {
static let keyLastApiUpdate = "keyLastApiUpdate"
static let keyLastVersionChecked = "keyLastVersionChecked"
static func getMessagesIfNeeded(completion: @escaping (MessageResponse?, MessageAPIError?) -> Void) {
static func getMessagesIfNeeded(completion: @escaping (MessageResponse?, CovidSafeAPIError?) -> Void) {
if shouldGetMessages() {
getMessages(completion: completion)
}
}
static func getMessages(completion: @escaping (MessageResponse?, MessageAPIError?) -> Void) {
static func getMessages(completion: @escaping (MessageResponse?, CovidSafeAPIError?) -> Void) {
guard let token = UserDefaults.standard.string(forKey: "deviceTokenForAPN") else {
completion(nil, .RequestError)
return
@ -82,20 +81,16 @@ class MessageAPI {
}
private static func getMessages(msgRequest: MessageRequest,
completion: @escaping (MessageResponse?, MessageAPIError?) -> Void) {
let keychain = KeychainSwift()
completion: @escaping (MessageResponse?, CovidSafeAPIError?) -> Void) {
guard let apiHost = PlistHelper.getvalueFromInfoPlist(withKey: "API_Host", plistName: "CovidSafe-config") else {
completion(nil, .RequestError)
return
}
guard let token = keychain.get("JWT_TOKEN") else {
completion(nil, .RequestError)
guard let headers = try? authenticatedHeaders() else {
completion(nil, .TokenExpiredError)
return
}
let headers: HTTPHeaders = [
"Authorization": "Bearer \(token)"
]
let preferredLanguages = Locale.preferredLanguages.count > 5 ? Locale.preferredLanguages[0...5].joined(separator: ",") : Locale.preferredLanguages.joined(separator: ",")
@ -138,11 +133,19 @@ class MessageAPI {
completion(nil, .UnknownError)
return
}
if (statusCode == 200) {
completion(nil, .ResponseError)
return
}
if statusCode == 401, let respData = response.data {
completion(nil, processUnauthorizedError(respData))
return
}
if (statusCode >= 400 && statusCode < 500) {
completion(nil, .RequestError)
return
}
completion(nil, .ServerError)
}
@ -183,10 +186,3 @@ struct Message: Decodable {
case destination
}
}
enum MessageAPIError: Error {
case RequestError
case ResponseError
case ServerError
case UnknownError
}

View file

@ -62,4 +62,5 @@ struct AuthResponse: Decodable {
protocol RegistrationHandler {
var registrationInfo: RegistrationRequest? { get set }
var reauthenticating: Bool { get set }
}

View file

@ -7,26 +7,21 @@
import Foundation
import Alamofire
import KeychainSwift
class StatisticsAPI {
class StatisticsAPI: CovidSafeAuthenticatedAPI {
static let keyCovidStatistics = "keyCovidStatistics"
static func getStatistics(completion: @escaping (StatisticsResponse?, MessageAPIError?) -> Void) {
let keychain = KeychainSwift()
static func getStatistics(completion: @escaping (StatisticsResponse?, CovidSafeAPIError?) -> Void) {
guard let apiHost = PlistHelper.getvalueFromInfoPlist(withKey: "API_Host", plistName: "CovidSafe-config") else {
completion(nil, .RequestError)
return
}
guard let token = keychain.get("JWT_TOKEN") else {
completion(nil, .RequestError)
guard let headers = try? authenticatedHeaders() else {
completion(nil, .TokenExpiredError)
return
}
let headers: HTTPHeaders = [
"Authorization": "Bearer \(token)"
]
CovidNetworking.shared.session.request("\(apiHost)/statistics",
method: .get,
@ -50,9 +45,17 @@ class StatisticsAPI {
}
if (statusCode == 200) {
completion(lastStats, .ResponseError)
return
}
if statusCode == 401, let respData = response.data {
completion(nil, processUnauthorizedError(respData))
return
}
if (statusCode >= 400 && statusCode < 500) {
completion(lastStats, .RequestError)
return
}
completion(lastStats, .ServerError)
}