This repository has been archived by the owner on Apr 12, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 113
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improved notification function that did not work normally even if the…
…re was close contact with a positive person on android app. Improved the case in which the application seems to be reset (usage start date is reset, the terms of use screen is displayed again, etc). when the application or OS is updated on some devices. Fixed the issue that the users who had close contact (within 1 meter for 15 minutes or more ) with a positive person were notified of the proximity to a positive person who did not meet the above condition on android app.
- Loading branch information
Showing
61 changed files
with
2,363 additions
and
1,536 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
154 changes: 154 additions & 0 deletions
154
Covid19Radar/Covid19Radar.Android/Services/PreferencesService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
using System; | ||
using Covid19Radar.Services; | ||
using Covid19Radar.Services.Logs; | ||
|
||
namespace Covid19Radar.Droid.Services | ||
{ | ||
public class PreferencesService : IPreferencesService | ||
{ | ||
private readonly ILoggerService loggerService; | ||
|
||
public PreferencesService(ILoggerService loggerService) | ||
{ | ||
this.loggerService = loggerService; | ||
} | ||
|
||
public bool ContainsKey(string key) | ||
{ | ||
var context = Android.App.Application.Context; | ||
var preference = context.GetSharedPreferences(context.PackageName, Android.Content.FileCreationMode.Private); | ||
return preference.Contains(key); | ||
} | ||
|
||
public T GetValue<T>(string key, T defaultValue) | ||
{ | ||
lock (this) | ||
{ | ||
loggerService.StartMethod(); | ||
loggerService.Info($"key={key}, type={typeof(T)}"); | ||
|
||
if (!ContainsKey(key)) | ||
{ | ||
loggerService.EndMethod(); | ||
return defaultValue; | ||
} | ||
|
||
var context = Android.App.Application.Context; | ||
var preference = context.GetSharedPreferences(context.PackageName, Android.Content.FileCreationMode.Private); | ||
try | ||
{ | ||
object value = null; | ||
if (defaultValue == null) | ||
{ | ||
value = preference.GetString(key, null); | ||
return (T)value; | ||
} | ||
|
||
switch (defaultValue) | ||
{ | ||
case int i: | ||
value = preference.GetInt(key, i); | ||
break; | ||
case bool b: | ||
value = preference.GetBoolean(key, b); | ||
break; | ||
case float f: | ||
value = preference.GetFloat(key, f); | ||
break; | ||
case string s: | ||
value = preference.GetString(key, s); | ||
break; | ||
case DateTime d: | ||
var valueString = preference.GetString(key, d.ToString()); | ||
value = DateTime.Parse(valueString); | ||
break; | ||
default: | ||
loggerService.Info("Type is not supported."); | ||
value = defaultValue; | ||
break; | ||
} | ||
|
||
loggerService.EndMethod(); | ||
return (T)value; | ||
} | ||
catch (Exception) | ||
{ | ||
loggerService.Error($"Failed to get value of {key}"); | ||
loggerService.EndMethod(); | ||
return defaultValue; | ||
} | ||
} | ||
} | ||
|
||
public void SetValue<T>(string key, T value) | ||
{ | ||
lock (this) | ||
{ | ||
loggerService.StartMethod(); | ||
loggerService.Info($"key={key}, type={typeof(T)}"); | ||
|
||
var context = Android.App.Application.Context; | ||
var preference = context.GetSharedPreferences(context.PackageName, Android.Content.FileCreationMode.Private); | ||
var editor = preference.Edit(); | ||
|
||
bool result; | ||
|
||
if (ContainsKey(key) && value == null) | ||
{ | ||
editor.Remove(key); | ||
result = editor.Commit(); | ||
} | ||
else | ||
{ | ||
switch (value) | ||
{ | ||
case int i: | ||
editor.PutInt(key, i); | ||
break; | ||
case bool b: | ||
editor.PutBoolean(key, b); | ||
break; | ||
case float f: | ||
editor.PutFloat(key, f); | ||
break; | ||
case string s: | ||
editor.PutString(key, s); | ||
break; | ||
case DateTime d: | ||
var valueString = d.ToString(); | ||
editor.PutString(key, valueString); | ||
break; | ||
} | ||
result = editor.Commit(); | ||
} | ||
|
||
if (!result) | ||
{ | ||
loggerService.Error($"Failed to save value of {key}"); | ||
} | ||
|
||
loggerService.EndMethod(); | ||
} | ||
} | ||
|
||
public void RemoveValue(string key) | ||
{ | ||
lock (this) | ||
{ | ||
loggerService.StartMethod(); | ||
|
||
if (ContainsKey(key)) | ||
{ | ||
loggerService.Info($"key={key}"); | ||
|
||
var context = Android.App.Application.Context; | ||
var preference = context.GetSharedPreferences(context.PackageName, Android.Content.FileCreationMode.Private); | ||
var editor = preference.Edit(); | ||
editor.Remove(key).Commit(); | ||
} | ||
|
||
loggerService.EndMethod(); | ||
} | ||
} | ||
} | ||
} |
126 changes: 126 additions & 0 deletions
126
Covid19Radar/Covid19Radar.Android/Services/SecureStorageServiceAndroid.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
using System; | ||
using Android.Content; | ||
using Android.Security.Keystore; | ||
using Covid19Radar.Droid.Services; | ||
using Covid19Radar.Services; | ||
using Java.Security; | ||
using Javax.Crypto; | ||
using Javax.Crypto.Spec; | ||
using Xamarin.Essentials; | ||
using Xamarin.Forms; | ||
|
||
[assembly: Dependency(typeof(SecureStorageServiceAndroid))] | ||
namespace Covid19Radar.Droid.Services | ||
{ | ||
public class SecureStorageServiceAndroid : ISecureStorageDependencyService | ||
{ | ||
private readonly string Alias = $"{AppInfo.PackageName}.securestorage"; | ||
private readonly int IvLength = 12; | ||
private readonly int GcmTagLength = 128; | ||
private readonly string KeyStoreType = "AndroidKeyStore"; | ||
private readonly string CipherTransformation = "AES/GCM/NoPadding"; | ||
|
||
private readonly ISharedPreferences sharedPreferences; | ||
|
||
public SecureStorageServiceAndroid() | ||
{ | ||
sharedPreferences = Android.App.Application.Context.GetSharedPreferences(Alias, FileCreationMode.Private); | ||
} | ||
|
||
public bool ContainsKey(string key) | ||
{ | ||
return sharedPreferences.Contains(key); | ||
} | ||
|
||
public byte[] GetBytes(string key) | ||
{ | ||
byte[] result = null; | ||
|
||
if (sharedPreferences.Contains(key)) | ||
{ | ||
var loadedText = sharedPreferences.GetString(key, ""); | ||
var loadedBytes = Convert.FromBase64String(loadedText); | ||
if (loadedBytes.Length <= IvLength) | ||
{ | ||
throw new InvalidOperationException("Invalid read data."); | ||
} | ||
|
||
var iv = new byte[IvLength]; | ||
Array.Copy(loadedBytes, 0, iv, 0, iv.Length); | ||
|
||
var encryptedBytes = new byte[loadedBytes.Length - iv.Length]; | ||
Array.Copy(loadedBytes, iv.Length, encryptedBytes, 0, encryptedBytes.Length); | ||
|
||
var keyStore = KeyStore.GetInstance(KeyStoreType); | ||
keyStore.Load(null); | ||
|
||
var storeKey = keyStore.GetKey(Alias, null); | ||
if (storeKey == null) | ||
{ | ||
throw new InvalidOperationException("Could not get the KeyStore key."); | ||
} | ||
|
||
var cipher = Cipher.GetInstance(CipherTransformation); | ||
cipher.Init(CipherMode.DecryptMode, storeKey, new GCMParameterSpec(GcmTagLength, iv)); | ||
result = cipher.DoFinal(encryptedBytes); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
public void Remove(string key) | ||
{ | ||
if (sharedPreferences.Contains(key)) | ||
{ | ||
var edit = sharedPreferences.Edit(); | ||
edit.Remove(key); | ||
edit.Commit(); | ||
} | ||
} | ||
|
||
public void SetBytes(string key, byte[] bytes) | ||
{ | ||
var keyStore = KeyStore.GetInstance(KeyStoreType); | ||
keyStore.Load(null); | ||
|
||
var storeKey = keyStore.GetKey(Alias, null); | ||
if (storeKey == null) | ||
{ | ||
var generator = KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, KeyStoreType); | ||
var spec = new KeyGenParameterSpec.Builder(Alias, KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt) | ||
.SetBlockModes(KeyProperties.BlockModeGcm) | ||
.SetEncryptionPaddings(KeyProperties.EncryptionPaddingNone) | ||
.SetRandomizedEncryptionRequired(false) | ||
.Build(); | ||
|
||
generator.Init(spec); | ||
generator.GenerateKey(); | ||
|
||
storeKey = keyStore.GetKey(Alias, null); | ||
if (storeKey == null) | ||
{ | ||
throw new InvalidOperationException("Failed KeyStore key generation."); | ||
} | ||
} | ||
|
||
var iv = new byte[IvLength]; | ||
var randam = new SecureRandom(); | ||
randam.NextBytes(iv); | ||
|
||
var cipher = Cipher.GetInstance(CipherTransformation); | ||
cipher.Init(CipherMode.EncryptMode, storeKey, new GCMParameterSpec(GcmTagLength, iv)); | ||
|
||
var encryptedBytes = cipher.DoFinal(bytes); | ||
|
||
var saveBytes = new byte[iv.Length + encryptedBytes.Length]; | ||
Array.Copy(iv, 0, saveBytes, 0, iv.Length); | ||
Array.Copy(encryptedBytes, 0, saveBytes, iv.Length, encryptedBytes.Length); | ||
|
||
var saveText = Convert.ToBase64String(saveBytes); | ||
|
||
var edit = sharedPreferences.Edit(); | ||
edit.PutString(key, saveText); | ||
edit.Commit(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.