Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

Fix/14454: Self-test: only one times warning within 24h allowed is blocking testing #4943

Original file line number Diff line number Diff line change
Expand Up @@ -693,14 +693,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate, CoronaWarnAppDelegate, Re
/// - App installation date
///
/// read values from the current store
let ppacEdusApiToken = store.ppacApiTokenEdus
let apiTokenPPAC = store.apiTokenPPAC
let installationDate = store.appInstallationDate

let newKey = try KeychainHelper().generateDatabaseKey(persistForKeychainKey: SecureStore.encryptionKeyKeychainKey)
store.wipeAll(key: newKey)

/// write excluded values back to the 'new' store
store.ppacApiTokenEdus = ppacEdusApiToken
store.apiTokenPPAC = apiTokenPPAC
store.appInstallationDate = installationDate
Analytics.collect(.submissionMetadata(.lastAppReset(Date())))
} catch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,17 +107,17 @@ final class DMSRSOptionsViewModel {
private func apiTokenStaticText() -> String {
"""

PPAC API Token SRS
\(store.ppacApiTokenSrs?.token ?? "No API Token generated yet")
PPAC API Token
\(store.apiTokenPPAC?.token ?? "No API Token generated yet")

PPAC API Token SRS Creation Date
\(createDateString(from: store.ppacApiTokenSrs?.timestamp))
PPAC API Token Creation Date
\(createDateString(from: store.apiTokenPPAC?.timestamp))

Previous PPAC API Token SRS
\(store.previousPpacApiTokenSrs?.token ?? "No API Token available")
Previous PPAC API Token
\(store.previousAPITokenPPAC?.token ?? "No API Token available")

Previous PPAC API Token SRS Creation Date
\(createDateString(from: store.previousPpacApiTokenSrs?.timestamp, fallback: "No Date available"))
Previous PPAC API Token Creation Date
\(createDateString(from: store.previousAPITokenPPAC?.timestamp, fallback: "No Date available"))

"""
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,25 +52,25 @@ final class DMPPCViewModel {

switch section {
case .ppacEdusApiToken:
let ppacEdusApiToken = store.ppacApiTokenEdus?.token ?? "no API EDUS Token generated yet"
return DMKeyValueCellViewModel(key: "API EDUS Token", value: ppacEdusApiToken)
let apiTokenPPAC = store.apiTokenPPAC?.token ?? "no API PPAC Token generated yet"
return DMKeyValueCellViewModel(key: "API PPAC Token", value: apiTokenPPAC)

case .ppacEdusApiTokenLastChange:
let creationDate: String
if let timestamp = store.ppacApiTokenEdus?.timestamp {
if let timestamp = store.apiTokenPPAC?.timestamp {
creationDate = DateFormatter.localizedString(from: timestamp, dateStyle: .medium, timeStyle: .medium)
} else {
creationDate = "unknown"
}
return DMKeyValueCellViewModel(key: "API EDUS Token creation date", value: creationDate)
return DMKeyValueCellViewModel(key: "API PPAC Token creation date", value: creationDate)

case .deviceToken:
let deviceTokenValue = deviceTokenText ?? "no device token created"
return DMKeyValueCellViewModel(key: "Device Token", value: deviceTokenValue)

case .generateAPIToken:
return DMButtonCellViewModel(
text: "Generate new API EDUS Token",
text: "Generate new API PPAC Token",
textColor: .white,
backgroundColor: .enaColor(for: .buttonPrimary),
action: { [weak self] in
Expand All @@ -93,7 +93,7 @@ final class DMPPCViewModel {
)
case .forceHTTPHeader:
return DMSwitchCellViewModel(
labelText: "Force API EDUS Token Authorization",
labelText: "Force API PPAC Token Authorization",
isOn: { [store] in
return store.forceAPITokenAuthorization
},
Expand All @@ -110,7 +110,7 @@ final class DMPPCViewModel {
private var lastKnownDeviceToken: Result<PPACToken, PPACError>?

private func generateppacEdusApiToken() {
guard (ppacService?.generateNewAPIEdusToken()) != nil else {
guard (ppacService?.generateNewAPITokenPPAC()) != nil else {
return
}
refreshTableView(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,12 +205,16 @@ class ExposureSubmissionCoordinatorModel {

case .success(let srsOTP):

isLoading(true)

// SUBMIT SRS EXPOSURE
self.exposureSubmissionService.submitSRSExposure(
submissionType: srsSubmissionType,
srsOTP: srsOTP
) { (submitSRSExposureResult: Result<Int?, ExposureSubmissionServiceError>) in

isLoading(false)

switch submitSRSExposureResult {

case .success(let cwaKeyTruncated):
Expand All @@ -223,11 +227,6 @@ class ExposureSubmissionCoordinatorModel {
// We continue the regular flow even if there are no keys collected.
case .preconditionError(.noKeysCollected):
onSuccess(nil)

// We don't show an error if the submission consent was not given, because we assume that the submission already happened in the background.
case .preconditionError(.noSubmissionConsent):
Log.info("Consent Not Given", log: .ui)
onSuccess(nil)

default:
Log.error("error: \(exposureSubmissionServiceError.localizedDescription)", log: .api)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ final class ErrorLogSubmissionService: ErrorLogSubmissionProviding {

private func authenticate(completion: @escaping ELSAuthenticationResponse) {
// first get ppac token for els (without divide time check)
ppacService.getPPACTokenELS({ [weak self] result in
ppacService.getAPITokenPPAC({ [weak self] result in
switch result {
case let .success(ppacToken):
Log.debug("Successfully retrieved for els a ppac token. Proceed for otp.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class FakeRequestService {

/// This method represents the fake Request for SRS OTP
func fakeSRSOTPServerRequest(completion: (() -> Void)? = nil) {
self.ppacService.getPPACTokenSRS { [weak self] result in
self.ppacService.getAPITokenPPAC { [weak self] result in
guard let self = self else {
Log.warning("[FakeRequestService] Could not get self, skipping fakeSRSOTPServerRequest call")
completion?()
Expand Down
72 changes: 13 additions & 59 deletions src/xcode/ENA/ENA/Source/Services/PPAccessControl/PPACService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,14 @@ import Foundation

protocol PrivacyPreservingAccessControl {
func getPPACTokenEDUS(_ completion: @escaping (Result<PPACToken, PPACError>) -> Void)
func getPPACTokenELS(_ completion: @escaping (Result<PPACToken, PPACError>) -> Void)
func getPPACTokenSRS(_ completion: @escaping (Result<PPACToken, PPACError>) -> Void)
func getAPITokenPPAC(_ completion: @escaping (Result<PPACToken, PPACError>) -> Void)
func checkSRSFlowPrerequisites(
minTimeSinceOnboardingInHours: Int,
minTimeBetweenSubmissionsInDays: Int,
completion: @escaping (Result<Void, SRSPreconditionError>) -> Void
)
#if !RELEASE
func generateNewAPIEdusToken() -> TimestampedToken
func generateNewAPIElsToken() -> TimestampedToken
func generateNewAPITokenPPAC() -> TimestampedToken
#endif
}

Expand Down Expand Up @@ -100,14 +98,6 @@ class PPACService: PrivacyPreservingAccessControl {
}
completion(.success(()))
}

func getPPACTokenSRS(_ completion: @escaping (Result<PPACToken, PPACError>) -> Void) {
deviceCheck.deviceToken(
apiToken: apiTokenSRS.token,
previousApiToken: store.previousPpacApiTokenSrs?.token,
completion: completion
)
}

func getPPACTokenEDUS(_ completion: @escaping (Result<PPACToken, PPACError>) -> Void) {

Expand All @@ -133,32 +123,26 @@ class PPACService: PrivacyPreservingAccessControl {
}

deviceCheck.deviceToken(
apiToken: apiTokenEDUS.token,
previousApiToken: store.previousPpacApiTokenEdus?.token,
apiToken: apiTokenPPAC.token,
previousApiToken: store.previousAPITokenPPAC?.token,
completion: completion
)
}

func getPPACTokenELS(_ completion: @escaping (Result<PPACToken, PPACError>) -> Void) {
func getAPITokenPPAC(_ completion: @escaping (Result<PPACToken, PPACError>) -> Void) {
// no device time checks for ELS
deviceCheck.deviceToken(
apiToken: apiTokenELS.token,
previousApiToken: store.previousPpacApiTokenEls?.token,
apiToken: apiTokenPPAC.token,
previousApiToken: store.previousAPITokenPPAC?.token,
completion: completion
)
}

#if !RELEASE
// needed to make it possible to get called from the developer menu
func generateNewAPIEdusToken() -> TimestampedToken {
let token = generateAndStoreFreshAPIToken()
store.ppacApiTokenEdus = token
return token
}

func generateNewAPIElsToken() -> TimestampedToken {
func generateNewAPITokenPPAC() -> TimestampedToken {
let token = generateAndStoreFreshAPIToken()
store.ppacApiTokenEls = token
store.apiTokenPPAC = token
return token
}
#endif
Expand All @@ -169,50 +153,20 @@ class PPACService: PrivacyPreservingAccessControl {
private let store: Store

/// will return the current API Token and create a new one if needed
private var apiTokenEDUS: TimestampedToken {
private var apiTokenPPAC: TimestampedToken {
let today = Date()
/// check if we already have a token and if it was created in this month / year
guard let storedToken = store.ppacApiTokenEdus,
guard let storedToken = store.apiTokenPPAC,
storedToken.timestamp.isEqual(to: today, toGranularity: .month),
storedToken.timestamp.isEqual(to: today, toGranularity: .year)
else {
store.previousPpacApiTokenEdus = store.ppacApiTokenEdus
store.previousAPITokenPPAC = store.apiTokenPPAC
let newToken = generateAndStoreFreshAPIToken()
store.ppacApiTokenEdus = newToken
store.apiTokenPPAC = newToken
return newToken
}
return storedToken
}

private var apiTokenELS: TimestampedToken {
let today = Date()
/// check if we already have a token and if it was created in this month / year
guard let storedToken = store.ppacApiTokenEls,
storedToken.timestamp.isEqual(to: Date(), toGranularity: .month),
storedToken.timestamp.isEqual(to: today, toGranularity: .year)
else {
store.previousPpacApiTokenEls = store.ppacApiTokenEls
let newToken = generateAndStoreFreshAPIToken()
store.ppacApiTokenEls = newToken
return newToken
}
return storedToken
}

private var apiTokenSRS: TimestampedToken {
let today = Date()
/// check if we already have a token and if it was created in this month / year
guard let storedToken = store.ppacApiTokenSrs,
storedToken.timestamp.isEqual(to: today, toGranularity: .month),
storedToken.timestamp.isEqual(to: today, toGranularity: .year)
else {
store.previousPpacApiTokenSrs = store.ppacApiTokenSrs
let newToken = generateAndStoreFreshAPIToken()
store.ppacApiTokenSrs = newToken
return newToken
}
return storedToken
}

/// generate a new API Token and store it
private func generateAndStoreFreshAPIToken() -> TimestampedToken {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ class PPACServiceMock: PPACService {
completion(.success(Self.ppacTokenMock))
}

override func getPPACTokenELS(_ completion: @escaping (Result<PPACToken, PPACError>) -> Void) {
completion(.success(Self.ppacTokenMock))
}

override func getPPACTokenSRS(_ completion: @escaping (Result<PPACToken, PPACError>) -> Void) {
override func getAPITokenPPAC(_ completion: @escaping (Result<PPACToken, PPACError>) -> Void) {
completion(.success(Self.ppacTokenMock))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ class PPACServiceTest: CWATestCase {
switch result {
case let .success(ppaToken):
ppacExpectation.fulfill()
XCTAssertNotNil(store.ppacApiTokenEdus)
XCTAssertEqual(store.ppacApiTokenEdus?.token, ppaToken.apiToken)
XCTAssertNotNil(store.apiTokenPPAC)
XCTAssertEqual(store.apiTokenPPAC?.token, ppaToken.apiToken)

case .failure:
XCTFail("Unexpected error happened")
Expand All @@ -130,38 +130,38 @@ class PPACServiceTest: CWATestCase {

// WHEN
let ppacService = PPACService(store: store, deviceCheck: deviceCheck)
let timestampedToken = ppacService.generateNewAPIEdusToken()
let timestampedToken = ppacService.generateNewAPITokenPPAC()

// THEN
XCTAssertNotNil(store.ppacApiTokenEdus)
XCTAssertEqual(timestampedToken.timestamp, store.ppacApiTokenEdus?.timestamp)
XCTAssertEqual(timestampedToken.token, store.ppacApiTokenEdus?.token)
XCTAssertNotNil(store.apiTokenPPAC)
XCTAssertEqual(timestampedToken.timestamp, store.apiTokenPPAC?.timestamp)
XCTAssertEqual(timestampedToken.token, store.apiTokenPPAC?.token)
}

func testGIVEN_ValidStoredAPIToken_WHEN_generateAPITokenEdusb_THEN_NewTokenCreatedAndStored() throws {
func testGIVEN_ValidStoredAPIToken_WHEN_generateAPITokenEdus_THEN_NewTokenCreatedAndStored() throws {
// GIVEN
let store = MockTestStore()
let deviceCheck = PPACDeviceCheckMock(true, deviceToken: "iPhone")

let uuid = UUID().uuidString
let today = Date()
store.ppacApiTokenEdus = TimestampedToken(token: uuid, timestamp: today)
store.apiTokenPPAC = TimestampedToken(token: uuid, timestamp: today)

// WHEN
let ppacService = PPACService(store: store, deviceCheck: deviceCheck)
let timestampedToken = ppacService.generateNewAPIEdusToken()
let timestampedToken = ppacService.generateNewAPITokenPPAC()

// THEN
XCTAssertNotNil(store.ppacApiTokenEdus)
XCTAssertNotNil(store.apiTokenPPAC)
XCTAssertNotEqual(timestampedToken.timestamp, today)
XCTAssertNotEqual(timestampedToken.token, uuid)
XCTAssertEqual(timestampedToken.timestamp, store.ppacApiTokenEdus?.timestamp)
XCTAssertEqual(timestampedToken.token, store.ppacApiTokenEdus?.token)
XCTAssertEqual(timestampedToken.timestamp, store.apiTokenPPAC?.timestamp)
XCTAssertEqual(timestampedToken.token, store.apiTokenPPAC?.token)
}

// ELS

func testGIVEN_NoStoredPPACToken_WHEN_getPPACTokenEls_THEN_DeviceTokenIsReturned() {
func testGIVEN_NoStoredPPACToken_WHEN_getAPITokenPPAC_THEN_DeviceTokenIsReturned() {

// GIVEN
let store = MockTestStore()
Expand All @@ -172,10 +172,10 @@ class PPACServiceTest: CWATestCase {
let ppacService = PPACService(store: store, deviceCheck: deviceCheck)
var expectedResponse: PPACToken?

XCTAssertNil(store.ppacApiTokenEls)
XCTAssertNil(store.apiTokenPPAC)

// WHEN
ppacService.getPPACTokenELS { result in
ppacService.getAPITokenPPAC { result in
switch result {
case let .success(token):
expectedResponse = token
Expand All @@ -190,7 +190,7 @@ class PPACServiceTest: CWATestCase {
XCTAssertNotNil(expectedResponse)
}

func testGIVEN_StoredPPACToken_WHEN_getPPACTokenEls_THEN_DeviceTokenIsReturned() {
func testGIVEN_StoredPPACToken_WHEN_getAPITokenPPAC_THEN_DeviceTokenIsReturned() {

// GIVEN
let store = MockTestStore()
Expand All @@ -200,11 +200,11 @@ class PPACServiceTest: CWATestCase {

let ppacService = PPACService(store: store, deviceCheck: deviceCheck)

let existingApiTokenEls = TimestampedToken(token: "FakeToken", timestamp: Date())
store.ppacApiTokenEls = existingApiTokenEls
let existingAPITokenPPAC = TimestampedToken(token: "FakeToken", timestamp: Date())
store.apiTokenPPAC = existingAPITokenPPAC

// WHEN
ppacService.getPPACTokenELS { result in
ppacService.getAPITokenPPAC { result in
switch result {
case .success:
successExpectation.fulfill()
Expand All @@ -215,6 +215,6 @@ class PPACServiceTest: CWATestCase {

// THEN
waitForExpectations(timeout: .short)
XCTAssertEqual(store.ppacApiTokenEls?.token, existingApiTokenEls.token)
XCTAssertEqual(store.apiTokenPPAC?.token, existingAPITokenPPAC.token)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ final class SRSService: SRSServiceProviding {

func authenticate(completion: @escaping SRSAuthenticationResponse) {
// first get ppac token for SRS
self.ppacService.getPPACTokenSRS { [weak self] result in
self.ppacService.getAPITokenPPAC { [weak self] result in
guard let self = self else { return }
switch result {
case let .success(ppacToken):
Expand Down
Loading