Skip to content

Commit

Permalink
💾 Feat(Dashboard): Available to exchange key.
Browse files Browse the repository at this point in the history
  • Loading branch information
Dynesshely committed Mar 2, 2024
1 parent 2107c09 commit 5cc5784
Show file tree
Hide file tree
Showing 15 changed files with 1,498 additions and 1,331 deletions.
2 changes: 2 additions & 0 deletions KitX Dashboard/ConstantTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ internal static class ConstantTable

internal static string ThirdPartLicenseFilePath => thirdPartLicenseFilePath.GetFullPath();

internal static string? ExchangeDeviceKeyCode;

internal static int DevicesServerPort = -1;

internal static int PluginsServerPort = -1;
Expand Down
367 changes: 186 additions & 181 deletions KitX Dashboard/Languages/en-us.axaml

Large diffs are not rendered by default.

367 changes: 186 additions & 181 deletions KitX Dashboard/Languages/fr-fr.axaml

Large diffs are not rendered by default.

367 changes: 186 additions & 181 deletions KitX Dashboard/Languages/ja-jp.axaml

Large diffs are not rendered by default.

367 changes: 186 additions & 181 deletions KitX Dashboard/Languages/ko-kr.axaml

Large diffs are not rendered by default.

367 changes: 186 additions & 181 deletions KitX Dashboard/Languages/ru-ru.axaml

Large diffs are not rendered by default.

367 changes: 186 additions & 181 deletions KitX Dashboard/Languages/zh-cn.axaml

Large diffs are not rendered by default.

367 changes: 186 additions & 181 deletions KitX Dashboard/Languages/zh-tw.axaml

Large diffs are not rendered by default.

56 changes: 56 additions & 0 deletions KitX Dashboard/Managers/SecurityManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,60 @@ public static string GetSHA1(string data)

return sb.ToString();
}

private static string ExpandKey(string key, int length)
{
var expandedKey = key.Length <= length ? key : key[..length];

var expandIndex = 0;

while (expandedKey.Length < length)
{
if (expandIndex == key.Length) expandIndex = 0;

expandedKey += key[expandIndex];

expandIndex++;
}

return expandedKey;
}

public static string AesEncrypt(string source, string key)
{
var data = source.FromUTF8();

var expandedKey = ExpandKey(key, 16);

var keyData = expandedKey.FromUTF8();
var iv = expandedKey.FromUTF8();

using var aes = Aes.Create();

aes.Key = keyData;
aes.IV = iv;

var result = aes.EncryptCbc(data, iv, PaddingMode.ISO10126);

return Convert.ToBase64String(result);
}

public static string AesDecrypt(string source, string key, bool isSourceInBase64 = true)
{
var data = isSourceInBase64 ? Convert.FromBase64String(source) : source.FromUTF8();

var expandedKey = ExpandKey(key, 16);

var keyData = expandedKey.FromUTF8();
var iv = expandedKey.FromUTF8();

using var aes = Aes.Create();

aes.Key = keyData;
aes.IV = iv;

var result = aes.DecryptCbc(data, iv, PaddingMode.ISO10126);

return result.ToUTF8();
}
}
39 changes: 0 additions & 39 deletions KitX Dashboard/Network/DevicesNetwork/DevicesOrganizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Avalonia.Threading;
using KitX.Dashboard.Configuration;
using KitX.Dashboard.Managers;
using KitX.Dashboard.Models;
using KitX.Dashboard.Services;
using KitX.Dashboard.Views;
using KitX.Shared.CSharp.Device;
using MsBox.Avalonia;
using Serilog;
using Timer = System.Timers.Timer;

Expand All @@ -31,8 +28,6 @@ internal class DevicesOrganizer : ConfigFetcher

private bool KeepCheckAndRemoveTaskRunning = false;

private List<string> SignedDeviceTokens { get; } = [];

public DevicesOrganizer()
{
Initialize();
Expand Down Expand Up @@ -274,38 +269,4 @@ private void WatchingOver(bool foundMainDevice, string serverAddress, int server
ConstantTable.IsMainMachine = true;
}
}

internal bool IsDeviceTokenExist(string token) => SignedDeviceTokens.Contains(token);

internal void AddDeviceToken(string token) => SignedDeviceTokens.Add(token);

public void RequireAcceptDeviceKey
(
DeviceLocator locator,
string verifyCodeSHA1,
string deviceKey
)
{
Dispatcher.UIThread.Post(() =>
{
var window = new ExchangeDeviceKeyWindow();
ViewInstances.ShowWindow(
window.OnVerificationCodeEntered(async code =>
{
if (verifyCodeSHA1.Equals(SecurityManager.GetSHA1(code)))
{
}
else
{
await window.OnErrorDecodeAsync();
}
}),
ViewInstances.MainWindow,
false,
true
);
});
}
}
80 changes: 80 additions & 0 deletions KitX Dashboard/Network/DevicesNetwork/DevicesServer.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Threading;
using KitX.Dashboard.Configuration;
using KitX.Dashboard.Managers;
using KitX.Dashboard.Services;
using KitX.Dashboard.Views;
using KitX.Shared.CSharp.Device;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server;
Expand All @@ -26,6 +32,8 @@ public class DevicesServer : ConfigFetcher

private IHost? _host;

private List<string> SignedDeviceTokens { get; } = [];

public async Task<DevicesServer> RunAsync()
{
var host = CreateHostBuilder([]).Build();
Expand Down Expand Up @@ -69,6 +77,78 @@ private IHostBuilder CreateHostBuilder(string[] args) =>
webBuilder.UseUrls($"http://0.0.0.0:{port}");
})
;

internal bool IsDeviceTokenExist(string token) => SignedDeviceTokens.Contains(token);

internal void AddDeviceToken(string token) => SignedDeviceTokens.Add(token);

public void RequireAcceptDeviceKey(string verifyCodeSHA1, int port, string deviceKey)
{
Dispatcher.UIThread.Post(() =>
{
var window = new ExchangeDeviceKeyWindow();
ViewInstances.ShowWindow(
window.OnVerificationCodeEntered(async code =>
{
if (verifyCodeSHA1.Equals(SecurityManager.GetSHA1(code)))
{
var deviceKeyDecrypted = SecurityManager.AesDecrypt(deviceKey, code);
var deviceKeyInstance = JsonSerializer.Deserialize<DeviceKey>(deviceKeyDecrypted);
if (deviceKeyInstance is null) await window.OnErrorDecodeAsync();
else
{
var sender = deviceKeyInstance.Device;
var url = $"http://{sender.IPv4}:{port}/Api/Device/ExchangeKeyBack";
if (SecurityManager.Instance.LocalDeviceKey is null)
{
await window.OnErrorDecodeAsync();
return;
}
var currentKey = new DeviceKey()
{
Device = SecurityManager.Instance.LocalDeviceKey.Device,
RsaPrivateKeyD = SecurityManager.Instance.LocalDeviceKey.RsaPrivateKeyD,
RsaPrivateKeyModulus = SecurityManager.Instance.LocalDeviceKey.RsaPrivateKeyModulus,
};
if (currentKey is null)
{
await window.OnErrorDecodeAsync();
return;
}
var currentKeyJson = JsonSerializer.Serialize(currentKey);
var currentKeyEncrypted = SecurityManager.AesEncrypt(currentKeyJson, code);
using var http = new HttpClient();
var response = await http.PostAsync(url, new StringContent(currentKeyEncrypted));
if (response.IsSuccessStatusCode)
SecurityManager.Instance.AddDeviceKey(deviceKeyInstance);
else await window.OnErrorDecodeAsync();
}
}
else
{
await window.OnErrorDecodeAsync();
}
}),
ViewInstances.MainWindow,
false,
true
);
});
}
}

public class Startup
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,47 @@
using KitX.Shared.CSharp.Device;
using System.Text.Json;
using KitX.Dashboard.Managers;
using KitX.Shared.CSharp.Device;
using Microsoft.AspNetCore.Mvc;

namespace KitX.Dashboard.Network.DevicesNetwork.DevicesServerControllers;

[ApiController]
[Route("Api/V1/[controller]")]
[Route("Api/[controller]")]
[ApiExplorerSettings(GroupName = "V1")]
public class DeviceController : ControllerBase
{
[ApiExplorerSettings(GroupName = "V1")]
[HttpGet("", Name = nameof(GetDeviceInfo))]
public IActionResult GetDeviceInfo([FromQuery] string token)
{
if (DevicesOrganizer.Instance.IsDeviceTokenExist(token))
if (DevicesServer.Instance.IsDeviceTokenExist(token))
return Ok(DevicesDiscoveryServer.Instance.DefaultDeviceInfo);
else
return BadRequest("You should connect to this device first.");
}

[ApiExplorerSettings(GroupName = "V1")]
[HttpPost("/ExchangeKey", Name = nameof(ExchangeKey))]
public IActionResult ExchangeKey
(
[FromQuery] DeviceLocator locator,
[FromQuery] string verifyCodeSHA1,
[FromBody] string deviceKey
)
public IActionResult ExchangeKey([FromQuery] string verifyCodeSHA1, [FromQuery] int port, [FromBody] string deviceKey)
{
DevicesOrganizer.Instance.RequireAcceptDeviceKey(
locator,
verifyCodeSHA1,
deviceKey
);
DevicesServer.Instance.RequireAcceptDeviceKey(verifyCodeSHA1, port, deviceKey);

return Ok();
}

[ApiExplorerSettings(GroupName = "V1")]
[HttpPost("/ExchangeKeyBack", Name = nameof(ExchangeKeyBack))]
public IActionResult ExchangeKeyBack([FromQuery] string deviceKey)
{
if (ConstantTable.ExchangeDeviceKeyCode is null) return BadRequest();

var deviceKeyDecrypted = SecurityManager.AesDecrypt(deviceKey, ConstantTable.ExchangeDeviceKeyCode);

var deviceKeyInstance = JsonSerializer.Deserialize<DeviceKey>(deviceKeyDecrypted);

if (deviceKeyInstance is null) return BadRequest();

SecurityManager.Instance.AddDeviceKey(deviceKeyInstance);

return Ok();
}
Expand Down
11 changes: 8 additions & 3 deletions KitX Dashboard/ViewModels/ExchangeDeviceKeyWindowViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reactive;
using Common.BasicHelper.Utils.Extensions;
using ReactiveUI;

namespace KitX.Dashboard.ViewModels;

internal class ExchangeDeviceKeyWindowViewModel : ViewModelBase
{
private Action? OnCancelAction;
private readonly Queue<Action> OnCancelActions = [];

public ExchangeDeviceKeyWindowViewModel()
{
Expand All @@ -19,7 +22,7 @@ public override void InitCommands()
{
CancelCommand = ReactiveCommand.Create(() =>
{
OnCancelAction?.Invoke();
OnCancelActions.ForEach(x => x.Invoke());
});
}

Expand All @@ -40,6 +43,8 @@ public override void InitEvents()

public string CurrentCodeIndex => updatingIndex.ToString();

public ObservableCollection<string> Logs { get; } = [];

private void Update()
{
this.RaisePropertyChanged(nameof(VerificationCode));
Expand Down Expand Up @@ -90,7 +95,7 @@ internal void Paste(string code)

internal ExchangeDeviceKeyWindowViewModel OnCancel(Action action)
{
OnCancelAction = action;
OnCancelActions.Enqueue(action);

return this;
}
Expand Down
13 changes: 7 additions & 6 deletions KitX Dashboard/Views/ExchangeDeviceKeyWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@
HorizontalAlignment="Center"
FontSize="24"
FontWeight="Bold"
Text="Exchanging Device Key"/>
Text="{DynamicResource Text_ExchangeDeviceKeyWindow_Title}"/>
<TextBlock Margin="30"
HorizontalAlignment="Center"
FontSize="16"
LineSpacing="10"
Text="Verification code displayed on the device is needed for exchanging key. If this wasn't you, please check your device's security."
Text="{DynamicResource Text_ExchangeDeviceKeyWindow_Description}"
TextAlignment="Center"
TextWrapping="WrapWithOverflow"/>
</StackPanel>
<StackPanel HorizontalAlignment="Right"
Expand All @@ -53,8 +54,8 @@
Orientation="Horizontal"
Spacing="10">
<Button Padding="20,5,20,6"
Command="{Binding}"
Content="Cancel"/>
Command="{Binding CancelCommand}"
Content="{DynamicResource Text_Public_Cancel}"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center"
VerticalAlignment="Top"
Expand Down Expand Up @@ -105,13 +106,13 @@
<Border Background="{DynamicResource ThemePrimaryAccent}" Opacity="0.1"/>
<StackPanel HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="30">
Spacing="20">
<progRing:ProgressRing Width="100"
Height="100"
HorizontalAlignment="Center"
IsActive="{Binding IsVerifing}"/>
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="16" Text="Your input: "/>
<TextBlock FontSize="16" Text="{DynamicResource Text_ExchangeDeviceKeyWindow_YourInput}"/>
<TextBlock FontSize="16" Text="{Binding VerificationCodeString}"/>
</StackPanel>
</StackPanel>
Expand Down
Loading

0 comments on commit 5cc5784

Please sign in to comment.