123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- using InABox.Clients;
- using InABox.Core;
- using InABox.Wpf;
- using Microsoft.Exchange.WebServices.Data;
- using Syncfusion.UI.Xaml.Controls.Barcode;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Web;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Data;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Windows.Shapes;
- namespace PRSDesktop.Panels.Users
- {
- /// <summary>
- /// Interaction logic for QR2FAWindow.xaml
- /// </summary>
- public partial class QR2FAWindow : ThemableWindow
- {
- private User User;
- public QR2FAWindow(User user)
- {
- User = user;
- user.AuthenticatorToken ??= User.GenerateAuthenticationToken();
- InitializeComponent();
- Barcode.QuietZone.All = 0;
- SetBarcodeText(user.UserID, user.AuthenticatorToken);
- Reset.IsEnabled = Security.CanEdit<User>();
- }
- public void SetBarcodeText(string userID, byte[] key)
- {
- var secret = Base32Encoding.ToString(key).Trim('=');
- var info = new Client<CompanyInformation>().Load().FirstOrDefault();
- if (info == null)
- info = new CompanyInformation();
- SetupKey.Text = secret;
- Barcode.Text = $"otpauth://totp/PRS-{Uri.EscapeDataString(userID)}?secret={secret}&issuer=PRS%20-%20{Uri.EscapeDataString(info.CompanyName)}";
- }
- private void OK_Click(object sender, RoutedEventArgs e)
- {
- DialogResult = true;
- Close();
- }
- private void Reset_Click(object sender, RoutedEventArgs e)
- {
- if(MessageBox.Show("Doing this will invalidate the authentication of this user, preventing them from being able to log in until they have rescanned this code. Do you wish to proceed?", "Continue?", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
- {
- User.AuthenticatorToken = User.GenerateAuthenticationToken();
- SetBarcodeText(User.UserID, User.AuthenticatorToken);
- }
- }
- }
- // Code taken from https://stackoverflow.com/questions/641361/base32-decoding
- public class Base32Encoding
- {
- public static byte[] ToBytes(string input)
- {
- if (string.IsNullOrEmpty(input))
- {
- throw new ArgumentNullException("input");
- }
- input = input.TrimEnd('='); //remove padding characters
- int byteCount = input.Length * 5 / 8; //this must be TRUNCATED
- byte[] returnArray = new byte[byteCount];
- byte curByte = 0, bitsRemaining = 8;
- int mask = 0, arrayIndex = 0;
- foreach (char c in input)
- {
- int cValue = CharToValue(c);
- if (bitsRemaining > 5)
- {
- mask = cValue << (bitsRemaining - 5);
- curByte = (byte)(curByte | mask);
- bitsRemaining -= 5;
- }
- else
- {
- mask = cValue >> (5 - bitsRemaining);
- curByte = (byte)(curByte | mask);
- returnArray[arrayIndex++] = curByte;
- curByte = (byte)(cValue << (3 + bitsRemaining));
- bitsRemaining += 3;
- }
- }
- //if we didn't end with a full byte
- if (arrayIndex != byteCount)
- {
- returnArray[arrayIndex] = curByte;
- }
- return returnArray;
- }
- public static string ToString(byte[] input)
- {
- if (input == null || input.Length == 0)
- {
- throw new ArgumentNullException("input");
- }
- int charCount = (int)Math.Ceiling(input.Length / 5d) * 8;
- char[] returnArray = new char[charCount];
- byte nextChar = 0, bitsRemaining = 5;
- int arrayIndex = 0;
- foreach (byte b in input)
- {
- nextChar = (byte)(nextChar | (b >> (8 - bitsRemaining)));
- returnArray[arrayIndex++] = ValueToChar(nextChar);
- if (bitsRemaining < 4)
- {
- nextChar = (byte)((b >> (3 - bitsRemaining)) & 31);
- returnArray[arrayIndex++] = ValueToChar(nextChar);
- bitsRemaining += 5;
- }
- bitsRemaining -= 3;
- nextChar = (byte)((b << bitsRemaining) & 31);
- }
- //if we didn't end with a full char
- if (arrayIndex != charCount)
- {
- returnArray[arrayIndex++] = ValueToChar(nextChar);
- while (arrayIndex != charCount) returnArray[arrayIndex++] = '='; //padding
- }
- return new string(returnArray);
- }
- private static int CharToValue(char c)
- {
- int value = (int)c;
- //65-90 == uppercase letters
- if (value < 91 && value > 64)
- {
- return value - 65;
- }
- //50-55 == numbers 2-7
- if (value < 56 && value > 49)
- {
- return value - 24;
- }
- //97-122 == lowercase letters
- if (value < 123 && value > 96)
- {
- return value - 97;
- }
- throw new ArgumentException("Character is not a Base32 character.", "c");
- }
- private static char ValueToChar(byte b)
- {
- if (b < 26)
- {
- return (char)(b + 65);
- }
- if (b < 32)
- {
- return (char)(b + 24);
- }
- throw new ArgumentException("Byte is not a value Base32 value.", "b");
- }
- }
- }
|