/// <summary> /// This method does a simple validation of keys that might be obtained from the operating system. /// Some actions by user, may cause wrond TEKs being generated and obtained from OS, e.g., manually changing the date. /// Xamarin representation of TEKs does not take care of such things so we do it in this method. /// The method will return a list with only valid keys. /// /// These are the factors that make a key upload invalid according to Apple at /// https://developer.apple.com/documentation/exposurenotification/setting_up_an_exposure_notification_server: /// 1. RollingStart is not unique for each of the user's keys /// 2. There are gaps in the key validity periods for a user /// (they say "gaps in ENIntervalNumber", but I think this is a more correct way of saying what they mean) /// 3. There are keys with overlapping validity periods /// 4. The period of time covered exceeds 14 days /// 5. RollingPeriod is not 1 day /// </summary> /// <param name="temporaryExposureKeys"></param> /// <returns></returns> public static List <ExposureKeyModel> CreateAValidListOfTemporaryExposureKeys(IEnumerable <ExposureKeyModel> temporaryExposureKeys) { List <ExposureKeyModel> validListOfTeks = temporaryExposureKeys.ToList(); // Satisfy criterion 1. If there are several keys with the same RollingStart, keep only 1 int i = 0; while (i < validListOfTeks.Count) { ExposureKeyModel leftTek = validListOfTeks[i]; // Remove all duplicates to the right of the key at i int j = validListOfTeks.Count - 1; while (j > i) { ExposureKeyModel rightTek = validListOfTeks[j]; if (leftTek.RollingStart == rightTek.RollingStart) { validListOfTeks.RemoveAt(j); } j--; } i++; } // Satisfy criterion 2. Iterate backwards in time and if the next key is not 1 day before the previous key // take what we have iterated over so far // Sort from newest to oldest validListOfTeks.Sort((x, y) => y.RollingStart.CompareTo(x.RollingStart)); for (int k = 0; k < validListOfTeks.Count - 1; k++) { if (validListOfTeks[k + 1].RollingStart != validListOfTeks[k].RollingStart.AddDays(-1)) { validListOfTeks = validListOfTeks.Take(k + 1).ToList(); break; } } // Criterion 3 will be satisfied. We now have unique RollingStarts and each key is 1 day from the next. Criterion 3 will // then be satisfied when we satisfy criterion 5 below // Satisfy criterion 4. If we have more than 14 keys, only take 14 if (validListOfTeks.Count > 14) { validListOfTeks = validListOfTeks.Take(14).ToList(); } // Satisfy criterion 5 by setting RollingDuration to 1 day foreach (ExposureKeyModel tek in validListOfTeks) { tek.RollingDuration = new TimeSpan(1, 0, 0, 0); } return(validListOfTeks); }
private bool TeksAreEqual(ExposureKeyModel tek1, ExposureKeyModel tek2) { return (tek1.Key == tek2.Key && tek1.RollingDuration == tek2.RollingDuration && tek1.RollingStart == tek2.RollingStart && tek1.TransmissionRiskLevel == tek2.TransmissionRiskLevel); }
// True iff. container contains a key with same value as the given tek. Not looking at object addresses private bool ContainsTek(ExposureKeyModel tek, IEnumerable <ExposureKeyModel> teks) { foreach (ExposureKeyModel containedTek in teks) { if (TeksAreEqual(containedTek, tek)) { return(true); } } return(false); }
public void createAValidListOfTemporaryExposureKeys_HaveDateGap_OnlyNewestShouldBeKept() { // Create keys ExposureKeyModel tek1 = new ExposureKeyModel(new byte[1], june1, TimeSpan.FromDays(1), RiskLevel.Medium); ExposureKeyModel tek2 = new ExposureKeyModel(new byte[2], june1.AddDays(1), TimeSpan.FromDays(1), RiskLevel.Medium); ExposureKeyModel tek3 = new ExposureKeyModel(new byte[3], june1.AddDays(3), TimeSpan.FromDays(1), RiskLevel.Medium); // Process a list of copies IEnumerable <ExposureKeyModel> temporaryExposureKeys = new List <ExposureKeyModel>() { CopyTek(tek1), CopyTek(tek2), CopyTek(tek3) }; IEnumerable <ExposureKeyModel> processedKeys = UploadDiagnosisKeysHelper.CreateAValidListOfTemporaryExposureKeys(temporaryExposureKeys); // Only tek3 should be left Assert.Single(processedKeys); Assert.True(ContainsTek(tek3, processedKeys)); }
public void createAValidListOfTemporaryExposureKeys_HaveMultipleWithSameDate_OnlyOneWithEachDateShouldBeKept() { // Create keys ExposureKeyModel tek1 = new ExposureKeyModel(new byte[1], june1, TimeSpan.FromDays(1), RiskLevel.Medium); ExposureKeyModel tek2 = new ExposureKeyModel(new byte[2], june1, TimeSpan.FromDays(1), RiskLevel.Medium); ExposureKeyModel tek3 = new ExposureKeyModel(new byte[3], june1.AddDays(1), TimeSpan.FromDays(1), RiskLevel.Medium); // Process a list of copies IEnumerable <ExposureKeyModel> temporaryExposureKeys = new List <ExposureKeyModel>() { CopyTek(tek1), CopyTek(tek2), CopyTek(tek3) }; IEnumerable <ExposureKeyModel> processedKeys = UploadDiagnosisKeysHelper.CreateAValidListOfTemporaryExposureKeys(temporaryExposureKeys); // The only difference should be that tek2 is not contained in the result Assert.Equal(2, processedKeys.Count()); Assert.True(ContainsTek(tek1, processedKeys)); Assert.True(ContainsTek(tek3, processedKeys)); }
public void createAValidListOfTemporaryExposureKeys_HaveBadRollingDurations_RollingDurationsShouldBeSetToOneDay() { // Create keys ExposureKeyModel tek1 = new ExposureKeyModel(new byte[1], june1, TimeSpan.FromDays(0), RiskLevel.Medium); ExposureKeyModel tek2 = new ExposureKeyModel(new byte[2], june1.AddDays(1), TimeSpan.FromDays(10), RiskLevel.Medium); ExposureKeyModel tek3 = new ExposureKeyModel(new byte[3], june1.AddDays(2), TimeSpan.FromDays(-10), RiskLevel.Medium); // Process a list of copies IEnumerable <ExposureKeyModel> temporaryExposureKeys = new List <ExposureKeyModel>() { CopyTek(tek1), CopyTek(tek2), CopyTek(tek3) }; IEnumerable <ExposureKeyModel> processedKeys = UploadDiagnosisKeysHelper.CreateAValidListOfTemporaryExposureKeys(temporaryExposureKeys); // RollingDurations should be 1 day foreach (ExposureKeyModel tek in processedKeys) { Assert.Equal(TimeSpan.FromDays(1), tek.RollingDuration); } }
public async void createAValidListOfTemporaryExposureKeys_HaveDateGap_AllShouldBeKept() { SystemTime.ResetDateTime(); // Create keys ExposureKeyModel tek1 = new ExposureKeyModel(new byte[1], SystemTime.Now(), TimeSpan.FromDays(1), RiskLevel.Medium); ExposureKeyModel tek2 = new ExposureKeyModel(new byte[2], SystemTime.Now().AddDays(-1), TimeSpan.FromDays(1), RiskLevel.Medium); ExposureKeyModel tek3 = new ExposureKeyModel(new byte[3], SystemTime.Now().AddDays(-3), TimeSpan.FromDays(1), RiskLevel.Medium); // Process a list of copies IEnumerable <ExposureKeyModel> temporaryExposureKeys = new List <ExposureKeyModel>() { CopyTek(tek1), CopyTek(tek2), CopyTek(tek3) }; IEnumerable <ExposureKeyModel> processedKeys = UploadDiagnosisKeysHelper.CreateAValidListOfTemporaryExposureKeys(temporaryExposureKeys); // No keys should be filtered out Assert.Equal(processedKeys.Count(), temporaryExposureKeys.Count()); Assert.True(ContainsTek(tek3, processedKeys)); Assert.False((await _logManager.GetLogs(10)).Any()); }
public void createAValidListOfTemporaryExposureKeys_HaveMultipleWithSameDate_AllShouldBeKept() { SystemTime.ResetDateTime(); // Create keys ExposureKeyModel tek1 = new ExposureKeyModel(new byte[1], SystemTime.Now(), TimeSpan.FromDays(0.7), RiskLevel.Medium); ExposureKeyModel tek2 = new ExposureKeyModel(new byte[2], SystemTime.Now(), TimeSpan.FromDays(0.3), RiskLevel.Medium); ExposureKeyModel tek3 = new ExposureKeyModel(new byte[3], SystemTime.Now().AddDays(-1), TimeSpan.FromDays(1), RiskLevel.Medium); // Process a list of copies IEnumerable <ExposureKeyModel> temporaryExposureKeys = new List <ExposureKeyModel>() { CopyTek(tek1), CopyTek(tek2), CopyTek(tek3) }; IEnumerable <ExposureKeyModel> processedKeys = UploadDiagnosisKeysHelper.CreateAValidListOfTemporaryExposureKeys(temporaryExposureKeys); // No keys should be filtered out Assert.True(ContainsTek(tek1, processedKeys)); Assert.True(ContainsTek(tek2, processedKeys)); Assert.True(ContainsTek(tek3, processedKeys)); }
private ExposureKeyModel CopyTek(ExposureKeyModel tek) { return(new ExposureKeyModel(tek.Key, tek.RollingStart, tek.RollingDuration, tek.TransmissionRiskLevel)); }
public async void calculateTransmissionRiskbasedOnDateDifference() { // Create keys with different dates ExposureKeyModel tekminus3 = new ExposureKeyModel(new byte[1], june1.AddDays(-3), TimeSpan.FromDays(1), RiskLevel.Invalid); ExposureKeyModel tekminus2 = new ExposureKeyModel(new byte[1], june1.AddDays(-2), TimeSpan.FromDays(1), RiskLevel.Invalid); ExposureKeyModel tekminus1 = new ExposureKeyModel(new byte[1], june1.AddDays(-1), TimeSpan.FromDays(1), RiskLevel.Invalid); ExposureKeyModel tek2 = new ExposureKeyModel(new byte[1], june1.AddDays(2), TimeSpan.FromDays(1), RiskLevel.Invalid); ExposureKeyModel tek3 = new ExposureKeyModel(new byte[1], june1.AddDays(3), TimeSpan.FromDays(1), RiskLevel.Invalid); ExposureKeyModel tek4 = new ExposureKeyModel(new byte[1], june1.AddDays(4), TimeSpan.FromDays(1), RiskLevel.Invalid); ExposureKeyModel tek5 = new ExposureKeyModel(new byte[1], june1.AddDays(5), TimeSpan.FromDays(1), RiskLevel.Invalid); ExposureKeyModel tek6 = new ExposureKeyModel(new byte[1], june1.AddDays(6), TimeSpan.FromDays(1), RiskLevel.Invalid); ExposureKeyModel tek7 = new ExposureKeyModel(new byte[1], june1.AddDays(7), TimeSpan.FromDays(1), RiskLevel.Invalid); ExposureKeyModel tek8 = new ExposureKeyModel(new byte[1], june1.AddDays(8), TimeSpan.FromDays(1), RiskLevel.Invalid); ExposureKeyModel tek9 = new ExposureKeyModel(new byte[1], june1.AddDays(9), TimeSpan.FromDays(1), RiskLevel.Invalid); ExposureKeyModel tek10 = new ExposureKeyModel(new byte[1], june1.AddDays(10), TimeSpan.FromDays(1), RiskLevel.Invalid); ExposureKeyModel tek11 = new ExposureKeyModel(new byte[1], june1.AddDays(11), TimeSpan.FromDays(1), RiskLevel.Invalid); ExposureKeyModel tek12 = new ExposureKeyModel(new byte[1], june1.AddDays(12), TimeSpan.FromDays(1), RiskLevel.Invalid); // Process a list of copies IEnumerable <ExposureKeyModel> temporaryExposureKeys = new List <ExposureKeyModel>() { tek2, tek3, tek4, tek5, tek6, tek7, tek8, tek9, tek10, tek11, tek12 }; IEnumerable <ExposureKeyModel> processedKeys = UploadDiagnosisKeysHelper.CreateAValidListOfTemporaryExposureKeys(temporaryExposureKeys); List <ExposureKeyModel> validKeys = UploadDiagnosisKeysHelper.CreateAValidListOfTemporaryExposureKeys(processedKeys); List <ExposureKeyModel> resultKeys = UploadDiagnosisKeysHelper.SetTransmissionRiskLevel(validKeys, MiBaDate); for (int i = 1; i < 11; i++) { if (i == 0) { Assert.Equal("Highest", resultKeys[i].TransmissionRiskLevel.ToString()); } if (i > 0 && i < 3) { Assert.Equal("VeryHigh", resultKeys[i].TransmissionRiskLevel.ToString()); } if (i > 2 && i < 5) { Assert.Equal("High", resultKeys[i].TransmissionRiskLevel.ToString()); } if (i > 4 && i < 9) { Assert.Equal("MediumHigh", resultKeys[i].TransmissionRiskLevel.ToString()); } if (i > 8) { Assert.Equal("Medium", resultKeys[i].TransmissionRiskLevel.ToString()); } } IEnumerable <ExposureKeyModel> negativeDifferenceExposureKeys = new List <ExposureKeyModel>() { tekminus1, tekminus2, tekminus3 }; IEnumerable <ExposureKeyModel> processedNegativeDifferenceExposureKeys = UploadDiagnosisKeysHelper.CreateAValidListOfTemporaryExposureKeys(negativeDifferenceExposureKeys); List <ExposureKeyModel> validNegativeDifferenceExposureKeys = UploadDiagnosisKeysHelper.CreateAValidListOfTemporaryExposureKeys(processedNegativeDifferenceExposureKeys); List <ExposureKeyModel> resultKeysNegativeDifference = UploadDiagnosisKeysHelper.SetTransmissionRiskLevel(validNegativeDifferenceExposureKeys, MiBaDate); for (int i = 1; i < 11; i++) { if (i == 0) { Assert.Equal("Medium", resultKeysNegativeDifference[i].TransmissionRiskLevel.ToString()); } if (i == 1) { Assert.Equal("MediumLow", resultKeysNegativeDifference[i].TransmissionRiskLevel.ToString()); } if (i == 2) { Assert.Equal("Low", resultKeysNegativeDifference[i].TransmissionRiskLevel.ToString()); } } }