-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #52 from lizaalert/dev
Dev
- Loading branch information
Showing
12 changed files
with
426 additions
and
6 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ public enum Status | |
Ready, | ||
Working, | ||
Success, | ||
Unauthenticated, | ||
Error | ||
} | ||
|
||
|
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,83 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Security.Cryptography; | ||
using Microsoft.AspNetCore.Cryptography.KeyDerivation; | ||
|
||
namespace RescuerLaApp.Models | ||
{ | ||
public class PasswordHasher | ||
{ | ||
public string GenerateIdentityV3Hash(string password, KeyDerivationPrf prf = KeyDerivationPrf.HMACSHA256, int iterationCount = 10000, int saltSize = 16) | ||
{ | ||
using (var rng = RandomNumberGenerator.Create()){ | ||
var salt = new byte[saltSize]; | ||
rng.GetBytes(salt); | ||
|
||
var pbkdf2Hash = KeyDerivation.Pbkdf2(password, salt, prf, iterationCount, 32); | ||
return Convert.ToBase64String(ComposeIdentityV3Hash(salt, (uint)iterationCount, pbkdf2Hash)); | ||
} | ||
} | ||
public bool VerifyIdentityV3Hash(string password, string passwordHash) | ||
{ | ||
var identityV3HashArray = Convert.FromBase64String(passwordHash); | ||
if (identityV3HashArray[0] != 1) throw new InvalidOperationException("passwordHash is not Identity V3"); | ||
|
||
var prfAsArray = new byte[4]; | ||
Buffer.BlockCopy(identityV3HashArray, 1, prfAsArray, 0, 4); | ||
var prf = (KeyDerivationPrf)ConvertFromNetworOrder(prfAsArray); | ||
|
||
var iterationCountAsArray = new byte[4]; | ||
Buffer.BlockCopy(identityV3HashArray, 5, iterationCountAsArray, 0, 4); | ||
var iterationCount = (int)ConvertFromNetworOrder(iterationCountAsArray); | ||
|
||
var saltSizeAsArray = new byte[4]; | ||
Buffer.BlockCopy(identityV3HashArray, 9, saltSizeAsArray, 0, 4); | ||
var saltSize = (int)ConvertFromNetworOrder(saltSizeAsArray); | ||
|
||
var salt = new byte[saltSize]; | ||
Buffer.BlockCopy(identityV3HashArray, 13, salt, 0, saltSize); | ||
|
||
var savedHashedPassword = new byte[identityV3HashArray.Length - 1 - 4 - 4 - 4 - saltSize]; | ||
Buffer.BlockCopy(identityV3HashArray, 13 + saltSize, savedHashedPassword, 0, savedHashedPassword.Length); | ||
|
||
var hashFromInputPassword = KeyDerivation.Pbkdf2(password, salt, prf, iterationCount, 32); | ||
|
||
return AreByteArraysEqual(hashFromInputPassword, savedHashedPassword); | ||
} | ||
private byte[] ComposeIdentityV3Hash(byte[] salt, uint iterationCount, byte[] passwordHash) | ||
{ | ||
var hash = new byte[1 + 4/*KeyDerivationPrf value*/ + 4/*Iteration count*/ + 4/*salt size*/ + salt.Length /*salt*/ + 32 /*password hash size*/]; | ||
hash[0] = 1; //Identity V3 marker | ||
|
||
Buffer.BlockCopy(ConvertToNetworkOrder((uint)KeyDerivationPrf.HMACSHA256), 0, hash, 1, sizeof(uint)); | ||
Buffer.BlockCopy(ConvertToNetworkOrder((uint)iterationCount), 0, hash, 1 + sizeof(uint), sizeof(uint)); | ||
Buffer.BlockCopy(ConvertToNetworkOrder((uint)salt.Length), 0, hash, 1 + 2 * sizeof(uint), sizeof(uint)); | ||
Buffer.BlockCopy(salt, 0, hash, 1 + 3 * sizeof(uint), salt.Length); | ||
Buffer.BlockCopy(passwordHash, 0, hash, 1 + 3 * sizeof(uint) + salt.Length, passwordHash.Length); | ||
|
||
return hash; | ||
} | ||
|
||
private bool AreByteArraysEqual(byte[] array1, byte[] array2) | ||
{ | ||
if (array1.Length != array2.Length) return false; | ||
|
||
var areEqual = true; | ||
for (var i = 0; i < array1.Length; i++) | ||
{ | ||
areEqual &= (array1[i] == array2[i]); | ||
} | ||
return areEqual; | ||
} | ||
|
||
private byte[] ConvertToNetworkOrder(uint number) | ||
{ | ||
return BitConverter.GetBytes(number).Reverse().ToArray(); | ||
} | ||
|
||
private uint ConvertFromNetworOrder(byte[] reversedUint) | ||
{ | ||
return BitConverter.ToUInt32(reversedUint.Reverse().ToArray(), 0); | ||
} | ||
} | ||
} |
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 |
---|---|---|
|
@@ -11,7 +11,7 @@ internal static class Program | |
{ | ||
private static void Main(string[] args) | ||
{ | ||
Console.WriteLine("Lacmus desktop application. Version 0.3.0 alpha. \nCopyright (c) 2019 Georgy Perevozghikov <[email protected]>\nGithub page: https://github.com/lizaalert/lacmus/.\nProvided by Yandex Cloud: https://cloud.yandex.com/."); | ||
Console.WriteLine("Lacmus desktop application. Version 0.3.1 alpha. \nCopyright (c) 2019 Georgy Perevozghikov <[email protected]>\nGithub page: https://github.com/lizaalert/lacmus/.\nProvided by Yandex Cloud: https://cloud.yandex.com/."); | ||
Console.WriteLine("This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'."); | ||
Console.WriteLine("This is free software, and you are welcome to redistribute it\nunder certain conditions; type `show c' for details."); | ||
Console.WriteLine("------------------------------------"); | ||
|
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
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,20 @@ | ||
<Window xmlns="https://github.com/avaloniaui" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | ||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | ||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" | ||
x:Class="RescuerLaApp.Views.SignInWindow" SizeToContent="WidthAndHeight" CanResize="False"> | ||
<StackPanel HorizontalAlignment="Center"> | ||
<TextBlock Margin="10 2 10 2">Email</TextBlock> | ||
<TextBox Name="tbEmail" Margin="10 2 10 2" Height="30" Width="300"></TextBox> | ||
<TextBlock Margin="10 2 10 2">Password</TextBlock> | ||
<TextBox Name="tbPassword" Margin="10 2 10 2" Height="30" Width="300"></TextBox> | ||
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Name="Buttons"> | ||
<StackPanel.Styles> | ||
<Style Selector="Button"> | ||
<Setter Property="Margin" Value="10, 5, 10, 5"/> | ||
</Style> | ||
</StackPanel.Styles> | ||
</StackPanel> | ||
</StackPanel> | ||
</Window> |
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,113 @@ | ||
using System; | ||
using System.Data; | ||
using System.IO; | ||
using System.Threading.Tasks; | ||
using Avalonia.Controls; | ||
using Avalonia.Interactivity; | ||
using Avalonia.Markup.Xaml; | ||
using MessageBox.Avalonia.DTO; | ||
using MessageBox.Avalonia.Enums; | ||
using Newtonsoft.Json; | ||
using RescuerLaApp.Models; | ||
|
||
namespace RescuerLaApp.Views | ||
{ | ||
class SignInWindow : Window | ||
{ | ||
[JsonObject] | ||
public class SignInResult | ||
{ | ||
[JsonProperty("email")] | ||
public string Email { get; set; } | ||
[JsonProperty("passwordHash")] | ||
public string PasswordHash { get; set; } | ||
[JsonProperty("id")] | ||
public int Id { get; set; } | ||
[JsonProperty("time")] | ||
public string Time { get; set; } | ||
|
||
public bool IsSignIn { get; set; } = false; | ||
} | ||
|
||
public SignInWindow() | ||
{ | ||
AvaloniaXamlLoader.Load(this); | ||
} | ||
|
||
public static Task<SignInResult> Show(Window parent) | ||
{ | ||
var title = "Sign In"; | ||
var msgbox = new SignInWindow() | ||
{ | ||
Title = title | ||
}; | ||
var buttonPanel = msgbox.FindControl<StackPanel>("Buttons"); | ||
|
||
SignInResult res = new SignInResult(); | ||
|
||
void AddButton(string caption) | ||
{ | ||
var btn = new Button {Content = caption}; | ||
btn.Click += (_, __) => | ||
{ | ||
var patch = AppDomain.CurrentDomain.BaseDirectory + "user_info"; | ||
if (File.Exists(patch)) | ||
{ | ||
res = JsonConvert.DeserializeObject<SignInResult>(File.ReadAllText(patch)); | ||
} | ||
else | ||
{ | ||
ShowError("There are no account. Please sign up"); | ||
return; | ||
} | ||
|
||
var passwordHash = msgbox.FindControl<TextBox>("tbPassword").Text; | ||
var email = msgbox.FindControl<TextBox>("tbEmail").Text; | ||
|
||
if (string.IsNullOrWhiteSpace(passwordHash) || passwordHash.Length < 6) | ||
{ | ||
ShowError("Incorrect Password"); | ||
return; | ||
} | ||
PasswordHasher hasher = new PasswordHasher(); | ||
if (string.IsNullOrWhiteSpace(passwordHash) || !hasher.VerifyIdentityV3Hash(passwordHash, res.PasswordHash)) | ||
{ | ||
ShowError("Incorrect Password"); | ||
return; | ||
} | ||
if (string.IsNullOrWhiteSpace(email) || !email.Contains('@') || !email.Contains('.') || email != res.Email) | ||
{ | ||
ShowError("Incorrect Email"); | ||
return; | ||
} | ||
|
||
res.IsSignIn = true; | ||
msgbox.Close(); | ||
}; | ||
buttonPanel.Children.Add(btn); | ||
} | ||
|
||
AddButton("Sign Ip"); | ||
var tcs = new TaskCompletionSource<SignInResult>(); | ||
msgbox.Closed += delegate { tcs.TrySetResult(res); }; | ||
if (parent != null) | ||
msgbox.ShowDialog(parent); | ||
else msgbox.Show(); | ||
return tcs.Task; | ||
} | ||
|
||
private static async void ShowError(string message) | ||
{ | ||
var msgbox = new MessageBox.Avalonia.MessageBoxWindow(new MessageBoxParams | ||
{ | ||
Button = ButtonEnum.Ok, | ||
ContentTitle = "Error", | ||
ContentMessage = message, | ||
Icon = MessageBox.Avalonia.Enums.Icon.Error, | ||
Style = Style.None, | ||
ShowInCenter = true | ||
}); | ||
var result = await msgbox.Show(); | ||
} | ||
} | ||
} |
Empty file.
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,26 @@ | ||
<Window xmlns="https://github.com/avaloniaui" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | ||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | ||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" | ||
x:Class="RescuerLaApp.Views.SignUpWindow" SizeToContent="WidthAndHeight" CanResize="False"> | ||
<StackPanel HorizontalAlignment="Center"> | ||
<TextBlock Margin="10 2 10 2">Email</TextBlock> | ||
<TextBox Name="tbEmail" Margin="10 2 10 2" Height="30" Width="300"></TextBox> | ||
<TextBlock Margin="10 2 10 2">Nick name</TextBlock> | ||
<TextBox Name="tbNickName" Margin="10 2 10 2" Height="30" Width="300"></TextBox> | ||
<TextBlock Margin="10 2 10 2">First name</TextBlock> | ||
<TextBox Name="tbFirstName" Margin="10 2 10 2" Height="30" Width="300"></TextBox> | ||
<TextBlock Margin="10 2 10 2">Last name</TextBlock> | ||
<TextBox Name="tbLastName" Margin="10 2 10 2" Height="30" Width="300"></TextBox> | ||
<TextBlock Margin="10 2 10 2">Password</TextBlock> | ||
<TextBox Name="tbPassword" Margin="10 2 10 2" Height="30" Width="300"></TextBox> | ||
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Name="Buttons"> | ||
<StackPanel.Styles> | ||
<Style Selector="Button"> | ||
<Setter Property="Margin" Value="10, 5, 10, 5"/> | ||
</Style> | ||
</StackPanel.Styles> | ||
</StackPanel> | ||
</StackPanel> | ||
</Window> |
Oops, something went wrong.