Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
TousAntiCovid sources
TousAntiCovid Android
Commits
bfed9529
Commit
bfed9529
authored
Jun 12, 2020
by
stopcovid@lunabee.com
Browse files
Update to 1.0.3
parent
d2f41886
Changes
60
Hide whitespace changes
Inline
Side-by-side
coreui/src/main/java/com/lunabeestudio/stopcovid/coreui/UiConstants.kt
View file @
bfed9529
...
...
@@ -26,7 +26,9 @@ object UiConstants {
enum
class
Notification
(
val
channelId
:
String
,
val
notificationId
:
Int
)
{
AT_RISK
(
"atRisk"
,
1
),
PROXIMITY
(
"proximity"
,
2
),
ERROR
(
"error"
,
3
)
ERROR
(
"error"
,
3
),
UPGRADE
(
"upgrade"
,
4
),
TIME
(
"error"
,
5
)
}
const
val
DEFAULT_LANGUAGE
:
String
=
"en"
...
...
coreui/src/main/java/com/lunabeestudio/stopcovid/coreui/extension/StringExt.kt
View file @
bfed9529
...
...
@@ -30,14 +30,14 @@ import java.text.Normalizer
import
java.util.Locale
@WorkerThread
fun
String
.
download
(
context
:
Context
):
String
{
fun
String
.
download
(
context
:
Context
):
okhttp3
.
Response
{
val
okHttpClient
=
OkHttpClient
.
getDefaultOKHttpClient
(
context
,
this
,
BuildConfig
.
SERVER_CERTIFICATE_SHA256
)
val
request
:
Request
=
Request
.
Builder
()
.
url
(
this
)
.
build
()
val
response
=
okHttpClient
.
newCall
(
request
).
execute
()
return
if
(
response
.
isSuccessful
&&
response
.
body
!=
null
)
{
response
.
body
!!
.
string
()
response
}
else
{
Timber
.
d
(
response
.
body
?.
string
())
throw
HttpException
(
Response
.
error
<
Any
>(
response
.
body
!!
,
response
))
...
...
@@ -54,7 +54,7 @@ fun String.saveTo(context: Context, file: File) {
if
(
response
.
isSuccessful
&&
response
.
body
!=
null
)
{
response
.
body
!!
.
string
().
byteInputStream
().
use
{
input
->
file
.
outputStream
().
use
{
output
->
input
.
copyTo
(
output
)
input
.
copyTo
(
output
,
4
*
1024
)
}
}
}
else
{
...
...
coreui/src/main/java/com/lunabeestudio/stopcovid/coreui/manager/ConfigManager.kt
View file @
bfed9529
...
...
@@ -14,6 +14,7 @@ import android.content.Context
import
androidx.annotation.WorkerThread
import
com.lunabeestudio.stopcovid.coreui.BuildConfig
import
com.lunabeestudio.stopcovid.coreui.extension.download
import
okhttp3.Response
import
timber.log.Timber
object
ConfigManager
{
...
...
@@ -21,7 +22,7 @@ object ConfigManager {
private
const
val
URL
:
String
=
BuildConfig
.
SERVER_URL
+
BuildConfig
.
CONFIG_JSON
@WorkerThread
fun
fetchLast
(
context
:
Context
):
String
{
fun
fetchLast
(
context
:
Context
):
Response
{
Timber
.
d
(
"Fetching remote config at $URL"
)
return
URL
.
download
(
context
)
}
...
...
coreui/src/main/java/com/lunabeestudio/stopcovid/coreui/manager/ServerManager.kt
View file @
bfed9529
...
...
@@ -23,6 +23,7 @@ import java.io.File
import
java.lang.reflect.Type
import
java.util.Locale
import
java.util.concurrent.TimeUnit
import
kotlin.math.abs
abstract
class
ServerManager
{
...
...
@@ -38,9 +39,9 @@ abstract class ServerManager {
protected
open
fun
url
():
String
=
BuildConfig
.
SERVER_URL
@WorkerThread
protected
fun
fetchLast
(
context
:
Context
,
languageCode
:
String
):
Boolean
{
protected
fun
fetchLast
(
context
:
Context
,
languageCode
:
String
,
forceRefresh
:
Boolean
):
Boolean
{
return
try
{
if
(
shouldRefresh
(
context
))
{
if
(
shouldRefresh
(
context
)
||
forceRefresh
)
{
val
filename
=
"${prefix(context)}${languageCode}${extension()}"
Timber
.
d
(
"Fetching remote data at ${url()}$filename"
)
"${url()}$filename"
.
saveTo
(
context
,
File
(
context
.
filesDir
,
filename
))
...
...
@@ -54,7 +55,7 @@ abstract class ServerManager {
Timber
.
d
(
"Fetching fail for $languageCode"
)
if
(
languageCode
!=
UiConstants
.
DEFAULT_LANGUAGE
)
{
Timber
.
d
(
"Trying for ${UiConstants.DEFAULT_LANGUAGE}"
)
fetchLast
(
context
,
UiConstants
.
DEFAULT_LANGUAGE
)
fetchLast
(
context
,
UiConstants
.
DEFAULT_LANGUAGE
,
forceRefresh
)
}
else
{
false
}
...
...
@@ -93,8 +94,8 @@ abstract class ServerManager {
private
fun
shouldRefresh
(
context
:
Context
):
Boolean
{
return
!
BuildConfig
.
USE_LOCAL_DATA
&&
System
.
currentTimeMillis
()
-
TimeUnit
.
HOURS
.
toMillis
(
1L
)
>
PreferenceManager
.
getDefaultSharedPreferences
(
context
)
.
getLong
(
lastRefreshSharedPrefsKey
(),
0L
)
&&
abs
(
System
.
currentTimeMillis
()
-
PreferenceManager
.
getDefaultSharedPreferences
(
context
)
.
getLong
(
lastRefreshSharedPrefsKey
(),
0L
)
)
>
TimeUnit
.
HOURS
.
toMillis
(
1L
)
}
private
fun
saveLastRefresh
(
context
:
Context
)
{
...
...
coreui/src/main/java/com/lunabeestudio/stopcovid/coreui/manager/StringsManager.kt
View file @
bfed9529
...
...
@@ -42,7 +42,9 @@ class StringsManager : ServerManager() {
fun
appForeground
(
context
:
Context
)
{
CoroutineScope
(
Dispatchers
.
IO
).
launch
{
if
(
StringsManager
().
fetchLast
(
context
,
Locale
.
getDefault
().
language
)
||
prevLanguage
!=
Locale
.
getDefault
().
language
)
{
if
(
StringsManager
().
fetchLast
(
context
,
Locale
.
getDefault
().
language
,
prevLanguage
!=
Locale
.
getDefault
().
language
)
||
prevLanguage
!=
Locale
.
getDefault
().
language
)
{
prevLanguage
=
Locale
.
getDefault
().
language
_strings
=
StringsManager
().
loadLocal
(
context
)
}
...
...
coreui/src/main/res/layout/item_button.xml
View file @
bfed9529
...
...
@@ -15,7 +15,7 @@
<com.google.android.material.button.MaterialButton
android:id=
"@+id/button"
style=
"@style/
Theme
.StopCovid.Button"
style=
"@style/
Widget
.StopCovid.Button"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginHorizontal=
"@dimen/spacing_large"
...
...
coreui/src/main/res/layout/item_light_button.xml
View file @
bfed9529
...
...
@@ -15,7 +15,7 @@
<com.google.android.material.button.MaterialButton
android:id=
"@+id/button"
style=
"@style/
Theme
.StopCovid.Button.Light"
style=
"@style/
Widget
.StopCovid.Button.Light"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginHorizontal=
"@dimen/spacing_large"
...
...
coreui/src/main/res/layout/layout_button_bottom_sheet.xml
View file @
bfed9529
...
...
@@ -32,7 +32,7 @@
<com.google.android.material.button.MaterialButton
android:id=
"@+id/bottomSheetButton"
style=
"@style/
Theme
.StopCovid.Button"
style=
"@style/
Widget
.StopCovid.Button"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginHorizontal=
"@dimen/spacing_xlarge"
...
...
coreui/src/main/res/layout/layout_confirmation_bottom_sheet.xml
View file @
bfed9529
...
...
@@ -32,7 +32,7 @@
<com.google.android.material.button.MaterialButton
android:id=
"@+id/mainButton"
style=
"@style/
Theme
.StopCovid.Button"
style=
"@style/
Widget
.StopCovid.Button"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginHorizontal=
"@dimen/spacing_large"
...
...
@@ -43,7 +43,7 @@
<com.google.android.material.button.MaterialButton
android:id=
"@+id/dangerButton"
style=
"@style/
Theme
.StopCovid.Button.Danger"
style=
"@style/
Widget
.StopCovid.Button.Danger"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginHorizontal=
"@dimen/spacing_large"
...
...
@@ -53,7 +53,7 @@
<com.google.android.material.button.MaterialButton
android:id=
"@+id/lightButton"
style=
"@style/
Theme
.StopCovid.Button.Light"
style=
"@style/
Widget
.StopCovid.Button.Light"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginHorizontal=
"@dimen/spacing_large"
...
...
coreui/src/main/res/values-night/styles_widget.xml
View file @
bfed9529
...
...
@@ -9,13 +9,13 @@
-->
<resources>
<style
name=
"
Theme
.StopCovid.Button.Light"
>
<style
name=
"
Widget
.StopCovid.Button.Light"
>
<item
name=
"backgroundTint"
>
@color/color_primary_light
</item>
<item
name=
"android:textColor"
>
@color/color_on_primary_light
</item>
<item
name=
"rippleColor"
>
@color/color_primary
</item>
</style>
<style
name=
"
Theme
.StopCovid.Button.Danger"
parent=
"
Theme
.StopCovid.Button.Light"
>
<style
name=
"
Widget
.StopCovid.Button.Danger"
parent=
"
Widget
.StopCovid.Button.Light"
>
<item
name=
"backgroundTint"
>
@color/color_error_light
</item>
<item
name=
"rippleColor"
>
@color/color_error
</item>
<item
name=
"android:textColor"
>
@color/color_error
</item>
...
...
coreui/src/main/res/values/styles.xml
View file @
bfed9529
...
...
@@ -26,6 +26,7 @@
<item
name=
"appBarLayoutStyle"
>
@style/Widget.MaterialComponents.AppBarLayout.Surface
</item>
<item
name=
"toolbarStyle"
>
@style/Widget.StopCovid.Toolbar.Surface
</item>
<item
name=
"actionMenuTextColor"
>
?colorControlNormal
</item>
<item
name=
"snackbarTextViewStyle"
>
@style/Widget.StopCovid.Snackbar.TextView
</item>
<item
name=
"android:windowTranslucentNavigation"
>
true
</item>
</style>
...
...
coreui/src/main/res/values/styles_widget.xml
View file @
bfed9529
...
...
@@ -23,7 +23,7 @@
<item
name=
"android:textColor"
>
?colorOnSurface
</item>
</style>
<style
name=
"
Theme
.StopCovid.Button"
parent=
"Widget.MaterialComponents.Button"
>
<style
name=
"
Widget
.StopCovid.Button"
parent=
"Widget.MaterialComponents.Button"
>
<item
name=
"android:padding"
>
@dimen/spacing_large
</item>
<item
name=
"android:textSize"
>
@dimen/button_font_size
</item>
<item
name=
"elevation"
>
0dp
</item>
...
...
@@ -33,7 +33,7 @@
<item
name=
"rippleColor"
>
@color/color_primary_light
</item>
</style>
<style
name=
"
Theme
.StopCovid.Button.Light"
parent=
"Widget.MaterialComponents.Button.OutlinedButton"
>
<style
name=
"
Widget
.StopCovid.Button.Light"
parent=
"Widget.MaterialComponents.Button.OutlinedButton"
>
<item
name=
"cornerRadius"
>
@dimen/corner_radius
</item>
<item
name=
"android:padding"
>
@dimen/spacing_large
</item>
<item
name=
"strokeColor"
>
@color/color_primary_light
</item>
...
...
@@ -45,7 +45,7 @@
<item
name=
"android:letterSpacing"
>
@dimen/button_letter_spacing
</item>
</style>
<style
name=
"
Theme
.StopCovid.Button.Danger"
parent=
"
Theme
.StopCovid.Button.Light"
>
<style
name=
"
Widget
.StopCovid.Button.Danger"
parent=
"
Widget
.StopCovid.Button.Light"
>
<item
name=
"strokeColor"
>
@color/color_error_light
</item>
<item
name=
"elevation"
>
0dp
</item>
<item
name=
"android:textAllCaps"
>
false
</item>
...
...
@@ -53,7 +53,7 @@
<item
name=
"android:textColor"
>
@color/color_error
</item>
</style>
<style
name=
"
Theme
.StopCovid.TextInput"
parent=
"Widget.MaterialComponents.TextInputLayout.OutlinedBox"
>
<style
name=
"
Widget
.StopCovid.TextInput"
parent=
"Widget.MaterialComponents.TextInputLayout.OutlinedBox"
>
<item
name=
"boxCornerRadiusTopStart"
>
@dimen/corner_radius
</item>
<item
name=
"boxCornerRadiusTopEnd"
>
@dimen/corner_radius
</item>
<item
name=
"boxCornerRadiusBottomStart"
>
@dimen/corner_radius
</item>
...
...
@@ -64,4 +64,8 @@
<item
name=
"errorEnabled"
>
true
</item>
</style>
<style
name=
"Widget.StopCovid.Snackbar.TextView"
parent=
"@style/Widget.MaterialComponents.Snackbar.TextView"
>
<item
name=
"android:maxLines"
>
5
</item>
</style>
</resources>
\ No newline at end of file
framework/src/androidTest/java/com/lunabeestudio/framework/local/LocalCryptoManagerTest.kt
0 → 100644
View file @
bfed9529
/*
* 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/.
*
* Authors
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Created by Lunabee Studio / Date - 2020/09/06 - for the STOP-COVID project
*/
package
com.lunabeestudio.framework.local
import
android.content.Context
import
androidx.test.core.app.ApplicationProvider
import
com.google.common.truth.Truth.assertThat
import
org.junit.Before
import
org.junit.Test
import
kotlin.random.Random
class
LocalCryptoManagerTest
{
private
lateinit
var
localCryptoManager
:
LocalCryptoManager
@Before
fun
init
()
{
val
context
=
ApplicationProvider
.
getApplicationContext
<
Context
>()
localCryptoManager
=
LocalCryptoManager
(
context
)
}
@Test
fun
encrypt_decrypt_shortByteArray
()
{
val
passphrase
=
Random
.
nextBytes
(
Random
.
nextInt
(
0
,
4096
))
val
encrypted
=
localCryptoManager
.
encrypt
(
passphrase
.
copyOf
())
val
decrypted
=
localCryptoManager
.
decrypt
(
encrypted
)
assertThat
(
encrypted
).
isNotEqualTo
(
passphrase
)
assertThat
(
decrypted
).
isEqualTo
(
passphrase
)
}
@Test
fun
encrypt_decrypt_longByteArray
()
{
val
passphrase
=
Random
.
nextBytes
(
Random
.
nextInt
(
4096
,
16384
))
val
encrypted
=
localCryptoManager
.
encrypt
(
passphrase
.
copyOf
())
val
decrypted
=
localCryptoManager
.
decrypt
(
encrypted
)
assertThat
(
encrypted
).
isNotEqualTo
(
passphrase
)
assertThat
(
decrypted
).
isEqualTo
(
passphrase
)
}
}
\ No newline at end of file
framework/src/androidTest/java/com/lunabeestudio/framework/local/datasource/KeystoreDataSourceTest.kt
View file @
bfed9529
...
...
@@ -70,6 +70,24 @@ class KeystoreDataSourceTest {
assert
(
key
.
contentEquals
(
decryptedKey
!!
))
}
@Test
fun
saveLongString_and_getLongString
()
{
val
key
=
Random
.
nextBytes
(
8732
)
keystoreDataSource
.
kA
=
key
val
storedString
=
ApplicationProvider
.
getApplicationContext
<
Context
>()
.
getSharedPreferences
(
"robert_prefs"
,
Context
.
MODE_PRIVATE
)
.
getString
(
"shared.pref.ka"
,
null
)
assertThat
(
storedString
).
isNotNull
()
assertThat
(
storedString
).
isNotEqualTo
(
key
)
val
decryptedKey
=
keystoreDataSource
.
kA
assertThat
(
decryptedKey
).
isNotNull
()
assert
(
key
.
contentEquals
(
decryptedKey
!!
))
}
@Test
fun
saveKA_and_removeKA
()
{
val
key
=
Random
.
nextBytes
(
16
)
...
...
framework/src/main/java/com/lunabeestudio/framework/local/LocalCryptoManager.kt
View file @
bfed9529
...
...
@@ -18,14 +18,15 @@ import android.security.KeyPairGeneratorSpec
import
android.security.keystore.KeyGenParameterSpec
import
android.security.keystore.KeyProperties
import
android.util.Base64
import
com.lunabeestudio.domain.extension.safeUse
import
com.lunabeestudio.framework.utils.SelfDestroyCipherInputStream
import
com.lunabeestudio.framework.utils.SelfDestroyCipherOutputStream
import
com.lunabeestudio.robert.extension.randomize
import
java.io.ByteArrayOutputStream
import
java.io.File
import
java.io.IOException
import
java.io.InputStream
import
java.io.OutputStream
import
java.io.StringWriter
import
java.math.BigInteger
import
java.security.InvalidAlgorithmParameterException
import
java.security.InvalidKeyException
...
...
@@ -75,7 +76,7 @@ class LocalCryptoManager(private val appContext: Context) {
val
tmpFile
=
createTempFile
(
directory
=
targetFile
.
parentFile
)
createCipherOutputStream
(
tmpFile
.
outputStream
()).
use
{
output
->
clearText
.
byteInputStream
().
use
{
input
->
input
.
copyTo
(
output
)
input
.
copyTo
(
output
,
BUFFER_SIZE
)
}
}
tmpFile
.
renameTo
(
targetFile
)
...
...
@@ -83,31 +84,20 @@ class LocalCryptoManager(private val appContext: Context) {
@Synchronized
fun
encrypt
(
passphrase
:
ByteArray
,
clearPassphrase
:
Boolean
=
true
):
ByteArray
{
val
iv
=
ByteArray
(
AES_GCM_IV_LENGTH
)
val
cipher
=
Cipher
.
getInstance
(
AES_GCM_CIPHER_TYPE
)
val
ciphertext
=
localProtectionKey
.
safeUse
{
secretKey
->
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
M
)
{
cipher
.
init
(
Cipher
.
ENCRYPT_MODE
,
secretKey
)
cipher
.
iv
.
copyInto
(
iv
)
}
else
{
prng
.
nextBytes
(
iv
)
cipher
.
init
(
Cipher
.
ENCRYPT_MODE
,
secretKey
,
IvParameterSpec
(
iv
))
val
bos
=
ByteArrayOutputStream
()
createCipherOutputStream
(
bos
,
false
).
use
{
cos
->
passphrase
.
inputStream
().
use
{
input
->
input
.
copyTo
(
cos
,
BUFFER_SIZE
)
}
cipher
.
doFinal
(
passphrase
)
}
val
ciphertext
=
bos
.
toByteArray
()
if
(
clearPassphrase
)
{
passphrase
.
randomize
()
}
val
encrypted
=
ByteArray
(
iv
.
size
+
ciphertext
.
size
)
System
.
arraycopy
(
iv
,
0
,
encrypted
,
0
,
iv
.
size
)
System
.
arraycopy
(
ciphertext
,
0
,
encrypted
,
iv
.
size
,
ciphertext
.
size
)
return
encrypted
return
ciphertext
}
fun
decrypt
(
encryptedText
:
String
):
ByteArray
{
...
...
@@ -120,25 +110,22 @@ class LocalCryptoManager(private val appContext: Context) {
val
fis
=
file
.
inputStream
()
val
cis
=
createCipherInputStream
(
fis
)
return
cis
.
reader
().
use
{
it
.
readText
()
return
cis
.
reader
().
use
{
reader
->
val
buffer
=
StringWriter
()
reader
.
copyTo
(
buffer
,
BUFFER_SIZE
)
buffer
.
toString
()
}
}
@Synchronized
fun
decrypt
(
encryptedData
:
ByteArray
):
ByteArray
{
val
iv
:
ByteArray
=
encryptedData
.
copyOfRange
(
0
,
AES_GCM_IV_LENGTH
)
val
cipher
=
Cipher
.
getInstance
(
AES_GCM_CIPHER_TYPE
)
val
ivSpec
=
GCMParameterSpec
(
AES_GCM_KEY_SIZE_IN_BITS
,
iv
)
return
localProtectionKey
.
safeUse
{
secretKey
->
cipher
.
init
(
Cipher
.
DECRYPT_MODE
,
secretKey
,
ivSpec
)
cipher
.
doFinal
(
encryptedData
,
AES_GCM_IV_LENGTH
,
encryptedData
.
size
-
AES_GCM_IV_LENGTH
)
val
bos
=
ByteArrayOutputStream
()
bos
.
use
{
output
->
createCipherInputStream
(
encryptedData
.
inputStream
(),
AES_GCM_IV_LENGTH
).
use
{
cis
->
cis
.
copyTo
(
output
,
BUFFER_SIZE
)
}
}
return
bos
.
toByteArray
()
}
/**
...
...
@@ -237,7 +224,7 @@ class LocalCryptoManager(private val appContext: Context) {
NoSuchProviderException
::
class
,
KeyStoreException
::
class
,
IllegalBlockSizeException
::
class
)
fun
createCipherOutputStream
(
outputStream
:
OutputStream
):
OutputStream
{
fun
createCipherOutputStream
(
outputStream
:
OutputStream
,
writeIvSize
:
Boolean
=
true
):
OutputStream
{
val
cipher
=
Cipher
.
getInstance
(
AES_GCM_CIPHER_TYPE
)
val
iv
:
ByteArray
=
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
M
)
{
cipher
.
init
(
Cipher
.
ENCRYPT_MODE
,
localProtectionKey
)
...
...
@@ -249,7 +236,9 @@ class LocalCryptoManager(private val appContext: Context) {
iv
}
outputStream
.
write
(
iv
.
size
)
if
(
writeIvSize
)
{
outputStream
.
write
(
iv
.
size
)
}
outputStream
.
write
(
iv
)
return
SelfDestroyCipherOutputStream
(
outputStream
,
cipher
,
localProtectionKey
)
...
...
@@ -259,6 +248,7 @@ class LocalCryptoManager(private val appContext: Context) {
* Create a CipherInputStream instance.
*
* @param inputStream the input stream
* @param pIvLength the length of the IV of null if it should be read at the beginning of the stream
* @return the created InputStream
*/
@Throws
(
NoSuchPaddingException
::
class
,
...
...
@@ -271,9 +261,9 @@ class LocalCryptoManager(private val appContext: Context) {
NoSuchProviderException
::
class
,
InvalidAlgorithmParameterException
::
class
,
IOException
::
class
)
fun
createCipherInputStream
(
inputStream
:
InputStream
):
InputStream
{
fun
createCipherInputStream
(
inputStream
:
InputStream
,
pIvLength
:
Int
?
=
null
):
InputStream
{
inputStream
.
mark
(
4
+
AES_GCM_IV_LENGTH
)
val
ivLen
:
Int
=
inputStream
.
read
()
val
ivLen
:
Int
=
pIvLength
?:
inputStream
.
read
()
val
iv
=
ByteArray
(
ivLen
)
inputStream
.
read
(
iv
)
val
cipher
=
Cipher
.
getInstance
(
AES_GCM_CIPHER_TYPE
)
...
...
@@ -302,6 +292,8 @@ class LocalCryptoManager(private val appContext: Context) {
private
const
val
RSA_WRAP_CIPHER_TYPE
=
"RSA/NONE/PKCS1Padding"
private
const
val
AES_WRAPPED_PROTECTION_KEY_SHARED_PREFERENCE
=
"aes_wrapped_local_protection"
private
const
val
BUFFER_SIZE
=
4
*
1024
private
val
prng
:
SecureRandom
=
SecureRandom
()
}
}
\ No newline at end of file
framework/src/main/java/com/lunabeestudio/framework/remote/RetrofitClient.kt
View file @
bfed9529
...
...
@@ -80,10 +80,10 @@ object RetrofitClient {
}
addInterceptor
(
getDefaultHeaderInterceptor
())
addInterceptor
(
getLogInterceptor
())
callTimeout
(
1
L
,
TimeUnit
.
MINUTE
S
)
connectTimeout
(
1
L
,
TimeUnit
.
MINUTE
S
)
readTimeout
(
1
L
,
TimeUnit
.
MINUTE
S
)
writeTimeout
(
1
L
,
TimeUnit
.
MINUTE
S
)
callTimeout
(
30
L
,
TimeUnit
.
SECOND
S
)
connectTimeout
(
30
L
,
TimeUnit
.
SECOND
S
)
readTimeout
(
30
L
,
TimeUnit
.
SECOND
S
)
writeTimeout
(
30
L
,
TimeUnit
.
SECOND
S
)
}.
build
()
}
...
...
robert/src/main/java/com/lunabeestudio/robert/RobertApplication.kt
View file @
bfed9529
...
...
@@ -17,4 +17,5 @@ interface RobertApplication {
fun
getAppContext
():
Context
fun
refreshProximityService
()
fun
atRiskDetected
()
fun
sendClockNotAlignedNotification
()
}
\ No newline at end of file
robert/src/main/java/com/lunabeestudio/robert/RobertConstant.kt
View file @
bfed9529
...
...
@@ -25,6 +25,7 @@ internal object RobertConstant {
const
val
BLE_SERVICE_UUID
:
String
=
"0000fd64-0000-1000-8000-00805f9b34fb"
const
val
BLE_CHARACTERISTIC_UUID
:
String
=
"a8f12d00-ee67-478b-b95f-65d599407756"
const
val
BLE_BACKGROUND_SERVICE_MANUFACTURER_DATA_IOS
:
String
=
"1.0.0.0.0.0.0.0.0.0.0.8.0.0.0.0.0"
const
val
MIN_GAP_SUCCESS_STATUS
:
Long
=
30L
*
60L
*
1000L
object
CONFIG
{
const
val
DATA_RETENTION_PERIOD
:
String
=
"app.dataRetentionPeriod"
...
...
robert/src/main/java/com/lunabeestudio/robert/RobertManager.kt
View file @
bfed9529
...
...
@@ -69,7 +69,7 @@ interface RobertManager {
suspend
fun
eraseLocalHistory
():
RobertResult
suspend
fun
eraseRemoteExposureHistory
():
RobertResult
suspend
fun
eraseRemoteExposureHistory
(
application
:
RobertApplication
):
RobertResult
suspend
fun
eraseRemoteAlert
():
RobertResult
...
...
robert/src/main/java/com/lunabeestudio/robert/RobertManagerImpl.kt
View file @
bfed9529
...
...
@@ -12,6 +12,7 @@ package com.lunabeestudio.robert
import
android.content.Context
import
android.util.Base64
import
androidx.work.ExistingPeriodicWorkPolicy
import
androidx.work.WorkManager
import
com.google.gson.Gson
import
com.google.gson.reflect.TypeToken
...
...
@@ -32,6 +33,7 @@ import com.lunabeestudio.robert.datasource.LocalLocalProximityDataSource
import
com.lunabeestudio.robert.datasource.RemoteServiceDataSource
import
com.lunabeestudio.robert.datasource.SharedCryptoDataSource
import
com.lunabeestudio.robert.extension.use
import
com.lunabeestudio.robert.model.TimeNotAlignedException
import
com.lunabeestudio.robert.model.NoEphemeralBluetoothIdentifierFound
import
com.lunabeestudio.robert.model.NoEphemeralBluetoothIdentifierFoundForEpoch
import
com.lunabeestudio.robert.model.NoKeyException
...
...
@@ -46,9 +48,8 @@ import com.lunabeestudio.robert.repository.LocalProximityRepository
import
com.lunabeestudio.robert.repository.RemoteServiceRepository
import
com.lunabeestudio.robert.worker.StatusWorker
import
timber.log.Timber
import
java.util.Date
import
java.util.concurrent.TimeUnit
import
kotlin.
random.Random
import
kotlin.
math.abs
class
RobertManagerImpl
(
application
:
RobertApplication
,
...
...
@@ -126,29 +127,30 @@ class RobertManagerImpl(
get
()
=
keystoreRepository
.
randomStatusHour
?:
RobertConstant
.
RANDOM_STATUS_HOUR
override
suspend
fun
register
(
application
:
RobertApplication
,
captcha
:
String
):
RobertResult
{
val
result
=
remoteServiceRepository
.
register
(
captcha
)
return
when
(
result
)
{
val
configResult
=
remoteServiceRepository
.
fetchConfig
(
application
.
getAppContext
())
return
when
(
configResult
)
{
is
RobertResultData
.
Success
->
{
if
(
result
.
data
.
configuration
.
isNullOrEmpty
())
{
val
configResult
=
remoteServiceRepository
.
fetchConfig
(
application
.
getAppContext
())
when
(
configResult
)
{
if
(
configResult
.
data
.
isNullOrEmpty
())
{
clearLocalData
(
application
)
RobertResult
.
Failure
(
RobertUnknownException
())
}
else
{
val
registerResult
=
remoteServiceRepository
.
register
(
captcha
)
when
(
registerResult
)
{
is
RobertResultData
.
Success
->
{
if
(
configResult
.
data
.
isNullOrEmpty
())
{
RobertResult
.
Failure
(
RobertUnknownException
())
}
else
{
finishRegister
(
application
,
result
.
data
,
configResult
.
data
)
}
finishRegister
(
application
,
registerResult
.
data
,
configResult
.
data
)
}
is
RobertResultData
.
Failure
->
{
clearLocalData
(
application
)
RobertResult
.
Failure
(
config
Result
.
error
)
RobertResult
.
Failure
(
register
Result
.
error
)
}
}
}
else
{
finishRegister
(
application
,
result
.
data
,
result
.
data
.
configuration
)
}
}
is
RobertResultData
.
Failure
->
RobertResult
.
Failure
(
result
.
error
)
is
RobertResultData
.
Failure
->
{
clearLocalData
(
application
)
RobertResult
.
Failure
(
configResult
.
error
)
}
}
}
...
...
@@ -163,6 +165,7 @@ class RobertManagerImpl(
activateProximity
(
application
)
RobertResult
.
Success
()
}
catch
(
e
:
Exception
)
{
Timber
.
e
(
e
)
clearLocalData
(
application
)
if
(
e
is
RobertException
)
{