Skip to content
Snippets Groups Projects
Commit e773c90d authored by Matthias Urhahn's avatar Matthias Urhahn
Browse files

Merge branch 'release/2.2.x' into release/2.3.x

parents 4ce27334 21c2473d
No related branches found
No related tags found
No related merge requests found
Showing
with 680 additions and 424 deletions
......@@ -493,47 +493,6 @@ jobs:
- store_artifacts:
path: /tmp/instrumentation_tests_device.zip
destination: zips/instrumentation_tests_device.zip
# Keep it until Firebase Test Lab proves reliability
device_screenshots:
macos:
xcode: "12.3.0"
resource_class: large
steps:
- checkout
- restore_cache:
key: gem-cache-v1-{{ arch }}-{{ checksum "Gemfile.lock" }}
- run: bundle check || bundle install --path vendor/bundle
- save_cache:
key: gem-cache-v1-{{ arch }}-{{ checksum "Gemfile.lock" }}
paths:
- vendor/bundle
- setup-android-macos
- restore-gradle-cache
- restore-android-build-cache-macos
- run-gradle-cmd:
desc: Build APKs for screenshots
cmd: >
:Corona-Warn-App:assembleDebug
:Corona-Warn-App:assembleAndroidTest
- save-gradle-cache
- save-android-build-cache-macos
- run-emulator-for-api:
apilevel: 29
- run:
name: Run fastlane screengrab
command: |
for i in {1..5}; do bundle exec fastlane screengrab && break || sleep 15; done
no_output_timeout: 30m
- kill-all-emulators
- store_artifacts:
path: fastlane/metadata/android
destination: screenshots
- compress-path:
input: ./fastlane/metadata/android
output: /tmp/device_screenshots.zip
- store_artifacts:
path: /tmp/device_screenshots.zip
destination: zips/device_screenshots.zip
firebase_screenshots:
resource_class: xlarge
......
......@@ -54,4 +54,8 @@ License: Apache-2.0
Files: Corona-Warn-App/src/main/res/font/roboto.ttf
Copyright: 2011 Google Inc.
License: Apache-2.0
Files: Corona-Warn-App/src/test/java/testhelpers/extensions/LiveDataTestUtil.kt
Copyright: 2019 The Android Open Source Project
License: Apache-2.0
\ No newline at end of file
......@@ -3,6 +3,7 @@ package de.rki.coronawarnapp.test.contactdiary.ui
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.View
import androidx.core.widget.TextViewCompat
import androidx.fragment.app.Fragment
import de.rki.coronawarnapp.R
import de.rki.coronawarnapp.databinding.FragmentTestContactDiaryBinding
......@@ -84,10 +85,10 @@ class ContactDiaryTestFragment :
text = duration.toContactDiaryFormat()
if (duration.millis == 0L) {
setBackgroundResource(R.drawable.contact_diary_duration_background_default)
setTextAppearance(R.style.bodyNeutral)
TextViewCompat.setTextAppearance(this, R.style.bodyNeutral)
} else {
setBackgroundResource(R.drawable.contact_diary_duration_background_selected)
setTextAppearance(R.style.body1)
TextViewCompat.setTextAppearance(this, R.style.body1)
}
}
}
......
......@@ -75,7 +75,7 @@ class DebugOptionsFragment : Fragment(R.layout.fragment_test_debugoptions), Auto
environmentPubkeyAppconfig.text = "AppConfigPubKey:\n${state.pubKeyAppConfig}"
}
}
vm.environmentChangeEvent.observe2(this) {
vm.environmentStateChange.observe2(this) {
showSnackBar("Environment changed to: $it\nForce stop & restart the app!")
}
}
......
package de.rki.coronawarnapp.test.debugoptions.ui
import androidx.lifecycle.asLiveData
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.environment.EnvironmentSetup
......@@ -7,25 +8,24 @@ import de.rki.coronawarnapp.environment.EnvironmentSetup.Type.Companion.toEnviro
import de.rki.coronawarnapp.test.debugoptions.ui.EnvironmentState.Companion.toEnvironmentState
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
import de.rki.coronawarnapp.util.ui.SingleLiveEvent
import de.rki.coronawarnapp.util.ui.smartLiveData
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
import kotlinx.coroutines.flow.MutableStateFlow
class DebugOptionsFragmentViewModel @AssistedInject constructor(
private val envSetup: EnvironmentSetup,
dispatcherProvider: DispatcherProvider
) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
val environmentState by smartLiveData {
envSetup.toEnvironmentState()
}
val environmentChangeEvent = SingleLiveEvent<EnvironmentSetup.Type>()
private val environmentStateFlow = MutableStateFlow(envSetup.toEnvironmentState())
val environmentState = environmentStateFlow.asLiveData(context = dispatcherProvider.Default)
val environmentStateChange = SingleLiveEvent<EnvironmentState>()
fun selectEnvironmentTytpe(type: String) {
environmentState.update {
envSetup.currentEnvironment = type.toEnvironmentType()
environmentChangeEvent.postValue(envSetup.currentEnvironment)
envSetup.toEnvironmentState()
envSetup.currentEnvironment = type.toEnvironmentType()
envSetup.toEnvironmentState().let {
environmentStateFlow.value = it
environmentStateChange.postValue(it)
}
}
......
......@@ -4,7 +4,7 @@
package="de.rki.coronawarnapp"
tools:ignore="LockedOrientationActivity">
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android" />
<uses-sdk tools:overrideLibrary="com.google.zxing.client.android,androidx.security" />
<uses-feature
android:name="android.hardware.bluetooth_le"
......
......@@ -77,7 +77,8 @@
<p>
Die Nutzung der App ist freiwillig. Es ist allein Ihre Entscheidung, ob Sie die App
installieren, welche App-Funktionen Sie nutzen und ob Sie Daten mit anderen teilen. Alle
App-Funktionen, die eine Weitergabe Ihrer personenbezogenen Daten an das RKI oder an andere
Haupt-Funktionen der App, die eine Weitergabe Ihrer personenbezogenen Daten an das RKI oder an
andere
Nutzer erfordern, holen vorher Ihr ausdrückliches Einverständnis ein. Falls Sie ein
Einverständnis nicht erteilen oder nachträglich zurücknehmen, entstehen Ihnen keine Nachteile.
</p>
......@@ -90,7 +91,7 @@
Falle von Gesundheitsdaten Art. 9 Abs. 2 lit. a DSGVO. Sie können ein einmal erteiltes
Einverständnis jederzeit wieder zurücknehmen (sogenanntes Widerrufsrecht). Weitere Informationen
zu Ihrem Widerrufsrecht finden Sie unter Punkt 12. Die Verarbeitung von Zugriffsdaten für die
Bereitstellung der täglichen Statistiken (siehe hierzu Punkt 6.e.) erfolgt im Rahmen der
Bereitstellung der täglichen Statistiken (siehe hierzu Punkt 6 f.) erfolgt im Rahmen der
Information der Öffentlichkeit durch das RKI gem. § 4 Abs. 4 BGA-NachfG auf Basis von Art. 6
Abs. 1 lit e. DSGVO i.V.m § 3 BDSG.
</p>
......@@ -109,14 +110,16 @@
verarbeitet werden. Das bedeutet, dass das System bei der Risiko-Ermittlung, der Warnung anderer
und dem Abruf des Testergebnisses keine Daten erfassen muss, die es dem RKI oder anderen Nutzern
ermöglichen, auf Ihre Identität, Ihren Namen, Ihren Standort oder andere persönliche Details zu
schließen. Eine Ausnahme gilt nur für die optionale Funktion „Schnelltest-Ergebnis nachweisen“,
mit der Sie eine auf Ihren Namen ausgestellte Bestätigung für negative Schnelltest-Ergebnisse
anzeigen lassen können (siehe hierzu Punkt 6 c.)
schließen. Eine Ausnahme gilt nur für die Funktion „Schnelltest-Ergebnis nachweisen“, mit der
Sie eine auf Ihren Namen ausgestellte Bestätigung für negative Schnelltest-Ergebnisse anzeigen
lassen können (siehe hierzu Punkt 6 c.)sowie die Funktion zum Anlegen eines
„Schnelltest-Profils“, mit der Sie einer Teststelle die zur Durchführung eines Schnelltests
erforderlichen Daten bereitstellen können (siehe hierzu Punkt 6 d.).
</p>
<p>
Die App verzichtet zudem standardmäßig auf die Auswertung Ihres Nutzungsverhaltens durch
Die App verzichtet standardmäßig auf die Auswertung Ihres Nutzungsverhaltens durch
Analyse-Tools. Nur wenn Sie ausdrücklich der freiwilligen Datenspende zustimmen, werden
bestimmte Daten über Ihre Nutzung der App an das RKI übermittelt (siehe hierzu Punkt 5 g.).
bestimmte Daten über Ihre Nutzung der App an das RKI übermittelt (siehe hierzu Punkt 5 h).
</p>
<p>
Die von der App verarbeiteten Daten lassen sich den folgenden Kategorien
......@@ -243,7 +246,20 @@
QR-Code in kodierter Form weitere von Ihnen angegebene Daten.
</p>
<h2>
d. Event-Daten
d. Schnelltest-Profil
</h2>
<p>
Sie können Angaben zu Ihrer Person in Ihrem Schnelltest-Profil in der App speichern. Das
Schnelltest-Profil umfasst folgende Felder: Vorname, Nachname, Geburtsdatum, Straße und
Hausnummer, PLZ, Stadt, Telefonnummer, E-Mail-Adresse. Die App wandelt Ihre Daten dann in Ihren
persönlichen QR-Code um, der alle von Ihnen eingegebenen Daten enthält. Das Anlegen eines
Schnelltest-Profils in der App und dessen Verwendung in einer Teststelle sind freiwillig. Sie
entscheiden selbst, welche Daten Sie in Ihrem Schnelltest-Profil eintragen. Nur diese Daten sind
im QR-Code enthalten. Sollte die Teststelle weitere Angaben benötigen, die nicht im QR-Code
enthalten sind, können Sie diese der Teststelle auch auf andere Weise mitteilen.
</p>
<h2>
e. Event-Daten
</h2>
<p>
Wenn Sie ein Event (beispielsweise eine Feier oder ein Konzert) oder einen Ort (beispielsweise
......@@ -270,7 +286,7 @@
</p>
<p>
Außerdem wird standardmäßig ein Eintrag in Ihrem Kontakt-Tagebuch angelegt. Die Einzelheiten
hierzu werden unter Punkt 5.e. und 6.e. erläutert. Wenn Sie für ein Event oder Ort keinen
hierzu werden unter Punkt 5 g. und 6 g. erläutert. Wenn Sie für ein Event oder Ort keinen
Eintrag in Ihrem Kontakt-Tagebuch anlegen möchten, können Sie diese Funktion einfach über den
entsprechenden Schieberegler ausschalten.
</p>
......@@ -292,7 +308,7 @@
einchecken.
</p>
<h2>
e. Gesundheitsdaten
f. Gesundheitsdaten
</h2>
<p>
Gesundheitsdaten sind alle Daten, die Informationen zum Gesundheitszustand
......@@ -320,7 +336,7 @@
Die Einzelheiten werden unter Punkt 6 erläutert.
</p>
<h2>
f. Einträge im Kontakt-Tagebuch
g. Einträge im Kontakt-Tagebuch
</h2>
<p>
Wenn Sie im Kontakt-Tagebuch notieren, wann und wo Sie welche Personen getroffen haben und
......@@ -342,7 +358,7 @@
Verfügung stellen können.
</p>
<h2>
g. Nutzungsdaten (Datenspende)
h. Nutzungsdaten (Datenspende)
</h2>
<p>
Wenn Sie die Datenspende aktivieren, übermittelt die App bestimmte Daten über Ihre App-Nutzung
......@@ -409,10 +425,10 @@
<p>
Die Teilnahme an der Datenspende ist freiwillig. Die Aktivierung der Datenspende setzt die
Bestätigung der Echtheit Ihrer App voraus (Beachten Sie bitte die weiteren Informationen hierzu
unter Punkt 5 i. und Punkt 11).
unter Punkt 5 j. und Punkt 11).
</p>
<h2>
h. Teilnahme an einer Befragung
i. Teilnahme an einer Befragung
</h2>
<p>
Einigen Nutzern wird in der App die Teilnahme an einer Befragung des RKI angeboten. In der Regel
......@@ -427,10 +443,10 @@
Befragung teilnehmen möchten und Daten hierfür an das RKI übermittelt werden sollen. Die
Befragungen finden auf einer Webseite außerhalb der App statt, auf die Sie weitergeleitet
werden. Die Teilnahme an einer Befragung setzt die Bestätigung der Echtheit Ihrer App voraus
(Beachten Sie bitte die weitere Informationen hierzu unter Punkt 5 i. und Punkt 11).
(Beachten Sie bitte die weitere Informationen hierzu unter Punkt 5 j. und Punkt 11).
</p>
<h2>
i. Bestätigung der Echtheit Ihrer App
j. Bestätigung der Echtheit Ihrer App
</h2>
<p>
Einige Funktionen der App setzen voraus, dass vorab die Echtheit Ihrer App geprüft und gegenüber
......@@ -464,15 +480,15 @@
</p>
<p>
Hierzu ruft die App vom Serversystem mehrmals täglich eine aktuelle Positiv-Liste mit den
Angaben von Nutzern, die über die offizielle Corona-App eines am länderübergreifenden Warnsystem
teilnehmenden Landes (siehe hierzu Punkt 7) eine Warnung ausgelöst haben ab. Diese Positiv-Liste
enthält die Zufalls-IDs der warnenden Nutzer sowie eventuelle Angaben zum Symptombeginn. Falls
die warnenden Nutzer bei einem Event eingecheckt waren, enthält die Positiv-Liste auch die
betreffenden Event-IDs und die Dauer des Check-ins (Eincheck- und Auscheck-Zeit).
Angaben von Nutzern ab, die über eine offizielle Corona-App eine Warnung ausgelöst haben (siehe
hierzu Punkt 7). Diese Positiv-Liste enthält die Zufalls-IDs der warnenden Nutzer sowie
eventuelle Angaben zum Symptombeginn. Falls die warnenden Nutzer bei einem Event eingecheckt
waren, enthält die Positiv-Liste auch die betreffenden Event-IDs und die Dauer des Check-ins
(Eincheck- und Auscheck-Zeit).
</p>
<p>
Die Zufalls-IDs und Event-IDs in den Positiv-Listen enthalten zusätzlich einen
Übertragungsrisiko-Wert und eine Angabe zur Art der Diagnose (siehe hierzu Punkt 6 d.).
Übertragungsrisiko-Wert und eine Angabe zur Art der Diagnose (siehe hierzu Punkt 6 e.).
</p>
<p>
Die App gibt die Zufalls-IDs aus der Positiv-Liste an das COVID-19-Benachrichtigungssystem
......@@ -613,7 +629,22 @@ Das für die letzten 14 Tage jeweils berechnete Risiko wird Ihnen in der Kalende
Schnelltest-Ergebnis nicht mehr in der App angezeigt wird.
</p>
<h2>
d. Andere warnen
d. Schnelltest-Profil
</h2>
<p>
Das Schnelltest-Profil bietet Ihnen die Möglichkeit, die Datenerfassung in teilnehmenden
Teststellen zu beschleunigen. Sie können hierfür Angaben zu Ihrer Person in Ihrem
Schnelltest-Profil in der App speichern und diese in Ihren persönlichen QR-Code umwandeln, der
alle eingegebenen Daten enthält. In der Teststelle können Sie den QR-Code Ihres
Schnelltest-Profils in Ihrer App vorzeigen, damit dieser von der Teststelle gescannt und die von
Ihnen angegebenen Daten auslesen werden können. Die für die Durchführung des Schnelltests
erforderlichen Daten werden so schnell und sicher bereitgestellt. Sie entscheiden selbst, welche
Daten Sie im Schnelltest-Profil angeben und ob Sie dieses in Teststellen vorzeigen. Angaben, die
die Teststelle benötigt und die nicht im QR-Code enthalten sind, können Sie der Teststelle auch
auf andere Weise mitteilen.
</p>
<h2>
e. Andere warnen
</h2>
<p>
Wenn Sie Corona-positiv getestet sind und Ihre Zufalls-IDs mit der App teilen, können andere
......@@ -690,7 +721,7 @@ Das für die letzten 14 Tage jeweils berechnete Risiko wird Ihnen in der Kalende
außer mit Ihnen keine anderen Kontakte hatte.
</p>
<h2>
e. Informatorische Nutzung der App
f. Informatorische Nutzung der App
</h2>
<p>
Die täglichen Statistiken, die in der App erscheinen, erhält die App
......@@ -701,7 +732,7 @@ Das für die letzten 14 Tage jeweils berechnete Risiko wird Ihnen in der Kalende
jeweiligen Anbietern der aufgerufenen Webseite festgelegt.
</p>
<h2>
f. Kontakt-Tagebuch
g. Kontakt-Tagebuch
</h2>
<p>
Das Kontakt-Tagebuch ist eine Zusatzfunktion der App. Ihre Einträge im Kontakt-Tagebuch dienen
......@@ -716,7 +747,7 @@ Das für die letzten 14 Tage jeweils berechnete Risiko wird Ihnen in der Kalende
Ansteckungen verhindern.
</p>
<h2>
g. Datenspende
h. Datenspende
</h2>
<p>
Die Datenspende ist eine Zusatzfunktionen der App. Die im Rahmen der Datenspende an das RKI
......@@ -757,7 +788,7 @@ Das für die letzten 14 Tage jeweils berechnete Risiko wird Ihnen in der Kalende
oder wen Sie getroffen haben.
</p>
<h2>
h. Befragungen
i. Befragungen
</h2>
<p>
Befragungen finden auf einer Webseite außerhalb der App statt, auf die Sie weitergeleitet
......@@ -766,7 +797,7 @@ Das für die letzten 14 Tage jeweils berechnete Risiko wird Ihnen in der Kalende
Befragung auf der Befragungs-Webseite beschrieben.
</p>
<h2>
i. Bestätigung der Echtheit Ihrer App
j. Bestätigung der Echtheit Ihrer App
</h2>
<p>
Zur Bestätigung der Echtheit Ihrer App wird eine Funktion des Betriebssystems Ihres Smartphones
......@@ -812,7 +843,7 @@ Das für die letzten 14 Tage jeweils berechnete Risiko wird Ihnen in der Kalende
<p>
Das jeweilige Serversystem führt die erhaltenen Positiv-Listen mit der eigenen Positiv-Liste
zusammen, so dass die Risiko-Ermittlung auch Risiko-Begegnungen mit Nutzern einer anderen
Corona-App berücksichtigen kann (siehe Ziffer 6 d.). Die anderen teilnehmenden Länder verfahren
Corona-App berücksichtigen kann (siehe Punkt 6 e.). Die anderen teilnehmenden Länder verfahren
entsprechend mit den vom RKI bereitgestellten Positiv-Listen.
</p>
<p>
......@@ -966,7 +997,11 @@ Das für die letzten 14 Tage jeweils berechnete Risiko wird Ihnen in der Kalende
gelöscht. Sofern Sie ein positives Testergebnis abgerufen haben, wird das
Token im App-Speicher gelöscht, sobald Sie eine Warnung auslösen. Die Einträge im
Kontakt-Tagebuch bleiben für 16 Tage auf Ihrem Smartphone gespeichert und werden dann
automatisch gelöscht. Sie können diese Einträge jederzeit auch vorzeitig selbst löschen.
automatisch gelöscht. Sie können diese Einträge jederzeit auch vorzeitig selbst löschen. Bitte
beachten Sie, dass beim Einchecken zu einem Event oder an einem Ort übernommene Einträge im
Kontakt-Tagebuch auch nach der Löschung des zugehörigen Check-Ins dort noch gespeichert sind.
Wenn Sie Ihr Schnelltest-Profil einmal angelegt haben, bleibt dieses so lange in der App
gespeichert, bis Sie es selbst wieder löschen.
</p>
<h2>
b. Daten auf Serversystemen
......@@ -1013,18 +1048,20 @@ Das für die letzten 14 Tage jeweils berechnete Risiko wird Ihnen in der Kalende
Schweizerischen Eidgenossenschaft in Abstimmung mit dem RKI betrieben und gewartet.
</p>
<p>
Mit dem Betrieb und der Wartung eines Teils der technischen Infrastruktur
der App (z. B. Serversysteme, Hotline) hat das RKI die T-Systems
International GmbH und die SAP Deutschland SE &amp; Co. KG beauftragt, die
als Auftragsverarbeiter des RKI tätig werden. Diese Unternehmen sind von
der EU-Kommission zudem als Unterauftragsverarbeiter mit der technischen
Bereitstellung und Verwaltung des gemeinsam betriebenen Warnsystems der
teilnehmenden Länder beauftragt. Im Übrigen gibt das RKI Ihre Daten, die im Zusammenhang mit der Nutzung der
App erhoben werden, nur an Dritte weiter, soweit das RKI rechtlich dazu
verpflichtet ist oder die Weitergabe im Falle von Angriffen auf die
technische Infrastruktur der App zur Rechts- oder Strafverfolgung
erforderlich ist. Eine Weitergabe durch das RKI in anderen Fällen erfolgt grundsätzlich
nicht.
Mit dem Betrieb und der Wartung des gemeinsam betriebenen Austausch-Servers der teilnehmenden
EU-Länder haben die jeweils zuständigen nationalen Gesundheitsbehörden die EU-Kommission als
Auftragsverarbeiter beauftragt. Der Austausch-Server für länderübergreifende Warnungen zwischen
der Corona-Warn-App und der schweizerischen Corona-App wird vom Bundesamt für Gesundheit der
Schweizerischen Eidgenossenschaft in Abstimmung mit dem RKI betrieben und gewartet. Mit dem
Betrieb und der Wartung eines Teils der technischen Infrastruktur der App (z. B. Serversysteme,
Hotline) hat das RKI die T-Systems International GmbH und die SAP Deutschland SE &amp; Co. KG
beauftragt, die als Auftragsverarbeiter des RKI tätig werden. Diese Unternehmen sind von der
EU-Kommission zudem als Unterauftragsverarbeiter mit der technischen Bereitstellung und
Verwaltung des gemeinsam betriebenen Warnsystems der teilnehmenden Länder beauftragt. Im Übrigen
gibt das RKI Ihre Daten, die im Zusammenhang mit der Nutzung der App erhoben werden, nur an
Dritte weiter, soweit das RKI rechtlich dazu verpflichtet ist oder die Weitergabe im Falle von
Angriffen auf die technische Infrastruktur der App zur Rechts- oder Strafverfolgung erforderlich
ist. Eine Weitergabe durch das RKI in anderen Fällen erfolgt grundsätzlich nicht.
</p>
<h1>
11. Werden Ihre Daten in Länder außerhalb der EU übermittelt?
......
......@@ -76,7 +76,8 @@
</h1>
<p>
Using the app is voluntary. It is entirely up to you whether you install the app, which of the
app’s features you use, and whether you share data with others. All of the app’s features that
app’s features you use, and whether you share data with others. All of the app’s main features
that
require the transfer of your personal data to the RKI or to other users will obtain your express
consent in advance. If you do not give your consent or if you subsequently withdraw it, this
will not result in any disadvantages for you.
......@@ -90,7 +91,7 @@
giving your consent, you can withdraw it at any time (so-called right of withdrawal). Please
refer to Section 12 for further information about your right of withdrawal. On the basis of Art.
6(1) Sentence 1(e) GDPR in conjunction with Sect. 3 of the German Federal Data Protection Act
(BDSG), the processing of access data for the provision of daily statistics (see Section 6 e.)
(BDSG), the processing of access data for the provision of daily statistics (see Section 6 f.)
is performed as part of the RKI’s duty to inform the public pursuant to Sect. 4(4) of the Act on
Successor Agencies to the Federal Health Agency (BGA-NachfG).
</p>
......@@ -107,13 +108,15 @@
The app’s entire system has been programmed to process as little personal data as possible. This
means that, when you use exposure logging, warn other users, or retrieve a test result, the
system does not need to collect any data that would allow the RKI or other users to infer your
identity, your name, your location or other personal details. The only exception to this is the
optional feature for proving a rapid test result, which allows you to display a confirmation
issued in your name for negative rapid test results (see Section 6 c.).
identity, your name, your location or other personal details.
The only exceptions to this are the feature for proving a rapid test result, which allows you to
display a confirmation issued in your name for negative rapid test results (see Section 6 c.),
and the feature for creating a rapid test profile, which allows you to provide a testing point
with the data required to perform a rapid test (see Section 6 d.).
</p>
<p>
The app therefore also refrains by default from using analysis tools to evaluate the way you use
it. Only if you expressly agree to voluntarily share data (see Section 5 g.), will certain data
The app refrains by default from using analysis tools to evaluate the way you use
it. Only if you expressly agree to voluntarily share data (see Section 5 h.), will certain data
about your use of the app be transmitted to the RKI.
</p>
<p>
......@@ -229,8 +232,8 @@
c. Rapid test data
</h2>
<p>
If you have taken rapid antigen tests at a testing centre, you can retrieve the results of these
through the app. If you choose to use this service, your testing centre will generate an
If you have taken rapid antigen tests at a testing point, you can retrieve the results of these
through the app. If you choose to use this service, your testing point will generate an
individual QR code for you to scan with the app. The QR code contains a unique code for your
rapid test, and the time you were tested, in encoded form. If, in the event of a negative rapid
test result, you wish to have the test result displayed along with your name in the app for
......@@ -238,7 +241,20 @@
will contain further data provided by you in encoded form.
</p>
<h2>
d. Event data
d. Rapid test profile
</h2>
<p>
You can store information about yourself in your rapid test profile in the app. The rapid test
profile includes the following fields: first name, last name, date of birth, street and house
number, postcode, town, phone number, email address. The app then converts your data into your
personal QR code, which contains all the data you have entered. Creating a rapid test profile in
the app, and using it at a testing point, are voluntary. You decide yourself which data you
enter in your rapid test profile. The QR code only contains this data. If the testing point
requires more information that is not contained in the QR code, you can also provide this to the
testing point in another way.
</p>
<h2>
e. Event data
</h2>
<p>
If you visit an event (such as a party or concert) or a place (such as a shop or restaurant),
......@@ -263,7 +279,7 @@
stored on your smartphone.
</p>
<p>
An entry will also be created in your contact journal by default. Sections 5 f. and 6.f. explain
An entry will also be created in your contact journal by default. Sections 5 g. and 6 g. explain
this in more detail. If you do not want to create an entry in your contact journal for an event
or place, you can simply switch off this feature using the corresponding toggle switch.
</p>
......@@ -283,7 +299,7 @@
check-out time.
</p>
<h2>
e. Health data
f. Health data
</h2>
<p>
Health data is any data containing information about a person’s health.
......@@ -311,7 +327,7 @@
Section 6 explains this in more detail.
</p>
<h2>
f. Entries in the contact journal
g. Entries in the contact journal
</h2>
<p>
If you use the contact journal to note when and where you met certain people and record certain
......@@ -331,7 +347,7 @@
tracing purposes, and how you can provide it.
</p>
<h2>
g. Usage data (data sharing)
h. Usage data (data sharing)
</h2>
<p>
If you enable data sharing, the app will transmit certain data about your use of the app
......@@ -392,9 +408,9 @@
<p>
Participation in data sharing is voluntary. To enable the data sharing feature, the authenticity
of your app first needs to be confirmed (please note the further information about this under
Sections 5 i. and 11).
Sections 5 j. and 11).
</p>
h. Participation in a survey
i. Participation in a survey
</h2>
<p>
Some app users are offered to participate in a survey by the RKI. This offer to participate in
......@@ -411,7 +427,7 @@ h. Participation in a survey
information about this in Sections 5 i. and 11).
</p>
<h2>
i. Confirmation of the authenticity of your app
j. Confirmation of the authenticity of your app
</h2>
<p>
Before you can use some of the app’s features, the authenticity of your app first needs to be
......@@ -445,9 +461,9 @@ h. Participation in a survey
</p>
<p>
For this purpose, the app retrieves an up-to-date positive list from the server system several
times a day. This list contains information from users who have used the warning feature in
their app, which is the official coronavirus app in any country participating in the
transnational warning system (see Section 7). This positive list contains the random IDs of
times a day. This list contains information from users who have used the warning feature in an
official coronavirus app (see Section 7).
This positive list contains the random IDs of
users who have activated the warning feature and, if applicable, information about the onset of
symptoms. If the users who have activated the warning feature were checked in at events, the
positive list also contains the relevant event IDs and the duration of the check-ins (check-in
......@@ -455,7 +471,7 @@ h. Participation in a survey
</p>
<p>
The random IDs and event IDs on the positive lists also contain a transmission risk value and an
indication of the type of diagnosis (see Section 6 d.).
indication of the type of diagnosis (see Section 6 e.).
</p>
<p>
The app passes the random IDs from the positive list to the COVID-19 exposure
......@@ -504,7 +520,7 @@ h. Participation in a survey
<p>
If you have taken a coronavirus test (PCR test or rapid antigen test), you can retrieve your
test result via the app. The app will notify you as soon as your test result is available. For
this to work, the testing facility (e.g. testing laboratory or testing centre) needs to be
this to work, the testing facility (e.g. testing laboratory or testing point) needs to be
connected to the server system and, as part of the testing procedure, you must have given
separate consent to your test result being sent. It is not possible to display test results from
testing facilities that are not connected to the app’s server system. If you have not received a
......@@ -594,7 +610,21 @@ h. Participation in a survey
no longer displayed in the app.
</p>
<h2>
d. Warning others
d. Rapid test profile
</h2>
<p>
The rapid test profile feature offers you the possibility to speed up data collection at
participating testing points. To do this, you can store information about yourself in your rapid
test profile in the app and convert it into your personal QR code, which contains all the data
you have entered. At the testing point, you can present your rapid test profile’s QR code in
your app so that it can be scanned by testing point staff, allowing the data you have provided
to be read. This is a quick and secure way for you to provide the data required to perform a
rapid test. You decide yourself which data you include in your rapid test profile and whether to
present it at testing points. If the testing point requires information that is not contained in
the QR code, you can provide the information to the testing point in another way.
</p>
<h2>
e. Warning others
</h2>
<p>
If you have tested positive for coronavirus and share your random IDs with the app, then it is
......@@ -669,7 +699,7 @@ h. Participation in a survey
which the possible exposure is displayed.
</p>
<h2>
e. Using the app for information purposes only
f. Using the app for information purposes only
</h2>
<p>
The app automatically receives the daily statistics that appear in the app
......@@ -680,7 +710,7 @@ h. Participation in a survey
of the websites accessed.
</p>
<h2>
f. Contact journal
g. Contact journal
</h2>
<p>
The contact journal is an additional feature of the app. What you enter in the contact journal
......@@ -693,7 +723,7 @@ h. Participation in a survey
the risk of causing undetected infections.
</p>
<h2>
g. Data sharing
h. Data sharing
</h2>
<p>
Share Data is an additional feature of the app. The usage data and other voluntary
......@@ -734,7 +764,7 @@ h. Participation in a survey
have met.
</p>
<h2>
h. Surveys
i. Surveys
</h2>
<p>
The surveys take place on a website outside of the app, which you will be redirected to. The app
......@@ -742,7 +772,7 @@ h. Participation in a survey
survey are described in the information about the survey on the survey website.
</p>
<h2>
i. Confirmation of the authenticity of your app
j. Confirmation of the authenticity of your app
</h2>
<p>
A feature of your smartphone’s operating system is used to confirm the authenticity of your app.
......@@ -787,7 +817,7 @@ h. Participation in a survey
Each server system merges the positive lists received in this way with its
own positive list, which allows the exposure logging feature to also take
into account possible exposures involving users of another coronavirus app
(see point 6 d.) The other participating countries proceed in the same way
(see section 6 e.) The other participating countries proceed in the same way
with the positive lists provided by the RKI.
</p>
<p>
......@@ -941,6 +971,8 @@ h. Participation in a survey
16 days before being automatically deleted. You can also delete these entries yourself at any
time. Please note that if entries are added to the contact journal when you check in at an event
or place, these will still be stored there even after you delete the associated check-in.
Once you have created your rapid test profile, it will be stored in the app until you delete it
yourself.
</p>
<h2>
b. Data on server systems
......
This diff is collapsed.
......@@ -33,11 +33,13 @@ import de.rki.coronawarnapp.risk.RiskLevelChangeDetector
import de.rki.coronawarnapp.risk.execution.ExposureWindowRiskWorkScheduler
import de.rki.coronawarnapp.submission.auto.AutoSubmission
import de.rki.coronawarnapp.task.TaskController
import de.rki.coronawarnapp.util.BuildVersionWrap
import de.rki.coronawarnapp.util.CWADebug
import de.rki.coronawarnapp.util.WatchdogService
import de.rki.coronawarnapp.util.device.ForegroundState
import de.rki.coronawarnapp.util.di.AppInjector
import de.rki.coronawarnapp.util.di.ApplicationComponent
import de.rki.coronawarnapp.util.hasAPILevel
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
......@@ -85,8 +87,10 @@ class CoronaWarnApplication : Application(), HasAndroidInjector {
CWADebug.init(this)
AppInjector.init(this).let { compPreview ->
Timber.v("Calling EncryptedPreferencesMigration.doMigration()")
compPreview.encryptedMigration.doMigration()
if (BuildVersionWrap.hasAPILevel(23)) {
Timber.v("Calling EncryptedPreferencesMigration.doMigration()")
compPreview.encryptedMigration.get().doMigration()
}
CWADebug.initAfterInjection(compPreview)
......
......@@ -5,12 +5,17 @@ import dagger.Provides
import dagger.Reusable
import dagger.multibindings.IntoSet
import de.rki.coronawarnapp.bugreporting.censors.BugCensor
import de.rki.coronawarnapp.bugreporting.censors.DiaryEncounterCensor
import de.rki.coronawarnapp.bugreporting.censors.DiaryLocationCensor
import de.rki.coronawarnapp.bugreporting.censors.DiaryPersonCensor
import de.rki.coronawarnapp.bugreporting.censors.DiaryVisitCensor
import de.rki.coronawarnapp.bugreporting.censors.QRCodeCensor
import de.rki.coronawarnapp.bugreporting.censors.RegistrationTokenCensor
import de.rki.coronawarnapp.bugreporting.censors.contactdiary.DiaryEncounterCensor
import de.rki.coronawarnapp.bugreporting.censors.contactdiary.DiaryLocationCensor
import de.rki.coronawarnapp.bugreporting.censors.contactdiary.DiaryPersonCensor
import de.rki.coronawarnapp.bugreporting.censors.contactdiary.DiaryVisitCensor
import de.rki.coronawarnapp.bugreporting.censors.presencetracing.CheckInsCensor
import de.rki.coronawarnapp.bugreporting.censors.presencetracing.TraceLocationCensor
import de.rki.coronawarnapp.bugreporting.censors.submission.CoronaTestCensor
import de.rki.coronawarnapp.bugreporting.censors.submission.PcrQrCodeCensor
import de.rki.coronawarnapp.bugreporting.censors.submission.RACoronaTestCensor
import de.rki.coronawarnapp.bugreporting.censors.submission.RatProfileCensor
import de.rki.coronawarnapp.bugreporting.censors.submission.RatQrCodeCensor
import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebugLoggerScope
import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope
import de.rki.coronawarnapp.bugreporting.debuglog.upload.server.LogUploadApiV1
......@@ -71,11 +76,19 @@ class BugReportingSharedModule {
@Provides
@IntoSet
fun registrationTokenCensor(censor: RegistrationTokenCensor): BugCensor = censor
fun registrationTokenCensor(censor: CoronaTestCensor): BugCensor = censor
@Provides
@IntoSet
fun qrCodeCensor(censor: QRCodeCensor): BugCensor = censor
fun pcrQrCodeCensor(censor: PcrQrCodeCensor): BugCensor = censor
@Provides
@IntoSet
fun ratQrCodeCensor(censor: RatQrCodeCensor): BugCensor = censor
@Provides
@IntoSet
fun raCoronaTestCensor(censor: RACoronaTestCensor): BugCensor = censor
@Provides
@IntoSet
......@@ -92,4 +105,16 @@ class BugReportingSharedModule {
@Provides
@IntoSet
fun diaryVisitCensor(censor: DiaryVisitCensor): BugCensor = censor
@Provides
@IntoSet
fun checkInsCensor(censor: CheckInsCensor): BugCensor = censor
@Provides
@IntoSet
fun traceLocationsCensor(censor: TraceLocationCensor): BugCensor = censor
@Provides
@IntoSet
fun ratProfileCensor(censor: RatProfileCensor): BugCensor = censor
}
......@@ -38,6 +38,34 @@ interface BugCensor {
return true
}
fun withValidDescription(description: String?, action: (String) -> Unit): Boolean {
if (description.isNullOrBlank()) return false
if (description.length < 5) return false
action(description)
return true
}
fun withValidAddress(address: String?, action: (String) -> Unit): Boolean {
if (address.isNullOrBlank()) return false
if (address.length < 4) return false
action(address)
return true
}
fun withValidCity(city: String?, action: (String) -> Unit): Boolean {
if (city.isNullOrBlank()) return false
if (city.length < 3) return false
action(city)
return true
}
fun withValidZipCode(zipCode: String?, action: (String) -> Unit): Boolean {
if (zipCode.isNullOrBlank()) return false
if (zipCode.length < 5) return false
action(zipCode)
return true
}
fun LogLine.toNewLogLineIfDifferent(newMessage: String): LogLine? {
return if (newMessage != message) copy(message = newMessage) else null
}
......
package de.rki.coronawarnapp.bugreporting.censors
package de.rki.coronawarnapp.bugreporting.censors.contactdiary
import dagger.Reusable
import de.rki.coronawarnapp.bugreporting.censors.BugCensor
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidComment
import de.rki.coronawarnapp.bugreporting.debuglog.LogLine
......
package de.rki.coronawarnapp.bugreporting.censors
package de.rki.coronawarnapp.bugreporting.censors.contactdiary
import dagger.Reusable
import de.rki.coronawarnapp.bugreporting.censors.BugCensor
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidEmail
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidName
......
package de.rki.coronawarnapp.bugreporting.censors
package de.rki.coronawarnapp.bugreporting.censors.contactdiary
import dagger.Reusable
import de.rki.coronawarnapp.bugreporting.censors.BugCensor
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidEmail
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidName
......
package de.rki.coronawarnapp.bugreporting.censors
package de.rki.coronawarnapp.bugreporting.censors.contactdiary
import dagger.Reusable
import de.rki.coronawarnapp.bugreporting.censors.BugCensor
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent
import de.rki.coronawarnapp.bugreporting.debuglog.LogLine
import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope
......
package de.rki.coronawarnapp.bugreporting.censors.presencetracing
import dagger.Reusable
import de.rki.coronawarnapp.bugreporting.censors.BugCensor
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidAddress
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidDescription
import de.rki.coronawarnapp.bugreporting.debuglog.LogLine
import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope
import de.rki.coronawarnapp.presencetracing.checkins.CheckInRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.stateIn
import javax.inject.Inject
@Reusable
class CheckInsCensor @Inject constructor(
@DebuggerScope debugScope: CoroutineScope,
private val checkInRepository: CheckInRepository
) : BugCensor {
private val checkInsFlow by lazy {
checkInRepository.allCheckIns.stateIn(
scope = debugScope,
started = SharingStarted.Lazily,
initialValue = null
).filterNotNull()
}
override suspend fun checkLog(entry: LogLine): LogLine? {
val checkIns = checkInsFlow.first()
if (checkIns.isEmpty()) return null
val newLogMsg = checkIns.fold(entry.message) { initial, checkIn ->
var acc = initial
withValidDescription(checkIn.description) { description ->
acc = acc.replace(description, "CheckIn#${checkIn.id}/Description")
}
withValidAddress(checkIn.address) { address ->
acc = acc.replace(address, "CheckIn#${checkIn.id}/Address")
}
acc
}
return entry.toNewLogLineIfDifferent(newLogMsg)
}
}
package de.rki.coronawarnapp.bugreporting.censors.presencetracing
import dagger.Reusable
import de.rki.coronawarnapp.bugreporting.censors.BugCensor
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidAddress
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.withValidDescription
import de.rki.coronawarnapp.bugreporting.debuglog.LogLine
import de.rki.coronawarnapp.bugreporting.debuglog.internal.DebuggerScope
import de.rki.coronawarnapp.presencetracing.locations.TraceLocationUserInput
import de.rki.coronawarnapp.presencetracing.storage.repo.TraceLocationRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.stateIn
import javax.inject.Inject
/**
* Censors Trace Location Data
*
* The information about which data to censor comes from two places
* - traceLocationRepository, for traceLocations that are already stored
* - dataToCensor, which is set before a traceLocation is created; this is needed in cases when the app crashes between
* data input and storing
*/
@Reusable
class TraceLocationCensor @Inject constructor(
@DebuggerScope debugScope: CoroutineScope,
private val traceLocationRepository: TraceLocationRepository
) : BugCensor {
private val traceLocationsFlow by lazy {
traceLocationRepository.allTraceLocations.stateIn(
scope = debugScope,
started = SharingStarted.Lazily,
initialValue = null
).filterNotNull()
}
override suspend fun checkLog(entry: LogLine): LogLine? {
val traceLocations = traceLocationsFlow.first()
var newLogMsg = traceLocations.fold(entry.message) { initial, traceLocation ->
var acc = initial
acc = acc.replace(traceLocation.type.name, "TraceLocation#${traceLocation.id}/Type")
withValidDescription(traceLocation.description) { description ->
acc = acc.replace(description, "TraceLocation#${traceLocation.id}/Description")
}
withValidAddress(traceLocation.address) { address ->
acc = acc.replace(address, "TraceLocation#${traceLocation.id}/Address")
}
acc
}
val inputDataToCensor = dataToCensor
if (inputDataToCensor != null) {
newLogMsg = newLogMsg.replace(inputDataToCensor.type.name, "TraceLocationUserInput#Type")
withValidDescription(inputDataToCensor.description) {
newLogMsg = newLogMsg.replace(inputDataToCensor.description, "TraceLocationUserInput#Description")
}
withValidAddress(inputDataToCensor.address) {
newLogMsg = newLogMsg.replace(inputDataToCensor.address, "TraceLocationUserInput#Address")
}
}
return entry.toNewLogLineIfDifferent(newLogMsg)
}
companion object {
var dataToCensor: TraceLocationUserInput? = null
}
}
package de.rki.coronawarnapp.bugreporting.censors
package de.rki.coronawarnapp.bugreporting.censors.submission
import dagger.Reusable
import de.rki.coronawarnapp.bugreporting.censors.BugCensor
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent
import de.rki.coronawarnapp.bugreporting.debuglog.LogLine
import de.rki.coronawarnapp.coronatest.CoronaTestRepository
......@@ -9,17 +10,25 @@ import kotlinx.coroutines.flow.first
import javax.inject.Inject
@Reusable
class RegistrationTokenCensor @Inject constructor(
class CoronaTestCensor @Inject constructor(
private val coronaTestRepository: CoronaTestRepository,
) : BugCensor {
// Keep a history to have references even after the user deletes a test
private val tokenHistory = mutableSetOf<String>()
private val identifierHistory = mutableSetOf<String>()
override suspend fun checkLog(entry: LogLine): LogLine? {
// The Registration Token is received after registration of PCR and RAT tests. It is required to poll the test result.
val tokens = coronaTestRepository.coronaTests.first().map { it.registrationToken }
tokenHistory.addAll(tokens)
if (tokens.isEmpty()) return null
val identifiers = coronaTestRepository.coronaTests.first().map { it.identifier }
identifierHistory.addAll(identifiers)
var newMessage = entry.message
for (token in tokens) {
for (token in tokenHistory) {
if (!entry.message.contains(token)) continue
newMessage = if (CWADebug.isDeviceForTestersBuild) {
......@@ -29,6 +38,12 @@ class RegistrationTokenCensor @Inject constructor(
}
}
identifierHistory
.filter { entry.message.contains(it) }
.forEach {
newMessage = newMessage.replace(it, "${it.take(11)}CoronaTest/Identifier")
}
return entry.toNewLogLineIfDifferent(newMessage)
}
......
package de.rki.coronawarnapp.bugreporting.censors
package de.rki.coronawarnapp.bugreporting.censors.submission
import dagger.Reusable
import de.rki.coronawarnapp.bugreporting.censors.BugCensor
import de.rki.coronawarnapp.bugreporting.censors.BugCensor.Companion.toNewLogLineIfDifferent
import de.rki.coronawarnapp.bugreporting.debuglog.LogLine
import de.rki.coronawarnapp.util.CWADebug
import javax.inject.Inject
@Reusable
class QRCodeCensor @Inject constructor() : BugCensor {
class PcrQrCodeCensor @Inject constructor() : BugCensor {
override suspend fun checkLog(entry: LogLine): LogLine? {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment