diff --git a/Chiota.sln b/Chiota.sln
index c11b3ee..b3892b8 100644
--- a/Chiota.sln
+++ b/Chiota.sln
@@ -11,6 +11,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Chiota.UWP", "Chiota\Chiota
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NTRUEngine", "Chiota\NTRU-NET-master\NTRUEngine.csproj", "{A25C6AB8-531E-4A7E-9968-305003D56332}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UWPRuntimeComponent", "UWPRuntimeComponent\UWPRuntimeComponent.csproj", "{A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -339,6 +341,66 @@ Global
{A25C6AB8-531E-4A7E-9968-305003D56332}.Release|x64.Build.0 = Release|Any CPU
{A25C6AB8-531E-4A7E-9968-305003D56332}.Release|x86.ActiveCfg = Release|x86
{A25C6AB8-531E-4A7E-9968-305003D56332}.Release|x86.Build.0 = Release|x86
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Debug|ARM.ActiveCfg = Debug|ARM
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Debug|ARM.Build.0 = Debug|ARM
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Debug|x64.ActiveCfg = Debug|x64
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Debug|x64.Build.0 = Debug|x64
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Debug|x86.ActiveCfg = Debug|x86
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Debug|x86.Build.0 = Debug|x86
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Fast|Any CPU.ActiveCfg = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Fast|Any CPU.Build.0 = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Fast|ARM.ActiveCfg = Release|ARM
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Fast|ARM.Build.0 = Release|ARM
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Fast|ARM64.ActiveCfg = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Fast|ARM64.Build.0 = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Fast|x64.ActiveCfg = Release|x64
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Fast|x64.Build.0 = Release|x64
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Fast|x86.ActiveCfg = Release|x86
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Fast|x86.Build.0 = Release|x86
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Generic|Any CPU.ActiveCfg = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Generic|Any CPU.Build.0 = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Generic|ARM.ActiveCfg = Release|ARM
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Generic|ARM.Build.0 = Release|ARM
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Generic|ARM64.ActiveCfg = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Generic|ARM64.Build.0 = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Generic|x64.ActiveCfg = Release|x64
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Generic|x64.Build.0 = Release|x64
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Generic|x86.ActiveCfg = Release|x86
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Generic|x86.Build.0 = Release|x86
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-fast|Any CPU.ActiveCfg = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-fast|Any CPU.Build.0 = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-fast|ARM.ActiveCfg = Release|ARM
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-fast|ARM.Build.0 = Release|ARM
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-fast|ARM64.ActiveCfg = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-fast|ARM64.Build.0 = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-fast|x64.ActiveCfg = Release|x64
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-fast|x64.Build.0 = Release|x64
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-fast|x86.ActiveCfg = Release|x86
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-fast|x86.Build.0 = Release|x86
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-generic|Any CPU.ActiveCfg = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-generic|Any CPU.Build.0 = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-generic|ARM.ActiveCfg = Release|ARM
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-generic|ARM.Build.0 = Release|ARM
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-generic|ARM64.ActiveCfg = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-generic|ARM64.Build.0 = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-generic|x64.ActiveCfg = Release|x64
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-generic|x64.Build.0 = Release|x64
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-generic|x86.ActiveCfg = Release|x86
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Optimized-generic|x86.Build.0 = Release|x86
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Release|ARM.ActiveCfg = Release|ARM
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Release|ARM.Build.0 = Release|ARM
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Release|ARM64.Build.0 = Release|Any CPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Release|x64.ActiveCfg = Release|x64
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Release|x64.Build.0 = Release|x64
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Release|x86.ActiveCfg = Release|x86
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Chiota/Chiota.Android/Chiota.Android.csproj b/Chiota/Chiota.Android/Chiota.Android.csproj
index a06ffcb..70229e0 100644
--- a/Chiota/Chiota.Android/Chiota.Android.csproj
+++ b/Chiota/Chiota.Android/Chiota.Android.csproj
@@ -59,6 +59,9 @@
+
+ ..\..\..\..\..\.nuget\packages\zxing.net.mobile\2.4.1\lib\MonoAndroid71\ZXingNetMobile.dll
+
@@ -80,7 +83,7 @@
0.6.0
- 9.1.0
+ 9.1.1
3.1.3
@@ -94,7 +97,7 @@
3.0.0-beta14
-
+
@@ -105,12 +108,14 @@
-
-
+
+
-
+
+
+
@@ -160,6 +165,10 @@
{a569a7a8-467d-45bd-8848-00f6a0dc34bc}
Chiota
+
+ {a25c6ab8-531e-4a7e-9968-305003d56332}
+ NTRUEngine
+
@@ -176,5 +185,8 @@
+
+
+
\ No newline at end of file
diff --git a/Chiota/Chiota.Android/MainActivity.cs b/Chiota/Chiota.Android/MainActivity.cs
index fcfae89..3909f94 100644
--- a/Chiota/Chiota.Android/MainActivity.cs
+++ b/Chiota/Chiota.Android/MainActivity.cs
@@ -1,17 +1,21 @@
namespace Chiota.Droid
{
using Android.App;
+ using Android.Content;
using Android.Content.PM;
using Android.OS;
using Chiota;
-
+ using Chiota.Droid.Services;
+ using Chiota.Messages;
using ImageCircle.Forms.Plugin.Droid;
using Plugin.LocalNotifications;
using Plugin.Permissions;
+ using Xamarin.Forms;
+
[Activity(Label = "FlorenceApp", Icon = "@drawable/icon", Theme = "@style/MainTheme", MainLauncher = false, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
@@ -30,9 +34,10 @@ protected override void OnCreate(Bundle bundle)
ImageCircleRenderer.Init();
// Changes the notification icon
- LocalNotificationsImplementation.NotificationIconId = Resource.Drawable.icon;
+ LocalNotificationsImplementation.NotificationIconId = Resource.Drawable.reminder;
this.LoadApplication(new App());
+ this.WireUpLongRunningTask();
}
// https://github.com/jamesmontemagno/MediaPlugin#important-permission-information
@@ -41,5 +46,26 @@ public override void OnRequestPermissionsResult(int requestCode, string[] permis
ZXing.Net.Mobile.Android.PermissionsHandler.OnRequestPermissionsResult(requestCode, permissions, grantResults);
PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
+
+ public void WireUpLongRunningTask()
+ {
+ MessagingCenter.Subscribe(
+ this,
+ "StartLongRunningTaskMessage",
+ message =>
+ {
+ var intent = new Intent(this, typeof(PeriodicTaskService));
+ this.StartService(intent);
+ });
+
+ MessagingCenter.Subscribe(
+ this,
+ "StopLongRunningTaskMessage",
+ message =>
+ {
+ var intent = new Intent(this, typeof(PeriodicTaskService));
+ this.StopService(intent);
+ });
+ }
}
}
\ No newline at end of file
diff --git a/Chiota/Chiota.Android/Properties/AndroidManifest.xml b/Chiota/Chiota.Android/Properties/AndroidManifest.xml
index f68b9a5..c7bb1ae 100644
--- a/Chiota/Chiota.Android/Properties/AndroidManifest.xml
+++ b/Chiota/Chiota.Android/Properties/AndroidManifest.xml
@@ -6,5 +6,6 @@
+
\ No newline at end of file
diff --git a/Chiota/Chiota.Android/FlatButtonRenderer.cs b/Chiota/Chiota.Android/Renderer/FlatButtonRenderer.cs
similarity index 100%
rename from Chiota/Chiota.Android/FlatButtonRenderer.cs
rename to Chiota/Chiota.Android/Renderer/FlatButtonRenderer.cs
diff --git a/Chiota/Chiota.Android/Scrollbardisabledrenderer.cs b/Chiota/Chiota.Android/Renderer/Scrollbardisabledrenderer.cs
similarity index 100%
rename from Chiota/Chiota.Android/Scrollbardisabledrenderer.cs
rename to Chiota/Chiota.Android/Renderer/Scrollbardisabledrenderer.cs
diff --git a/Chiota/Chiota.Android/Resources/Resource.designer.cs b/Chiota/Chiota.Android/Resources/Resource.designer.cs
index d1b80ec..2d99489 100644
--- a/Chiota/Chiota.Android/Resources/Resource.designer.cs
+++ b/Chiota/Chiota.Android/Resources/Resource.designer.cs
@@ -28,7 +28,12 @@ public static void UpdateIdValues()
{
global::Plugin.LocalNotifications.Resource.Drawable.plugin_lc_smallicon = global::Chiota.Droid.Resource.Drawable.plugin_lc_smallicon;
global::Xamarin.Forms.Platform.Android.Resource.Attribute.actionBarSize = global::Chiota.Droid.Resource.Attribute.actionBarSize;
+ global::ZXing.Net.Mobile.Forms.Android.Resource.Layout.zxingscanneractivitylayout = global::Chiota.Droid.Resource.Layout.zxingscanneractivitylayout;
+ global::ZXing.Net.Mobile.Forms.Android.Resource.Layout.zxingscannerfragmentlayout = global::Chiota.Droid.Resource.Layout.zxingscannerfragmentlayout;
global::ZXing.Net.Mobile.Forms.Android.Resource.String.library_name = global::Chiota.Droid.Resource.String.library_name;
+ global::ZXing.Mobile.Resource.Id.contentFrame = global::Chiota.Droid.Resource.Id.contentFrame;
+ global::ZXing.Mobile.Resource.Layout.zxingscanneractivitylayout = global::Chiota.Droid.Resource.Layout.zxingscanneractivitylayout;
+ global::ZXing.Mobile.Resource.Layout.zxingscannerfragmentlayout = global::Chiota.Droid.Resource.Layout.zxingscannerfragmentlayout;
}
public partial class Animation
@@ -2350,26 +2355,26 @@ public partial class Drawable
// aapt resource value: 0x7f020053
public const int avd_hide_password = 2130837587;
- // aapt resource value: 0x7f020135
- public const int avd_hide_password_1 = 2130837813;
-
// aapt resource value: 0x7f020136
- public const int avd_hide_password_2 = 2130837814;
+ public const int avd_hide_password_1 = 2130837814;
// aapt resource value: 0x7f020137
- public const int avd_hide_password_3 = 2130837815;
+ public const int avd_hide_password_2 = 2130837815;
+
+ // aapt resource value: 0x7f020138
+ public const int avd_hide_password_3 = 2130837816;
// aapt resource value: 0x7f020054
public const int avd_show_password = 2130837588;
- // aapt resource value: 0x7f020138
- public const int avd_show_password_1 = 2130837816;
-
// aapt resource value: 0x7f020139
- public const int avd_show_password_2 = 2130837817;
+ public const int avd_show_password_1 = 2130837817;
// aapt resource value: 0x7f02013a
- public const int avd_show_password_3 = 2130837818;
+ public const int avd_show_password_2 = 2130837818;
+
+ // aapt resource value: 0x7f02013b
+ public const int avd_show_password_3 = 2130837819;
// aapt resource value: 0x7f020055
public const int design_bottom_navigation_item_background = 2130837589;
@@ -3016,11 +3021,11 @@ public partial class Drawable
// aapt resource value: 0x7f02012b
public const int notification_icon_background = 2130837803;
- // aapt resource value: 0x7f020133
- public const int notification_template_icon_bg = 2130837811;
-
// aapt resource value: 0x7f020134
- public const int notification_template_icon_low_bg = 2130837812;
+ public const int notification_template_icon_bg = 2130837812;
+
+ // aapt resource value: 0x7f020135
+ public const int notification_template_icon_low_bg = 2130837813;
// aapt resource value: 0x7f02012c
public const int notification_tile_bg = 2130837804;
@@ -3035,13 +3040,16 @@ public partial class Drawable
public const int plus = 2130837807;
// aapt resource value: 0x7f020130
- public const int splash_screen = 2130837808;
+ public const int reminder = 2130837808;
// aapt resource value: 0x7f020131
- public const int tooltip_frame_dark = 2130837809;
+ public const int splash_screen = 2130837809;
// aapt resource value: 0x7f020132
- public const int tooltip_frame_light = 2130837810;
+ public const int tooltip_frame_dark = 2130837810;
+
+ // aapt resource value: 0x7f020133
+ public const int tooltip_frame_light = 2130837811;
static Drawable()
{
@@ -3194,6 +3202,9 @@ public partial class Id
// aapt resource value: 0x7f09008c
public const int container = 2131296396;
+ // aapt resource value: 0x7f0900c8
+ public const int contentFrame = 2131296456;
+
// aapt resource value: 0x7f090065
public const int contentPanel = 2131296357;
@@ -3317,8 +3328,8 @@ public partial class Id
// aapt resource value: 0x7f090060
public const int list_item = 2131296352;
- // aapt resource value: 0x7f0900c9
- public const int masked = 2131296457;
+ // aapt resource value: 0x7f0900ca
+ public const int masked = 2131296458;
// aapt resource value: 0x7f0900b8
public const int media_actions = 2131296440;
@@ -3650,8 +3661,8 @@ public partial class Id
// aapt resource value: 0x7f090016
public const int view_offset_helper = 2131296278;
- // aapt resource value: 0x7f0900c8
- public const int visible = 2131296456;
+ // aapt resource value: 0x7f0900c9
+ public const int visible = 2131296457;
// aapt resource value: 0x7f0900aa
public const int volume_item_container = 2131296426;
@@ -3953,6 +3964,12 @@ public partial class Layout
// aapt resource value: 0x7f030044
public const int tooltip = 2130903108;
+ // aapt resource value: 0x7f030045
+ public const int zxingscanneractivitylayout = 2130903109;
+
+ // aapt resource value: 0x7f030046
+ public const int zxingscannerfragmentlayout = 2130903110;
+
static Layout()
{
global::Android.Runtime.ResourceIdManager.UpdateIdValues();
diff --git a/Chiota/Chiota.Android/Resources/drawable/iota.png b/Chiota/Chiota.Android/Resources/drawable/iota.png
index 7d03b99..4f76f10 100644
Binary files a/Chiota/Chiota.Android/Resources/drawable/iota.png and b/Chiota/Chiota.Android/Resources/drawable/iota.png differ
diff --git a/Chiota/Chiota.Android/Resources/drawable/old/reminder.png b/Chiota/Chiota.Android/Resources/drawable/old/reminder.png
new file mode 100644
index 0000000..5e3af84
Binary files /dev/null and b/Chiota/Chiota.Android/Resources/drawable/old/reminder.png differ
diff --git a/Chiota/Chiota.Android/Resources/drawable/reminder.png b/Chiota/Chiota.Android/Resources/drawable/reminder.png
new file mode 100644
index 0000000..9a5cb91
Binary files /dev/null and b/Chiota/Chiota.Android/Resources/drawable/reminder.png differ
diff --git a/Chiota/Chiota.Android/Services/BackgroundReceiver.cs b/Chiota/Chiota.Android/Services/BackgroundReceiver.cs
new file mode 100644
index 0000000..02bd003
--- /dev/null
+++ b/Chiota/Chiota.Android/Services/BackgroundReceiver.cs
@@ -0,0 +1,46 @@
+namespace Chiota.Droid.Services
+{
+ using System.Linq;
+
+ using Android.Content;
+ using Android.OS;
+
+ using Chiota.Models;
+ using Chiota.Services;
+
+ using Plugin.LocalNotifications;
+
+ [BroadcastReceiver]
+ public class BackgroundReceiver : BroadcastReceiver
+ {
+ public override async void OnReceive(Context context, Intent intent)
+ {
+ var pm = (PowerManager)context.GetSystemService(Context.PowerService);
+ var wakeLock = pm.NewWakeLock(WakeLockFlags.Partial, "BackgroundReceiver");
+ wakeLock.Acquire();
+
+ // seed needs to be stored on device!!
+ var secureStorage = new SecureStorage();
+ if (secureStorage.CheckUserStored())
+ {
+ var user = await secureStorage.GetUser();
+ if (user != null)
+ {
+ var contactApprovedList = await user.TangleMessenger.GetJsonMessageAsync>(user.ApprovedAddress);
+
+ // Todo also message for a new contact request
+ foreach (var contact in contactApprovedList.Where(c => !c.Data.Rejected))
+ {
+ var encryptedMessages = await user.TangleMessenger.GetMessagesAsync(contact.Data.ChatAdress);
+ foreach (var unused in encryptedMessages.Where(c => !c.Stored))
+ {
+ CrossLocalNotifications.Current.Show(contact.Data.Name, "New Message from " + contact.Data.Name);
+ }
+ }
+ }
+ }
+
+ wakeLock.Release();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Chiota/Chiota.Android/ClipboardService.cs b/Chiota/Chiota.Android/Services/ClipboardService.cs
similarity index 100%
rename from Chiota/Chiota.Android/ClipboardService.cs
rename to Chiota/Chiota.Android/Services/ClipboardService.cs
diff --git a/Chiota/Chiota.Android/Services/PeriodicTaskService.cs b/Chiota/Chiota.Android/Services/PeriodicTaskService.cs
new file mode 100644
index 0000000..4295962
--- /dev/null
+++ b/Chiota/Chiota.Android/Services/PeriodicTaskService.cs
@@ -0,0 +1,78 @@
+namespace Chiota.Droid.Services
+{
+ using System.Threading;
+ using System.Threading.Tasks;
+
+ using Android.App;
+ using Android.Content;
+ using Android.OS;
+ using Android.Runtime;
+
+ using Chiota.Messages;
+
+ using Xamarin.Forms;
+
+ //Todo https://blog.xamarin.com/replacing-services-jobs-android-oreo-8-0/
+ [Service]
+ public class PeriodicTaskService : Service
+ {
+ private CancellationTokenSource cts;
+
+ public override IBinder OnBind(Intent intent)
+ {
+ return null;
+ }
+
+ public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
+ {
+ this.cts = new CancellationTokenSource();
+
+ Task.Run(
+ () =>
+ {
+ try
+ {
+ // start backgroundreceiver
+ var alarmIntent = new Intent(this, typeof(BackgroundReceiver));
+
+ var pending = PendingIntent.GetBroadcast(this, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
+
+ var alarmManager = this.GetSystemService(AlarmService).JavaCast();
+
+ // alarmManager.Set(AlarmType.ElapsedRealtime, SystemClock.ElapsedRealtime() + 3 * 1000, pending);
+ alarmManager.SetRepeating(
+ AlarmType.RtcWakeup,
+ SystemClock.ElapsedRealtime(),
+ 1000 * 60 * 15, // updates every 15 minutes
+ pending);
+ }
+ catch (OperationCanceledException)
+ {
+ }
+ finally
+ {
+ if (this.cts.IsCancellationRequested)
+ {
+ var message = new CancelledMessage();
+ Device.BeginInvokeOnMainThread(() => MessagingCenter.Send(message, "CancelledMessage"));
+ }
+ }
+ },
+ this.cts.Token);
+
+ return StartCommandResult.Sticky;
+ }
+
+ public override void OnDestroy()
+ {
+ if (this.cts != null)
+ {
+ this.cts.Token.ThrowIfCancellationRequested();
+
+ this.cts.Cancel();
+ }
+
+ base.OnDestroy();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Chiota/Chiota.Android/SplashActivity.cs b/Chiota/Chiota.Android/SplashActivity.cs
index 9e10de1..ea6c29d 100644
--- a/Chiota/Chiota.Android/SplashActivity.cs
+++ b/Chiota/Chiota.Android/SplashActivity.cs
@@ -1,30 +1,16 @@
namespace Chiota.Droid
{
- using System.Threading.Tasks;
-
using Android.App;
using Android.Content;
- using Android.OS;
- using Android.Support.V7.App;
-
- using Chiota.Droid;
[Activity(Theme = "@style/SplashTheme", MainLauncher = true, NoHistory = true)]
- public class SplashActivity : Activity
+ public class SplashActivity : Activity
+ {
+ // Launches the startup task
+ protected override void OnResume()
{
- static readonly string TAG = "X:" + typeof(SplashActivity).Name;
-
- public override void OnCreate(Bundle savedInstanceState, PersistableBundle persistentState)
- {
- base.OnCreate(savedInstanceState, persistentState);
- }
-
- // Launches the startup task
- protected override void OnResume()
- {
- base.OnResume();
- this.StartActivity(new Intent(Application.Context, typeof(MainActivity)));
- }
-
+ base.OnResume();
+ this.StartActivity(new Intent(Application.Context, typeof(MainActivity)));
}
+ }
}
\ No newline at end of file
diff --git a/Chiota/Chiota.UWP/Assets/photothumb.db b/Chiota/Chiota.UWP/Assets/photothumb.db
index 9054b9a..3dc5640 100644
Binary files a/Chiota/Chiota.UWP/Assets/photothumb.db and b/Chiota/Chiota.UWP/Assets/photothumb.db differ
diff --git a/Chiota/Chiota.UWP/Chiota.UWP.csproj b/Chiota/Chiota.UWP/Chiota.UWP.csproj
index 4f194ef..fce6780 100644
--- a/Chiota/Chiota.UWP/Chiota.UWP.csproj
+++ b/Chiota/Chiota.UWP/Chiota.UWP.csproj
@@ -151,14 +151,21 @@
2.0.2
+
+ 3.0.0-beta14
+
- 2.5.0.280555
+ 2.5.1.444934
2.4.1
+
+ {a7fca39f-0fee-4213-b0d8-ea6b7b228e50}
+ UWPRuntimeComponent
+
{a569a7a8-467d-45bd-8848-00f6a0dc34bc}
Chiota
diff --git a/Chiota/Chiota.UWP/MainPage.xaml.cs b/Chiota/Chiota.UWP/MainPage.xaml.cs
index 76efad0..f50d6ec 100644
--- a/Chiota/Chiota.UWP/MainPage.xaml.cs
+++ b/Chiota/Chiota.UWP/MainPage.xaml.cs
@@ -1,5 +1,17 @@
namespace Chiota.UWP
{
+ using System;
+ using System.Linq;
+ using System.Threading.Tasks;
+
+ using Chiota.Models;
+ using Chiota.Services;
+
+ using Plugin.LocalNotifications;
+
+ using Windows.ApplicationModel.Background;
+ using Windows.UI.Xaml;
+
///
/// An empty page that can be used on its own or navigated to within a Frame.
///
@@ -8,8 +20,94 @@ public sealed partial class MainPage
public MainPage()
{
this.InitializeComponent();
- LoadApplication(new Chiota.App());
+ this.LoadApplication(new Chiota.App());
+
ZXing.Net.Mobile.Forms.WindowsUniversal.ZXingScannerViewRenderer.Init();
+
+ if (this.IsRegistered())
+ {
+ this.Deregister();
+ }
+
+ this.Loaded += this.MainPageLoaded;
+ }
+
+ private async void MainPageLoaded(object sender, RoutedEventArgs e)
+ {
+ await this.BackgroundTask();
+ }
+
+ private void Deregister()
+ {
+ var taskName = "BackgroundTask";
+
+ foreach (var task in BackgroundTaskRegistration.AllTasks)
+ {
+ if (task.Value.Name == taskName)
+ {
+ task.Value.Unregister(true);
+ }
+ }
+ }
+
+ private bool IsRegistered()
+ {
+ var taskName = "BackgroundTask";
+
+ foreach (var task in BackgroundTaskRegistration.AllTasks)
+ {
+ if (task.Value.Name == taskName)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private async Task BackgroundTask()
+ {
+ BackgroundExecutionManager.RemoveAccess();
+
+ await BackgroundExecutionManager.RequestAccessAsync();
+
+ var builder = new BackgroundTaskBuilder
+ {
+ Name = "BackgroundTask",
+ TaskEntryPoint = "UWPRuntimeComponent.BackgroundTask"
+ };
+
+ builder.SetTrigger(new TimeTrigger(15, false));
+ var task = builder.Register();
+ task.Completed += this.TaskCompleted;
+ }
+
+ private async void TaskCompleted(BackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs args)
+ {
+ var settings = Windows.Storage.ApplicationData.Current.LocalSettings;
+ var key = "BackgroundTask";
+ var message = settings.Values[key].ToString();
+
+ // Run your background task code here
+ var secureStorage = new SecureStorage();
+ if (secureStorage.CheckUserStored())
+ {
+ var user = await secureStorage.GetUser();
+ if (user != null)
+ {
+ var contactApprovedList = await user.TangleMessenger.GetJsonMessageAsync>(user.ApprovedAddress);
+
+ // Todo also message for a new contact request
+ foreach (var contact in contactApprovedList.Where(c => !c.Data.Rejected))
+ {
+ var encryptedMessages = await user.TangleMessenger.GetMessagesAsync(contact.Data.ChatAdress);
+ foreach (var unused in encryptedMessages.Where(c => !c.Stored))
+ {
+ CrossLocalNotifications.Current.Show(contact.Data.Name, "New Message from " + contact.Data.Name);
+ }
+ }
+ }
+ }
}
}
}
diff --git a/Chiota/Chiota.UWP/Package.appxmanifest b/Chiota/Chiota.UWP/Package.appxmanifest
index 2710180..c9d0a1f 100644
--- a/Chiota/Chiota.UWP/Package.appxmanifest
+++ b/Chiota/Chiota.UWP/Package.appxmanifest
@@ -20,9 +20,17 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Chiota/Chiota.UWP/iota.png b/Chiota/Chiota.UWP/iota.png
index 7d03b99..4f76f10 100644
Binary files a/Chiota/Chiota.UWP/iota.png and b/Chiota/Chiota.UWP/iota.png differ
diff --git a/Chiota/Chiota/App.xaml.cs b/Chiota/Chiota/App.xaml.cs
index bb572e2..0c4ae10 100644
--- a/Chiota/Chiota/App.xaml.cs
+++ b/Chiota/Chiota/App.xaml.cs
@@ -4,13 +4,14 @@
namespace Chiota
{
- using Chiota.CustomCells;
+ using Chiota.Messages;
using Chiota.Services;
+ using Chiota.Views;
using Xamarin.Forms;
using ContactPage = Views.ContactPage;
- using LoginPage = Chiota.Views.LoginPage;
+ using LoginPage = Views.LoginPage;
///
/// The app.
@@ -20,19 +21,24 @@ public partial class App : Application
public App()
{
this.InitializeComponent();
- this.MainPage = new NavigationPage(new LoginPage());
+ this.MainPage = new GreyPage();
}
public static string AppName => "Chiota";
protected override async void OnStart()
{
- // Handle when your app starts
+ // starts listening for messages
+ var messagestart = new StartLongRunningTaskMessage();
+ MessagingCenter.Send(messagestart, "StartLongRunningTaskMessage");
+
var secureStorage = new SecureStorage();
if (secureStorage.CheckUserStored())
{
var user = await secureStorage.GetUser();
- this.MainPage = new NavigationPage(new ContactPage(user));
+
+ // user = null => setup probably interrupted
+ this.MainPage = user != null ? new NavigationPage(new ContactPage(user)) : new NavigationPage(new LoginPage());
}
else
{
diff --git a/Chiota/Chiota/Chiota.csproj b/Chiota/Chiota/Chiota.csproj
index a921da6..dad5bc9 100644
--- a/Chiota/Chiota/Chiota.csproj
+++ b/Chiota/Chiota/Chiota.csproj
@@ -26,12 +26,12 @@
-
+
-
+
@@ -52,6 +52,9 @@
ChatPage.xaml
+
+ CheckSeedStoredPage.xaml
+
SetupPage.xaml
@@ -67,6 +70,9 @@
MSBuild:UpdateDesignTimeXaml
+
+ MSBuild:UpdateDesignTimeXaml
+
MSBuild:UpdateDesignTimeXaml
@@ -76,6 +82,9 @@
MSBuild:UpdateDesignTimeXaml
+
+ MSBuild:UpdateDesignTimeXaml
+
MSBuild:UpdateDesignTimeXaml
diff --git a/Chiota/Chiota/IOTAServices/IOTAHelper.cs b/Chiota/Chiota/IOTAServices/IOTAHelper.cs
index e8cec65..97d6a31 100644
--- a/Chiota/Chiota/IOTAServices/IOTAHelper.cs
+++ b/Chiota/Chiota/IOTAServices/IOTAHelper.cs
@@ -7,11 +7,9 @@
using Chiota.Models;
using Chiota.Services;
-
- using Newtonsoft.Json;
+ using Chiota.ViewModels;
using Tangle.Net.Entity;
- using Tangle.Net.Mam.Services;
using VTDev.Libraries.CEXEngine.Crypto.Cipher.Asymmetric.Encrypt.NTRU;
using VTDev.Libraries.CEXEngine.Crypto.Cipher.Asymmetric.Interfaces;
@@ -28,58 +26,24 @@ public static bool CorrectSeedAdressChecker(string seed)
return seed != string.Empty && seed.All(c => "ABCDEFGHIJKLMNOPQRSTUVWXYZ9".Contains(c));
}
- public static Contact FilterRequestInfos(IEnumerable trytes)
- {
- var contact = new Contact();
- var oneKeyAlreadyFound = false;
- foreach (var tryte in trytes)
- {
- var trytesString = tryte.ToString();
- if (!trytesString.Contains("9CHIOTAYOURIOTACHATAPP9"))
- {
- continue;
- }
-
- if (oneKeyAlreadyFound)
- {
- return null;
- }
-
- var index = trytesString.IndexOf("9CHIOTAYOURIOTACHATAPP9", StringComparison.Ordinal);
- var publicKeyString = trytesString.Substring(0, index);
- var bytesKey = new TryteString(publicKeyString).ToBytes();
-
- contact.PublicNtruKey = new NTRUPublicKey(bytesKey);
-
- contact.ContactAdress = trytesString.Substring(index + 23, 81);
- oneKeyAlreadyFound = true;
- }
-
- return contact;
- }
-
- public static List FilterChatMessages(IEnumerable trytes, NtruKex ntruKex, IAsymmetricKeyPair keyPair, DateTime lastPostDate)
+ public static List FilterChatMessages(IEnumerable trytes, IAsymmetricKeyPair keyPair)
{
var chatMessages = new List();
foreach (var tryte in trytes)
{
try
{
- var trytesString = tryte.ToString();
- var firstBreak = trytesString.IndexOf("9CHIOTAYOUR9", StringComparison.Ordinal);
- var secondBreak = trytesString.IndexOf("9IOTACHATAPP9", StringComparison.Ordinal);
- var dateTrytes = new TryteString(trytesString.Substring(secondBreak + 13, trytesString.Length - secondBreak - 13));
+ var trytesString = tryte.Message.ToString();
+ var firstBreak = trytesString.IndexOf(ChiotaIdentifier.FirstBreak, StringComparison.Ordinal);
+ var secondBreak = trytesString.IndexOf(ChiotaIdentifier.SecondBreak, StringComparison.Ordinal);
+ var dateTrytes = new TryteString(trytesString.Substring(secondBreak + ChiotaIdentifier.SecondBreak.Length, trytesString.Length - secondBreak - ChiotaIdentifier.SecondBreak.Length));
var date = DateTime.Parse(dateTrytes.ToUtf8String());
- // decrypt only if this is a new message
- if (date > lastPostDate)
- {
- var signature = trytesString.Substring(firstBreak + 12, 30);
- var messageTrytes = new TryteString(trytesString.Substring(0, firstBreak));
- var decryptedMessage = ntruKex.Decrypt(keyPair, messageTrytes.ToBytes());
- var chatMessage = new ChatMessage { Message = decryptedMessage, Date = date, Signature = signature };
- chatMessages.Add(chatMessage);
- }
+ var signature = trytesString.Substring(firstBreak + ChiotaIdentifier.FirstBreak.Length, 30);
+ var messageTrytes = new TryteString(trytesString.Substring(0, firstBreak));
+ var decryptedMessage = new NtruKex().Decrypt(keyPair, messageTrytes.ToBytes());
+ var chatMessage = new ChatMessage { Message = decryptedMessage, Date = date, Signature = signature };
+ chatMessages.Add(chatMessage);
}
catch
{
@@ -90,18 +54,27 @@ public static List FilterChatMessages(IEnumerable tryt
return chatMessages;
}
- public static async Task UpdateUserWithTangleInfos(User user, List ownDataWrappers)
+ public static async Task> GetNewMessages(IAsymmetricKeyPair keyPair, Contact contact, TangleMessenger tangle)
{
- var trytes = await user.TangleMessenger.GetMessagesAsync(user.PublicKeyAddress, 3);
- var contact = FilterRequestInfos(trytes);
- var decrypted = new CurlMask().Unmask(ownDataWrappers[0], user.Seed);
- var decryptedString = decrypted.ToUtf8String();
- var decryptedUser = JsonConvert.DeserializeObject(decryptedString);
- user.Name = decryptedUser.Name;
- user.ImageUrl = decryptedUser.ImageUrl;
- IAsymmetricKey privateKey = new NTRUPrivateKey(new TryteString(decryptedUser.PrivateKey).ToBytes());
- user.NtruKeyPair = new NTRUKeyPair(contact.PublicNtruKey, privateKey);
- return user;
+ var messages = new List();
+ var encryptedMessages = await tangle.GetMessagesAsync(contact.ChatAdress);
+ var messageList = FilterChatMessages(encryptedMessages, keyPair);
+ if (messageList != null)
+ {
+ var sortedMessageList = messageList.OrderBy(o => o.Date).ToList();
+ foreach (var message in sortedMessageList)
+ {
+ messages.Add(new MessageViewModel
+ {
+ Text = message.Message,
+ IsIncoming = message.Signature == contact.PublicKeyAdress.Substring(0, 30),
+ MessagDateTime = message.Date,
+ ProfileImage = contact.ImageUrl
+ });
+ }
+ }
+
+ return messages;
}
public static List GetNewHashes(Tangle.Net.Repository.DataTransfer.TransactionHashList transactions, List storedHashes)
@@ -127,5 +100,42 @@ public static List GetNewHashes(Tangle.Net.Repository.DataTransfer.Transac
return newHashes;
}
+
+ ///
+ /// Filters Transactions for public key and contact address
+ ///
+ /// Transactions in List form
+ /// null if more than one key
+ public static List GetPublicKeysAndContactAddresses(IEnumerable trytes)
+ {
+ var contacts = new List();
+ foreach (var tryte in trytes)
+ {
+ var trytesString = tryte.Message.ToString();
+ if (!trytesString.Contains(ChiotaIdentifier.LineBreak))
+ {
+ continue;
+ }
+
+ try
+ {
+ var index = trytesString.IndexOf(ChiotaIdentifier.LineBreak, StringComparison.Ordinal);
+ var publicKeyString = trytesString.Substring(0, index);
+ var bytesKey = new TryteString(publicKeyString).ToBytes();
+ var contact = new Contact
+ {
+ PublicNtruKey = new NTRUPublicKey(bytesKey),
+ ContactAdress = trytesString.Substring(index + ChiotaIdentifier.LineBreak.Length, 81)
+ };
+ contacts.Add(contact);
+ }
+ catch
+ {
+ // ignored
+ }
+ }
+
+ return contacts;
+ }
}
}
diff --git a/Chiota/Chiota/IOTAServices/TangleMessenger.cs b/Chiota/Chiota/IOTAServices/TangleMessenger.cs
index 17f8b64..adb9cb8 100644
--- a/Chiota/Chiota/IOTAServices/TangleMessenger.cs
+++ b/Chiota/Chiota/IOTAServices/TangleMessenger.cs
@@ -47,10 +47,10 @@ public async Task SendJsonMessageAsync(SentDataWrapper data, string addres
await Task.Factory.StartNew(() => this.repository.SendTransfer(this.seed, bundle, SecurityLevel.Medium, 27, 14));
}
- public async Task> GetMessagesAsync(string adresse, int retryNumber = 1)
+ public async Task> GetMessagesAsync(string adresse, int retryNumber = 1)
{
var roundNumber = 0;
- var messagesList = new List();
+ var messagesList = new List();
while (roundNumber < retryNumber && messagesList.Count == 0)
{
// try to update the repository
@@ -127,21 +127,25 @@ public async Task> GetJsonMessageAsync(string adresse)
return messagesList;
}
- private async Task MessageFromBundleOrStorage(Hash transactionsHash)
+ private async Task MessageFromBundleOrStorage(Hash transactionsHash)
{
// todo upload them again after snapshot
- TryteString message;
+ TryteStringMessage message = new TryteStringMessage();
var hashString = transactionsHash.ToString();
if (Application.Current.Properties.ContainsKey(hashString))
{
+ // old messages
var messageString = Application.Current.Properties[hashString] as string;
- message = new TryteString(messageString);
+ message.Message = new TryteString(messageString);
+ message.Stored = true;
}
else
{
+ // new messages
var bundle = await this.repository.GetBundleAsync(transactionsHash);
- message = this.GetMessages(bundle);
- Application.Current.Properties[hashString] = message.ToString();
+ message.Message = this.GetMessages(bundle);
+ message.Stored = false;
+ Application.Current.Properties[hashString] = message.Message.ToString();
await Application.Current.SavePropertiesAsync();
}
diff --git a/Chiota/Chiota/IOTAServices/UserDataOnTangle.cs b/Chiota/Chiota/IOTAServices/UserDataOnTangle.cs
new file mode 100644
index 0000000..e3e2f8b
--- /dev/null
+++ b/Chiota/Chiota/IOTAServices/UserDataOnTangle.cs
@@ -0,0 +1,103 @@
+namespace Chiota.IOTAServices
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Threading.Tasks;
+
+ using Chiota.Models;
+ using Chiota.Services;
+
+ using Newtonsoft.Json;
+
+ using Tangle.Net.Cryptography;
+ using Tangle.Net.Entity;
+ using Tangle.Net.Mam.Services;
+
+ using VTDev.Libraries.CEXEngine.Crypto.Cipher.Asymmetric.Encrypt.NTRU;
+ using VTDev.Libraries.CEXEngine.Crypto.Cipher.Asymmetric.Interfaces;
+
+ public class UserDataOnTangle
+ {
+ private readonly NtruKex ntru;
+
+ private readonly User user;
+
+ private IAsymmetricKey privateKey;
+
+ public UserDataOnTangle(User user)
+ {
+ this.ntru = new NtruKex();
+ this.user = user;
+ }
+
+ public async Task UpdateUserWithOwnDataAddress()
+ {
+ var ownDataWrappers = await this.user.TangleMessenger.GetMessagesAsync(this.user.OwnDataAdress, 3);
+ if (ownDataWrappers != null && ownDataWrappers.Count > 0)
+ {
+ var decryptedString = new CurlMask().Unmask(ownDataWrappers[0].Message, this.user.Seed).ToUtf8String();
+ var decryptedUser = JsonConvert.DeserializeObject(decryptedString);
+ this.privateKey = new NTRUPrivateKey(new TryteString(decryptedUser.PrivateKey).ToBytes());
+ this.user.Name = decryptedUser.Name;
+ this.user.ImageUrl = decryptedUser.ImageUrl;
+ }
+
+ return this.user;
+ }
+
+ public async Task UpdateUserWithPublicKeyAddress()
+ {
+ var trytes = await this.user.TangleMessenger.GetMessagesAsync(this.user.PublicKeyAddress, 3);
+ var contacts = IotaHelper.GetPublicKeysAndContactAddresses(trytes);
+
+ // more than one key at this address
+ if (contacts.Count > 1)
+ {
+ contacts = this.FindCorrectPublicKey(contacts);
+
+ // generate a new public key address based on changed seed until you find a unused address
+ // this way the attacker doesn't know the next public key address
+ List newContacts;
+ var addresses = new List { new Address(contacts[0].ContactAdress) };
+ do
+ {
+ var newSeed = this.user.Seed.ToString().Substring(0, 75) + addresses[0].ToString().Substring(0, 6);
+ addresses = await Task.Factory.StartNew(() => new AddressGenerator(new Seed(newSeed), SecurityLevel.Low).GetAddresses(0, 1));
+ var testtrytes = await this.user.TangleMessenger.GetMessagesAsync(addresses[0].ToString(), 3);
+ newContacts = IotaHelper.GetPublicKeysAndContactAddresses(testtrytes);
+
+ if (newContacts == null)
+ {
+ var requestAdressTrytes = new TryteString(contacts[0].PublicNtruKey + ChiotaIdentifier.LineBreak + this.user.RequestAddress + ChiotaIdentifier.End);
+ await this.user.TangleMessenger.SendMessageAsync(requestAdressTrytes, addresses[0].ToString());
+ }
+
+ this.user.PublicKeyAddress = addresses[0].ToString();
+ }
+ while (newContacts?.Count > 1);
+ }
+
+ this.user.NtruKeyPair = new NTRUKeyPair(contacts[0].PublicNtruKey, this.privateKey);
+ return this.user;
+ }
+
+ private List FindCorrectPublicKey(List contacts)
+ {
+ const string TestString = "Hello World";
+ foreach (var contact in contacts)
+ {
+ var keypair = new NTRUKeyPair(contact.PublicNtruKey, this.privateKey);
+ var encrypt = this.ntru.Encrypt(contact.PublicNtruKey, TestString);
+ if (TestString == this.ntru.Decrypt(keypair, encrypt))
+ {
+ // Removes all infos except the correct version
+ contacts.Clear();
+ contacts.Add(contact);
+ break;
+ }
+ }
+
+ return contacts;
+ }
+ }
+}
diff --git a/Chiota/Chiota/Messages/CancelledMessage.cs b/Chiota/Chiota/Messages/CancelledMessage.cs
new file mode 100644
index 0000000..28f19b3
--- /dev/null
+++ b/Chiota/Chiota/Messages/CancelledMessage.cs
@@ -0,0 +1,6 @@
+namespace Chiota.Messages
+{
+ public class CancelledMessage
+ {
+ }
+}
diff --git a/Chiota/Chiota/Messages/StartLongRunningTaskMessage.cs b/Chiota/Chiota/Messages/StartLongRunningTaskMessage.cs
new file mode 100644
index 0000000..51b388b
--- /dev/null
+++ b/Chiota/Chiota/Messages/StartLongRunningTaskMessage.cs
@@ -0,0 +1,6 @@
+namespace Chiota.Messages
+{
+ public class StartLongRunningTaskMessage
+ {
+ }
+}
diff --git a/Chiota/Chiota/Messages/StopLongRunningTaskMessage.cs b/Chiota/Chiota/Messages/StopLongRunningTaskMessage.cs
new file mode 100644
index 0000000..c308829
--- /dev/null
+++ b/Chiota/Chiota/Messages/StopLongRunningTaskMessage.cs
@@ -0,0 +1,6 @@
+namespace Chiota.Messages
+{
+ public class StopLongRunningTaskMessage
+ {
+ }
+}
diff --git a/Chiota/Chiota/Models/ChiotaIdentifier.cs b/Chiota/Chiota/Models/ChiotaIdentifier.cs
new file mode 100644
index 0000000..4d3e111
--- /dev/null
+++ b/Chiota/Chiota/Models/ChiotaIdentifier.cs
@@ -0,0 +1,13 @@
+namespace Chiota.Models
+{
+ public class ChiotaIdentifier
+ {
+ public static string LineBreak => "9CHIOTAYOURIOTACHATAPP9";
+
+ public static string End => "9ENDEGUTALLESGUT9";
+
+ public static string FirstBreak => "9CHIOTAYOUR9";
+
+ public static string SecondBreak => "9IOTACHATAPP9";
+ }
+}
diff --git a/Chiota/Chiota/Models/DiffieHellmanObject.cs b/Chiota/Chiota/Models/DiffieHellmanObject.cs
deleted file mode 100644
index b75023f..0000000
--- a/Chiota/Chiota/Models/DiffieHellmanObject.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-namespace Chiota.Models
-{
- using Org.BouncyCastle.Crypto;
- using Org.BouncyCastle.Math;
-
- public class DiffieHellmanObject
- {
- // To be shared
- public AsymmetricKeyParameter PublicKey { get; set; }
-
- public BigInteger PrimInteger { get; set; }
-
- public BigInteger NaturalInteger { get; set; }
-
- // To be stored
- public AsymmetricKeyParameter PrivateKey { get; set; }
- }
-}
diff --git a/Chiota/Chiota/Models/TryteStringMessage.cs b/Chiota/Chiota/Models/TryteStringMessage.cs
new file mode 100644
index 0000000..6161351
--- /dev/null
+++ b/Chiota/Chiota/Models/TryteStringMessage.cs
@@ -0,0 +1,11 @@
+namespace Chiota.Models
+{
+ using Tangle.Net.Entity;
+
+ public class TryteStringMessage
+ {
+ public TryteString Message { get; set; }
+
+ public bool Stored { get; set; }
+ }
+}
diff --git a/Chiota/Chiota/Models/UserFactory.cs b/Chiota/Chiota/Models/UserFactory.cs
index 62fcdd5..b45800a 100644
--- a/Chiota/Chiota/Models/UserFactory.cs
+++ b/Chiota/Chiota/Models/UserFactory.cs
@@ -8,13 +8,13 @@
public class UserFactory
{
- public User Create(Seed storeSeed, List addresses, string username = null, string imageUrl = null)
+ public User Create(Seed storeSeed, List addresses)
{
return new User()
{
- Name = username,
+ Name = null,
Seed = storeSeed,
- ImageUrl = imageUrl,
+ ImageUrl = null,
OwnDataAdress = addresses[0].Value,
PublicKeyAddress = addresses[1].Value,
RequestAddress = addresses[2].Value,
diff --git a/Chiota/Chiota/Services/DiffieHellman.cs b/Chiota/Chiota/Services/DiffieHellman.cs
deleted file mode 100644
index 494d948..0000000
--- a/Chiota/Chiota/Services/DiffieHellman.cs
+++ /dev/null
@@ -1,223 +0,0 @@
-namespace Chiota.Services
-{
- using System;
- using System.Diagnostics;
- using System.IO;
-
- using Chiota.Models;
-
- using Org.BouncyCastle.Crypto;
- using Org.BouncyCastle.Crypto.Engines;
- using Org.BouncyCastle.Crypto.Generators;
- using Org.BouncyCastle.Crypto.Modes;
- using Org.BouncyCastle.Crypto.Parameters;
- using Org.BouncyCastle.Math;
- using Org.BouncyCastle.Security;
-
- // https://stackoverflow.com/questions/33813108/bouncycastle-diffie-hellman
- // To be replaced by https://en.wikipedia.org/wiki/Supersingular_isogeny_key_exchange
- // https://github.com/Microsoft/PQCrypto-SIDH
-
- public class DiffieHellman
- {
- private const string Algorithm = "ECDH";
-
- private const int KeyBitSize = 256;
-
- private const int NonceBitSize = 128;
-
- private const int MacBitSize = 128;
-
- private const int DefaultPrimeProbability = 30;
-
- public DiffieHellmanObject CreateAlice()
- {
- var aliceKeyGen = GeneratorUtilities.GetKeyPairGenerator(Algorithm);
- var aliceGenerator = new DHParametersGenerator();
- aliceGenerator.Init(KeyBitSize, DefaultPrimeProbability, new SecureRandom());
- var aliceParameters = aliceGenerator.GenerateParameters();
-
- aliceKeyGen.Init(new DHKeyGenerationParameters(new SecureRandom(), aliceParameters));
-
- var aliceKeyPair = aliceKeyGen.GenerateKeyPair();
-
- return new DiffieHellmanObject
- {
- PublicKey = aliceKeyPair.Public,
- PrimInteger = aliceParameters.P,
- NaturalInteger = aliceParameters.G,
- PrivateKey = aliceKeyPair.Private
- };
- }
-
- public DiffieHellmanObject CreateBob(DiffieHellmanObject alice)
- {
- var bobKeyGen = GeneratorUtilities.GetKeyPairGenerator(Algorithm);
- var bobParameters = new DHParameters(alice.PrimInteger, alice.NaturalInteger);
-
- bobKeyGen.Init(new DHKeyGenerationParameters(new SecureRandom(), bobParameters));
-
- var bobKeyPair = bobKeyGen.GenerateKeyPair();
- return new DiffieHellmanObject
- {
- PublicKey = bobKeyPair.Public,
- PrimInteger = bobParameters.P,
- NaturalInteger = bobParameters.G,
- PrivateKey = bobKeyPair.Private
- };
- }
-
-
- public static void TestMethod()
- {
- //BEGIN SETUP ALICE
- var aliceKeyGen = GeneratorUtilities.GetKeyPairGenerator(Algorithm);
- var aliceGenerator = new DHParametersGenerator();
- aliceGenerator.Init(KeyBitSize, DefaultPrimeProbability, new SecureRandom());
- DHParameters aliceParameters = aliceGenerator.GenerateParameters();
-
- var aliceKGP = new DHKeyGenerationParameters(new SecureRandom(), aliceParameters);
- aliceKeyGen.Init(aliceKGP);
-
- AsymmetricCipherKeyPair aliceKeyPair = aliceKeyGen.GenerateKeyPair();
- var aliceKeyAgree = AgreementUtilities.GetBasicAgreement(Algorithm);
- aliceKeyAgree.Init(aliceKeyPair.Private);
- //END SETUP ALICE
-
- /////AT THIS POINT, Alice's Public Key, Alice's Parameter P and Alice's Parameter G are sent unsecure to BOB
-
- //BEGIN SETUP BOB
- var bobKeyGen = GeneratorUtilities.GetKeyPairGenerator(Algorithm);
- DHParameters bobParameters = new DHParameters(aliceParameters.P, aliceParameters.G);
-
- KeyGenerationParameters bobKGP = new DHKeyGenerationParameters(new SecureRandom(), bobParameters);
- bobKeyGen.Init(bobKGP);
-
- AsymmetricCipherKeyPair bobKeyPair = bobKeyGen.GenerateKeyPair();
- IBasicAgreement bobKeyAgree = AgreementUtilities.GetBasicAgreement(Algorithm);
- bobKeyAgree.Init(bobKeyPair.Private);
- //END SETUP BOB
-
- BigInteger aliceAgree = aliceKeyAgree.CalculateAgreement(bobKeyPair.Public);
- BigInteger bobAgree = bobKeyAgree.CalculateAgreement(aliceKeyPair.Public);
-
- if (!aliceAgree.Equals(bobAgree))
- {
- throw new Exception("Keys do not match.");
- }
-
- byte[] nonSecretMessage = GetBytes("HeaderMessageForASDF");
- byte[] secretMessage = GetBytes("Secret message contents");
- byte[] decNonSecretBytes;
-
- KeyParameter sharedKey = new KeyParameter(aliceAgree.ToByteArrayUnsigned());
-
- var encMessage = EncryptMessage(sharedKey, nonSecretMessage, secretMessage);
- var decMessage = DecryptMessage(sharedKey, encMessage, out decNonSecretBytes);
-
- var decNonSecretMessage = GetString(decNonSecretBytes);
- var decSecretMessage = GetString(decMessage);
-
- Debug.WriteLine(decNonSecretMessage + " - " + decSecretMessage);
-
- return;
- }
-
- public static byte[] EncryptMessage(string sharedKey, string nonSecretMessage, string secretMessage)
- {
- return EncryptMessage(new KeyParameter(Convert.FromBase64String(sharedKey)), GetBytes(nonSecretMessage), GetBytes(secretMessage));
- }
-
- public static byte[] EncryptMessage(KeyParameter sharedKey, byte[] nonSecretMessage, byte[] secretMessage)
- {
- if (nonSecretMessage != null && nonSecretMessage.Length > 255) throw new Exception("Non Secret Message Too Long!");
- byte nonSecretLength = nonSecretMessage == null ? (byte)0 : (byte)nonSecretMessage.Length;
-
- var nonce = new byte[NonceBitSize / 8];
- var rand = new SecureRandom();
- rand.NextBytes(nonce, 0, nonce.Length);
-
- var cipher = new GcmBlockCipher(new AesFastEngine());
- var aeadParameters = new AeadParameters(sharedKey, MacBitSize, nonce, nonSecretMessage);
- cipher.Init(true, aeadParameters);
-
- //Generate Cipher Text With Auth Tag
- var cipherText = new byte[cipher.GetOutputSize(secretMessage.Length)];
- var len = cipher.ProcessBytes(secretMessage, 0, secretMessage.Length, cipherText, 0);
- cipher.DoFinal(cipherText, len);
-
- using (var combinedStream = new MemoryStream())
- {
- using (var binaryWriter = new BinaryWriter(combinedStream))
- {
- //Prepend Authenticated Payload
- binaryWriter.Write(nonSecretLength);
- binaryWriter.Write(nonSecretMessage);
-
- //Prepend Nonce
- binaryWriter.Write(nonce);
- //Write Cipher Text
- binaryWriter.Write(cipherText);
- }
- return combinedStream.ToArray();
- }
- }
-
- public static string DecryptMessage(string sharedKey, byte[] encryptedMessage, out string nonSecretPayload)
- {
- byte[] nonSecretPayloadBytes;
- byte[] payload = DecryptMessage(new KeyParameter(Convert.FromBase64String(sharedKey)), encryptedMessage, out nonSecretPayloadBytes);
-
- nonSecretPayload = GetString(nonSecretPayloadBytes);
- return GetString(payload);
- }
-
- public static byte[] DecryptMessage(KeyParameter sharedKey, byte[] encryptedMessage, out byte[] nonSecretPayloadBytes)
- {
- using (var cipherStream = new MemoryStream(encryptedMessage))
- using (var cipherReader = new BinaryReader(cipherStream))
- {
- //Grab Payload
- int nonSecretLength = (int)cipherReader.ReadByte();
- nonSecretPayloadBytes = cipherReader.ReadBytes(nonSecretLength);
-
- //Grab Nonce
- var nonce = cipherReader.ReadBytes(NonceBitSize / 8);
-
- var cipher = new GcmBlockCipher(new AesFastEngine());
- var parameters = new AeadParameters(sharedKey, MacBitSize, nonce, nonSecretPayloadBytes);
- cipher.Init(false, parameters);
-
- //Decrypt Cipher Text
- var cipherText = cipherReader.ReadBytes(encryptedMessage.Length - nonSecretLength - nonce.Length);
- var plainText = new byte[cipher.GetOutputSize(cipherText.Length)];
-
- try
- {
- var len = cipher.ProcessBytes(cipherText, 0, cipherText.Length, plainText, 0);
- cipher.DoFinal(plainText, len);
- }
- catch (InvalidCipherTextException)
- {
- //Return null if it doesn't authenticate
- return null;
- }
-
- return plainText;
- }
- }
-
- static byte[] GetBytes(string str)
- {
- if (str == null) return null;
- return System.Text.Encoding.Unicode.GetBytes(str);
- }
-
- static string GetString(byte[] bytes)
- {
- if (bytes == null) return null;
- return System.Text.Encoding.Unicode.GetString(bytes, 0, bytes.Length);
- }
- }
-
-}
diff --git a/Chiota/Chiota/Services/NTRUKex.cs b/Chiota/Chiota/Services/NTRUKex.cs
index 041fe30..be81772 100644
--- a/Chiota/Chiota/Services/NTRUKex.cs
+++ b/Chiota/Chiota/Services/NTRUKex.cs
@@ -4,6 +4,8 @@
using System.Linq;
using System.Text;
+ using Tangle.Net.Utils;
+
using VTDev.Libraries.CEXEngine.Crypto.Cipher.Asymmetric.Encrypt.NTRU;
using VTDev.Libraries.CEXEngine.Crypto.Cipher.Asymmetric.Interfaces;
@@ -18,7 +20,15 @@ public class NtruKex
public IAsymmetricKeyPair CreateAsymmetricKeyPair()
{
var keyGen = new NTRUKeyGenerator(this.encParams);
- return keyGen.GenerateKeyPair();
+ var keyPair = keyGen.GenerateKeyPair();
+
+ // publicKey sometimes has only 1025 bytes instead of 1026 after conversation?!
+ while (keyPair.PublicKey.ToBytes().ToTrytes().ToBytes().Length != 1026)
+ {
+ keyPair = keyGen.GenerateKeyPair();
+ }
+
+ return keyPair;
}
///
diff --git a/Chiota/Chiota/Services/SecureStorage.cs b/Chiota/Chiota/Services/SecureStorage.cs
index 9c1ee53..8c6a11b 100644
--- a/Chiota/Chiota/Services/SecureStorage.cs
+++ b/Chiota/Chiota/Services/SecureStorage.cs
@@ -43,9 +43,18 @@ public async Task GetUser()
TangleMessenger = new TangleMessenger(storedSeed)
};
- var ownDataWrappers = await user.TangleMessenger.GetMessagesAsync(user.OwnDataAdress, 3);
- user = await IotaHelper.UpdateUserWithTangleInfos(user, ownDataWrappers);
- return user;
+ try
+ {
+ var tangleData = new UserDataOnTangle(user);
+ await tangleData.UpdateUserWithOwnDataAddress();
+ user = await tangleData.UpdateUserWithPublicKeyAddress();
+ return user;
+ }
+ catch
+ {
+ // incomplete => setup interrupted or not yet finished
+ return null;
+ }
}
public bool StoreUser(User user)
diff --git a/Chiota/Chiota/ViewModels/AddContactViewModel.cs b/Chiota/Chiota/ViewModels/AddContactViewModel.cs
index 2bfdfda..0fb6025 100644
--- a/Chiota/Chiota/ViewModels/AddContactViewModel.cs
+++ b/Chiota/Chiota/ViewModels/AddContactViewModel.cs
@@ -93,36 +93,34 @@ private async Task AddContact()
{
this.IsBusy = true;
this.AlreadyClicke = true;
- try
- {
- // get information from receiver adress
- var trytes = await this.user.TangleMessenger.GetMessagesAsync(this.ReceiverAdress, 3);
- var contact = IotaHelper.FilterRequestInfos(trytes);
- if (contact?.PublicNtruKey != null && contact.ContactAdress != null)
- {
- // faster than generating adresses
- var requestContact = new Contact()
- {
- ChatAdress = Seed.Random().ToString(),
- Name = this.user.Name,
- ImageUrl = this.user.ImageUrl,
- ContactAdress = this.user.ApprovedAddress,
- Request = true,
- Rejected = false,
- PublicNtruKey = null,
- PublicKeyAdress = this.user.PublicKeyAddress
- };
-
- // encrypt contact request? too much infos needed here for one message needs to get request adress plus chatadress
- await this.user.TangleMessenger.SendJsonMessageAsync(new SentDataWrapper { Data = requestContact, Sender = this.user.Name }, contact.ContactAdress);
- this.SuccessfulRequestPrompt();
- }
- }
- catch
+ // get information from receiver adress
+ var trytes = await this.user.TangleMessenger.GetMessagesAsync(this.ReceiverAdress, 3);
+ var contacts = IotaHelper.GetPublicKeysAndContactAddresses(trytes);
+
+ if (contacts == null || contacts.Count > 1)
{
this.DisplayInvalidAdressPrompt();
}
+ else if (contacts[0]?.PublicNtruKey != null && contacts[0].ContactAdress != null)
+ {
+ // faster than generating adresses
+ var requestContact = new Contact()
+ {
+ ChatAdress = Seed.Random().ToString(),
+ Name = this.user.Name,
+ ImageUrl = this.user.ImageUrl,
+ ContactAdress = this.user.ApprovedAddress,
+ Request = true,
+ Rejected = false,
+ PublicNtruKey = null,
+ PublicKeyAdress = this.user.PublicKeyAddress
+ };
+
+ // encrypt contact request? too much infos needed here for one message needs to get request adress plus chatadress
+ await this.user.TangleMessenger.SendJsonMessageAsync(new SentDataWrapper { Data = requestContact, Sender = this.user.Name }, contacts[0].ContactAdress);
+ this.SuccessfulRequestPrompt();
+ }
}
else
{
diff --git a/Chiota/Chiota/ViewModels/ChatViewModel.cs b/Chiota/Chiota/ViewModels/ChatViewModel.cs
index a0ea9b3..0427727 100644
--- a/Chiota/Chiota/ViewModels/ChatViewModel.cs
+++ b/Chiota/Chiota/ViewModels/ChatViewModel.cs
@@ -9,6 +9,7 @@
using System.Windows.Input;
using Chiota.IOTAServices;
+ using Chiota.Messages;
using Chiota.Models;
using Chiota.Services;
@@ -23,7 +24,7 @@ public class ChatViewModel : BaseViewModel
{
public Action DisplayMessageTooLong;
- private readonly string profileImageUrl;
+ public Action DisplayInvalidPublicKeyPrompt;
private readonly User user;
@@ -33,8 +34,6 @@ public class ChatViewModel : BaseViewModel
private readonly ListView messagesListView;
- private DateTime lastPostDate;
-
private string outgoingText;
private ObservableCollection messagesList;
@@ -43,11 +42,10 @@ public ChatViewModel(ListView messagesListView, Contact contact, User user)
{
this.ntruKex = new NtruKex();
this.Messages = new ObservableCollection();
- this.profileImageUrl = contact.ImageUrl;
this.user = user;
this.contact = contact;
this.messagesListView = messagesListView;
- this.MessageLoop = true;
+ this.PageIsShown = true;
this.OutGoingText = null;
// reset hash short storage, because it's different for every chat
@@ -56,7 +54,7 @@ public ChatViewModel(ListView messagesListView, Contact contact, User user)
this.SendCommand = new Command(async () => { await this.SendMessage(); });
}
- public bool MessageLoop { get; set; }
+ public bool PageIsShown { get; set; }
public string OutGoingText
{
@@ -82,15 +80,39 @@ public ObservableCollection Messages
public async void OnAppearing()
{
+ // cancel if there is no interent
this.contact.PublicNtruKey = await this.GetContactPublicKey();
- this.GetMessagesAsync(this.Messages);
+ if (this.contact.PublicNtruKey == null)
+ {
+ // todo: delete contact
+ this.DisplayInvalidPublicKeyPrompt();
+ await this.Navigation.PopAsync();
+ }
+ else
+ {
+ this.GetMessagesAsync(this.Messages);
+ }
+
+ var messagestart = new StartLongRunningTaskMessage();
+ MessagingCenter.Send(messagestart, "StopLongRunningTaskMessage");
+ }
+
+ public void OnDisappearing()
+ {
+ var messagestart = new StartLongRunningTaskMessage();
+ MessagingCenter.Send(messagestart, "StartLongRunningTaskMessage");
}
private async Task GetContactPublicKey()
{
- var trytes = await this.user.TangleMessenger.GetMessagesAsync(this.contact.PublicKeyAdress);
- var contactInfos = IotaHelper.FilterRequestInfos(trytes);
- return contactInfos.PublicNtruKey;
+ var trytes = await this.user.TangleMessenger.GetMessagesAsync(this.contact.PublicKeyAdress, 3);
+ var contactInfos = IotaHelper.GetPublicKeysAndContactAddresses(trytes);
+ if (contactInfos == null || contactInfos.Count > 1)
+ {
+ return null;
+ }
+
+ return contactInfos[0].PublicNtruKey;
}
private async Task SendMessage()
@@ -111,11 +133,11 @@ private async Task SendMessage()
// encryption with public key of other user
var encryptedForContact = this.ntruKex.Encrypt(this.contact.PublicNtruKey, this.OutGoingText);
- var tryteContact = new TryteString(encryptedForContact.ToTrytes() + "9CHIOTAYOUR9" + signature + "9IOTACHATAPP9" + trytesDate + "9ENDEGUTALLESGUT9");
+ var tryteContact = new TryteString(encryptedForContact.ToTrytes() + ChiotaIdentifier.FirstBreak + signature + ChiotaIdentifier.SecondBreak + trytesDate + ChiotaIdentifier.End);
// encryption with public key of user
var encryptedForUser = this.ntruKex.Encrypt(this.user.NtruKeyPair.PublicKey, this.OutGoingText);
- var tryteUser = new TryteString(encryptedForUser.ToTrytes() + "9CHIOTAYOUR9" + signature + "9IOTACHATAPP9" + trytesDate + "9ENDEGUTALLESGUT9");
+ var tryteUser = new TryteString(encryptedForUser.ToTrytes() + ChiotaIdentifier.FirstBreak + signature + ChiotaIdentifier.SecondBreak + trytesDate + ChiotaIdentifier.End);
await this.SendParallelAsync(tryteContact, tryteUser);
}
@@ -134,7 +156,7 @@ private Task SendParallelAsync(TryteString tryteContact, TryteString tryteUser)
private async void GetMessagesAsync(ICollection messages)
{
- while (this.MessageLoop)
+ while (this.PageIsShown)
{
await this.AddNewMessagesAsync(messages);
await Task.Delay(9000);
@@ -143,28 +165,15 @@ private async void GetMessagesAsync(ICollection messages)
private async Task AddNewMessagesAsync(ICollection messages)
{
- var encryptedMessages = await this.user.TangleMessenger.GetMessagesAsync(this.contact.ChatAdress);
- var messageList = IotaHelper.FilterChatMessages(encryptedMessages, this.ntruKex, this.user.NtruKeyPair, this.lastPostDate);
- if (messageList != null)
+ var newMessages = await IotaHelper.GetNewMessages(this.user.NtruKeyPair, this.contact, this.user.TangleMessenger);
+ if (newMessages.Count > 0)
{
- var sortedMessageList = messageList.OrderBy(o => o.Date).ToList();
- foreach (var message in sortedMessageList)
+ foreach (var m in newMessages)
{
- // might cause problem when two messages send at the exact same time
- if (message.Date > this.lastPostDate)
- {
- messages.Add(
- new MessageViewModel
- {
- Text = message.Message,
- IsIncoming = message.Signature == this.contact.PublicKeyAdress.Substring(0, 30),
- MessagDateTime = message.Date,
- ProfileImage = this.profileImageUrl
- });
- this.ScrollToNewMessage();
- this.lastPostDate = message.Date;
- }
+ messages.Add(m);
}
+
+ this.ScrollToNewMessage();
}
}
diff --git a/Chiota/Chiota/ViewModels/CheckSeedStoredViewModel.cs b/Chiota/Chiota/ViewModels/CheckSeedStoredViewModel.cs
new file mode 100644
index 0000000..4c0aa43
--- /dev/null
+++ b/Chiota/Chiota/ViewModels/CheckSeedStoredViewModel.cs
@@ -0,0 +1,66 @@
+namespace Chiota.ViewModels
+{
+ using System;
+ using System.Threading.Tasks;
+ using System.Windows.Input;
+
+ using Chiota.Models;
+ using Chiota.Views;
+
+ using Xamarin.Forms;
+
+ public class CheckSeedStoredViewModel : BaseViewModel
+ {
+ public Action DisplayInvalidSeedPrompt;
+
+ private readonly User user;
+
+ private string seedInput;
+
+ public CheckSeedStoredViewModel(User user)
+ {
+ this.user = user;
+ this.SubmitCommand = new Command(async () => { await this.SeedCheck(); });
+ this.BackCommand = new Command(async () => { await this.Back(); });
+ }
+
+ public ICommand SubmitCommand { get; protected set; }
+
+ public ICommand BackCommand { get; protected set; }
+
+ public string SeedInput
+ {
+ get => this.seedInput;
+ set
+ {
+ this.seedInput = value;
+ this.RaisePropertyChanged();
+ }
+ }
+
+ private async Task SeedCheck()
+ {
+ this.SeedInput = this.SeedInput?.Trim();
+ if (this.user.Seed.ToString() != this.SeedInput)
+ {
+ this.DisplayInvalidSeedPrompt();
+ }
+ else if (!this.AlreadyClicke)
+ {
+ this.AlreadyClicke = true;
+ await this.Navigation.PushModalAsync(new NavigationPage(new SetupPage(this.user)));
+ this.AlreadyClicke = false;
+ }
+ }
+
+ private async Task Back()
+ {
+ if (!this.AlreadyClicke)
+ {
+ this.AlreadyClicke = true;
+ await this.Navigation.PopModalAsync();
+ this.AlreadyClicke = false;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Chiota/Chiota/ViewModels/ContactViewModel.cs b/Chiota/Chiota/ViewModels/ContactViewModel.cs
index 4677014..e09d2bf 100644
--- a/Chiota/Chiota/ViewModels/ContactViewModel.cs
+++ b/Chiota/Chiota/ViewModels/ContactViewModel.cs
@@ -4,13 +4,10 @@
using System.Linq;
using System.Threading.Tasks;
- using Chiota.CustomCells;
using Chiota.Models;
using Chiota.Services;
- using Xamarin.Forms;
-
- using ChatPage = Chiota.Views.ChatPage;
+ using ChatPage = Views.ChatPage;
public class ContactViewModel : BaseViewModel
{
@@ -85,6 +82,7 @@ private async Task UpdateContacts()
}
}
+ // Todo store contacts on device
private async Task> GetConctacts(string searchText = null)
{
var contacts = new ObservableCollection();
diff --git a/Chiota/Chiota/ViewModels/LoginViewModel.cs b/Chiota/Chiota/ViewModels/LoginViewModel.cs
index 105f33d..55020d2 100644
--- a/Chiota/Chiota/ViewModels/LoginViewModel.cs
+++ b/Chiota/Chiota/ViewModels/LoginViewModel.cs
@@ -7,6 +7,7 @@
using Chiota.IOTAServices;
using Chiota.Models;
using Chiota.Services;
+ using Chiota.Views;
using Tangle.Net.Cryptography;
using Tangle.Net.Entity;
@@ -14,23 +15,25 @@
using Xamarin.Forms;
using ContactPage = Views.ContactPage;
- using SetupPage = Chiota.Views.SetupPage;
public class LoginViewModel : BaseViewModel
{
+ public Action DisplayInvalidLoginPrompt;
+
private string randomSeed = Seed.Random().Value;
private string username;
private bool storeSeed;
+ private UserDataOnTangle dataOnTangle;
+
public LoginViewModel()
{
+ this.StoreSeed = true;
this.SubmitCommand = new Command(async () => { await this.Login(); });
}
- public Action DisplayInvalidLoginPrompt;
-
public bool StoreSeed
{
get => this.storeSeed;
@@ -65,8 +68,8 @@ public string Username
private async Task Login()
{
- this.randomSeed = this.randomSeed?.Trim();
- if (!IotaHelper.CorrectSeedAdressChecker(this.randomSeed))
+ this.RandomSeed = this.RandomSeed?.Trim();
+ if (!IotaHelper.CorrectSeedAdressChecker(this.RandomSeed))
{
this.DisplayInvalidLoginPrompt();
}
@@ -74,7 +77,7 @@ private async Task Login()
{
this.IsBusy = true;
this.AlreadyClicke = true;
- var seed = new Seed(this.randomSeed);
+ var seed = new Seed(this.RandomSeed);
// 4 addresses needed:
// 0. own user data address (encrypted, MAM or private key)
@@ -89,17 +92,18 @@ private async Task Login()
new SecureStorage().StoreUser(user);
}
- var ownDataWrappers = await user.TangleMessenger.GetMessagesAsync(user.OwnDataAdress, 3);
+ this.dataOnTangle = new UserDataOnTangle(user);
+ user = await this.dataOnTangle.UpdateUserWithOwnDataAddress();
- if (ownDataWrappers == null || ownDataWrappers.Count == 0)
+ if (user.Name == null)
{
this.IsBusy = false;
this.AlreadyClicke = false;
- await this.Navigation.PushModalAsync(new NavigationPage(new SetupPage(user)));
+ await this.Navigation.PushModalAsync(new NavigationPage(new CheckSeedStoredPage(user)));
}
else
{
- user = await IotaHelper.UpdateUserWithTangleInfos(user, ownDataWrappers);
+ user = await this.dataOnTangle.UpdateUserWithPublicKeyAddress();
this.IsBusy = false;
if (user.NtruKeyPair != null)
{
diff --git a/Chiota/Chiota/ViewModels/SetupViewModel.cs b/Chiota/Chiota/ViewModels/SetupViewModel.cs
index fbee5a4..84f4ba3 100644
--- a/Chiota/Chiota/ViewModels/SetupViewModel.cs
+++ b/Chiota/Chiota/ViewModels/SetupViewModel.cs
@@ -108,14 +108,6 @@ private async Task StoreKeysAndRequestAdress(User user)
var publicKeyTrytes = user.NtruKeyPair.PublicKey.ToBytes().ToTrytes();
var privateKeyTrytes = user.NtruKeyPair.PrivateKey.ToBytes().ToTrytes();
- // publicKey sometimes has only 1025 bytes instead of 1026?!
- while (publicKeyTrytes.ToBytes().Length != 1026)
- {
- user.NtruKeyPair = new NtruKex().CreateAsymmetricKeyPair();
- publicKeyTrytes = user.NtruKeyPair.PublicKey.ToBytes().ToTrytes();
- privateKeyTrytes = user.NtruKeyPair.PrivateKey.ToBytes().ToTrytes();
- }
-
var userData = new UserFactory().CreateUploadUser(user, privateKeyTrytes.ToString());
var serializeObject = JsonConvert.SerializeObject(userData);
@@ -127,14 +119,10 @@ private async Task StoreKeysAndRequestAdress(User user)
private Task SendParallelAsync(User user, TryteString publicKeyTrytes, TryteString mamEncrypted)
{
- // not sure this is necessary
- const string LineBreak = "9CHIOTAYOURIOTACHATAPP9";
- const string End = "9ENDEGUTALLESGUT9";
-
- var firstTransaction = user.TangleMessenger.SendMessageAsync(new TryteString(mamEncrypted + End), user.OwnDataAdress);
+ var firstTransaction = user.TangleMessenger.SendMessageAsync(new TryteString(mamEncrypted + ChiotaIdentifier.End), user.OwnDataAdress);
// only way to store it with one transaction, json to big
- var requestAdressTrytes = new TryteString(publicKeyTrytes + LineBreak + user.RequestAddress + End);
+ var requestAdressTrytes = new TryteString(publicKeyTrytes + ChiotaIdentifier.LineBreak + user.RequestAddress + ChiotaIdentifier.End);
var secondTransaction = user.TangleMessenger.SendMessageAsync(requestAdressTrytes, user.PublicKeyAddress);
return Task.WhenAll(firstTransaction, secondTransaction);
diff --git a/Chiota/Chiota/Views/AddContact.xaml.cs b/Chiota/Chiota/Views/AddContact.xaml.cs
index 0a85a43..e4a8b1e 100644
--- a/Chiota/Chiota/Views/AddContact.xaml.cs
+++ b/Chiota/Chiota/Views/AddContact.xaml.cs
@@ -8,6 +8,9 @@
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
+ ///
+ /// The add contact.
+ ///
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AddContact : ContentPage
{
@@ -18,7 +21,7 @@ public AddContact(User user)
var vm = new AddContactViewModel(user) { Navigation = this.Navigation };
- vm.DisplayInvalidAdressPrompt += () => this.DisplayAlert("Error", "Invalid adress, try again", "OK");
+ vm.DisplayInvalidAdressPrompt += () => this.DisplayAlert("Error", "Invalid address, try again", "OK");
vm.SuccessfulRequestPrompt += () => this.DisplayAlert("Successful Request", "Your new contact needs to accept the request before you can chat with him!", "OK");
this.ReceiverAdress.Completed += (object sender, EventArgs e) =>
diff --git a/Chiota/Chiota/Views/ChatPage.xaml b/Chiota/Chiota/Views/ChatPage.xaml
index f8dc162..8dcd225 100644
--- a/Chiota/Chiota/Views/ChatPage.xaml
+++ b/Chiota/Chiota/Views/ChatPage.xaml
@@ -46,11 +46,12 @@
+ Command="{Binding SendCommand}">
+
diff --git a/Chiota/Chiota/Views/ChatPage.xaml.cs b/Chiota/Chiota/Views/ChatPage.xaml.cs
index 9a49cdd..b95a6ff 100644
--- a/Chiota/Chiota/Views/ChatPage.xaml.cs
+++ b/Chiota/Chiota/Views/ChatPage.xaml.cs
@@ -6,7 +6,12 @@
using Chiota.ViewModels;
using Xamarin.Forms;
+ using Xamarin.Forms.Xaml;
+ ///
+ /// The chat page.
+ ///
+ [XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ChatPage : ContentPage
{
private ChatViewModel vm;
@@ -20,8 +25,9 @@ public ChatPage(Contact contact, User user)
}
this.Title = contact.Name;
- this.vm = new ChatViewModel(MessagesListView, contact, user);
+ this.vm = new ChatViewModel(MessagesListView, contact, user) { Navigation = this.Navigation };
this.vm.DisplayMessageTooLong += () => this.DisplayAlert("Error", "Sorry, only 105 characters per message are allowed!", "OK");
+ this.vm.DisplayInvalidPublicKeyPrompt += () => this.DisplayAlert("Error", "Invalid public key! You contact needs to give you a new contact address.", "OK");
this.BindingContext = this.vm;
}
@@ -33,7 +39,8 @@ protected override void OnAppearing()
protected override void OnDisappearing()
{
- this.vm.MessageLoop = false;
+ this.vm.OnDisappearing();
+ this.vm.PageIsShown = false;
this.vm = null;
this.Navigation.PopAsync();
}
diff --git a/Chiota/Chiota/Views/CheckSeedStoredPage.xaml b/Chiota/Chiota/Views/CheckSeedStoredPage.xaml
new file mode 100644
index 0000000..50cd9fc
--- /dev/null
+++ b/Chiota/Chiota/Views/CheckSeedStoredPage.xaml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Chiota/Chiota/Views/CheckSeedStoredPage.xaml.cs b/Chiota/Chiota/Views/CheckSeedStoredPage.xaml.cs
new file mode 100644
index 0000000..e3200e2
--- /dev/null
+++ b/Chiota/Chiota/Views/CheckSeedStoredPage.xaml.cs
@@ -0,0 +1,32 @@
+namespace Chiota.Views
+{
+ using System;
+
+ using Chiota.Models;
+ using Chiota.ViewModels;
+
+ using Xamarin.Forms;
+ using Xamarin.Forms.Xaml;
+
+ ///
+ /// The check seed stored page.
+ ///
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ public partial class CheckSeedStoredPage : ContentPage
+ {
+ public CheckSeedStoredPage(User user)
+ {
+ this.InitializeComponent();
+ NavigationPage.SetHasNavigationBar(this, false);
+ var vm = new CheckSeedStoredViewModel(user) { Navigation = this.Navigation };
+
+ vm.DisplayInvalidSeedPrompt += () => this.DisplayAlert("Incorrect Seed", "The seed you entered is incorrect. Please try again.", "OK");
+
+ this.SeedInput.Completed += (object sender, EventArgs e) =>
+ {
+ vm.SubmitCommand.Execute(null);
+ };
+ this.BindingContext = vm;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Chiota/Chiota/Views/ContactPage.xaml.cs b/Chiota/Chiota/Views/ContactPage.xaml.cs
index 0770fb1..ae1f3a5 100644
--- a/Chiota/Chiota/Views/ContactPage.xaml.cs
+++ b/Chiota/Chiota/Views/ContactPage.xaml.cs
@@ -9,6 +9,9 @@
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
+ ///
+ /// The contact page.
+ ///
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ContactPage : ContentPage
{
diff --git a/Chiota/Chiota/Views/GreyPage.xaml b/Chiota/Chiota/Views/GreyPage.xaml
new file mode 100644
index 0000000..84a842a
--- /dev/null
+++ b/Chiota/Chiota/Views/GreyPage.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Chiota/Chiota/Views/GreyPage.xaml.cs b/Chiota/Chiota/Views/GreyPage.xaml.cs
new file mode 100644
index 0000000..7bf1639
--- /dev/null
+++ b/Chiota/Chiota/Views/GreyPage.xaml.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+
+namespace Chiota.Views
+{
+ [XamlCompilation(XamlCompilationOptions.Compile)]
+ public partial class GreyPage : ContentPage
+ {
+ public GreyPage ()
+ {
+ InitializeComponent ();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Chiota/Chiota/Views/LoginPage.xaml b/Chiota/Chiota/Views/LoginPage.xaml
index 9c1ace3..3b40788 100644
--- a/Chiota/Chiota/Views/LoginPage.xaml
+++ b/Chiota/Chiota/Views/LoginPage.xaml
@@ -2,7 +2,7 @@
-
+
diff --git a/Chiota/Chiota/Views/LoginPage.xaml.cs b/Chiota/Chiota/Views/LoginPage.xaml.cs
index b00848d..181bc8e 100644
--- a/Chiota/Chiota/Views/LoginPage.xaml.cs
+++ b/Chiota/Chiota/Views/LoginPage.xaml.cs
@@ -7,6 +7,9 @@
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
+ ///
+ /// The login page.
+ ///
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class LoginPage : ContentPage
{
diff --git a/Chiota/Chiota/Views/SetupPage.xaml.cs b/Chiota/Chiota/Views/SetupPage.xaml.cs
index f273bd6..c6e8e96 100644
--- a/Chiota/Chiota/Views/SetupPage.xaml.cs
+++ b/Chiota/Chiota/Views/SetupPage.xaml.cs
@@ -8,6 +8,9 @@
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
+ ///
+ /// The setup page.
+ ///
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SetupPage : ContentPage
{
diff --git a/README.md b/README.md
index 41ddb18..b41324b 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ The goal is to create a quantum secure chat app, in which you are the owner of y
Impressions of the current state:
-
+
# How Chiota works?
Currently, Chiota doesn’t use the MAM Layer for sending secure messages. Instead, it uses the NTRU Encryption.
@@ -34,17 +34,15 @@ Currently, there are the following points on my to-do list:
- [x] Store contacts/profile on the tangle
- [x] Qr codes for address sharing
- [x] Performance improvements
-- [ ] Check for unique Address public key combination
+- [x] Check for unique Address public key combination
+- [ ] Improve Notifications/Background Tasks (Android 8.0, Sound, Windows, etc.)
- [ ] Recovery after snapshot
- [ ] Mam Integration
- [ ] Improve/check NTRU solution or switch to SIDH (key only 564 bytes) for key exchange
- [ ] iOS App
-- [ ] improve Windows App
-- [ ] Notifications (https://github.com/edsnider/LocalNotificationsPlugin)
- [ ] Unit testing
- [ ] Code refactoring
-
# Donate
```
GUEOJUOWOWYEXYLZXNQUYMLMETF9OOGASSKUZZWUJNMSHLFLYIDIVKXKLTLZPMNNJCYVSRZABFKCAVVIW9IYHJNNRX
diff --git a/UWPRuntimeComponent/BackgroundTask.cs b/UWPRuntimeComponent/BackgroundTask.cs
new file mode 100644
index 0000000..f1b7d77
--- /dev/null
+++ b/UWPRuntimeComponent/BackgroundTask.cs
@@ -0,0 +1,28 @@
+namespace UWPRuntimeComponent
+{
+ using Windows.ApplicationModel.Background;
+
+ public sealed class BackgroundTask : IBackgroundTask
+ {
+ private BackgroundTaskDeferral deferral;
+
+ public void Run(IBackgroundTaskInstance taskInstance)
+ {
+ this.deferral = taskInstance.GetDeferral();
+
+ // Run your background task code here
+ try
+ {
+ var settings = Windows.Storage.ApplicationData.Current.LocalSettings;
+
+ settings.Values.Add("BackgroundTask", "Hello from UWP");
+ }
+ catch
+ {
+ // ignored
+ }
+
+ this.deferral.Complete();
+ }
+ }
+}
diff --git a/UWPRuntimeComponent/Properties/AssemblyInfo.cs b/UWPRuntimeComponent/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..2e07e71
--- /dev/null
+++ b/UWPRuntimeComponent/Properties/AssemblyInfo.cs
@@ -0,0 +1,29 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("UWPRuntimeComponent")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("UWPRuntimeComponent")]
+[assembly: AssemblyCopyright("Copyright © 2018")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: ComVisible(false)]
\ No newline at end of file
diff --git a/UWPRuntimeComponent/UWPRuntimeComponent.csproj b/UWPRuntimeComponent/UWPRuntimeComponent.csproj
new file mode 100644
index 0000000..e34051e
--- /dev/null
+++ b/UWPRuntimeComponent/UWPRuntimeComponent.csproj
@@ -0,0 +1,129 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {A7FCA39F-0FEE-4213-B0D8-EA6B7B228E50}
+ winmdobj
+ Properties
+ UWPRuntimeComponent
+ UWPRuntimeComponent
+ en-US
+ UAP
+ 10.0.16299.0
+ 10.0.10586.0
+ 14
+ 512
+ {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ false
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ prompt
+ 4
+
+
+ x86
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ x86
+ false
+ prompt
+
+
+ x86
+ bin\x86\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ x86
+ false
+ prompt
+
+
+ ARM
+ true
+ bin\ARM\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ ARM
+ false
+ prompt
+
+
+ ARM
+ bin\ARM\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ ARM
+ false
+ prompt
+
+
+ x64
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ x64
+ false
+ prompt
+
+
+ x64
+ bin\x64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ x64
+ false
+ prompt
+
+
+ PackageReference
+
+
+
+
+
+
+
+ 6.0.8
+
+
+
+ 14.0
+
+
+
+
\ No newline at end of file