diff --git a/src/App/Abstractions/Services/IAuthService.cs b/src/App/Abstractions/Services/IAuthService.cs index ff7f70cf4..56246af7a 100644 --- a/src/App/Abstractions/Services/IAuthService.cs +++ b/src/App/Abstractions/Services/IAuthService.cs @@ -8,6 +8,7 @@ namespace Bit.App.Abstractions bool IsAuthenticated { get; } string Token { get; set; } string UserId { get; set; } + string PIN { get; set; } void LogOut(); Task> TokenPostAsync(TokenRequest request); diff --git a/src/App/App.csproj b/src/App/App.csproj index a57043e39..123b00c7e 100644 --- a/src/App/App.csproj +++ b/src/App/App.csproj @@ -84,6 +84,7 @@ + diff --git a/src/App/Controls/PinControl.cs b/src/App/Controls/PinControl.cs index 78b0708e5..6fdb8a547 100644 --- a/src/App/Controls/PinControl.cs +++ b/src/App/Controls/PinControl.cs @@ -5,14 +5,10 @@ namespace Bit.App.Controls { public class PinControl { - private Action _pinEnteredAction; - private Action _confirmPinEnteredAction; + public EventHandler OnPinEntered; - public PinControl(Action pinEnteredAction, Action confirmPinEnteredAction = null) + public PinControl() { - _pinEnteredAction = pinEnteredAction; - _confirmPinEnteredAction = confirmPinEnteredAction; - Label = new Label { HorizontalTextAlignment = TextAlignment.Center, @@ -28,34 +24,17 @@ namespace Bit.App.Controls Margin = new Thickness(0, int.MaxValue, 0, 0) }; Entry.TextChanged += Entry_TextChanged; - - ConfirmEntry = new ExtendedEntry - { - Keyboard = Keyboard.Numeric, - MaxLength = 4, - Margin = new Thickness(0, int.MaxValue, 0, 0) - }; - Entry.TextChanged += ConfirmEntry_TextChanged; } private void Entry_TextChanged(object sender, TextChangedEventArgs e) { - if(e.NewTextValue.Length >= 4 && _pinEnteredAction != null) + if(e.NewTextValue.Length >= 4) { - _pinEnteredAction(); - } - } - - private void ConfirmEntry_TextChanged(object sender, TextChangedEventArgs e) - { - if(e.NewTextValue.Length >= 4 && _confirmPinEnteredAction != null) - { - _confirmPinEnteredAction(); + OnPinEntered.Invoke(this, null); } } public Label Label { get; set; } public ExtendedEntry Entry { get; set; } - public ExtendedEntry ConfirmEntry { get; set; } } } diff --git a/src/App/Pages/LockPinPage.cs b/src/App/Pages/LockPinPage.cs index b4b012e19..72151e375 100644 --- a/src/App/Pages/LockPinPage.cs +++ b/src/App/Pages/LockPinPage.cs @@ -31,7 +31,8 @@ namespace Bit.App.Pages public void Init() { - PinControl = new PinControl(PinEntered); + PinControl = new PinControl(); + PinControl.OnPinEntered += PinEntered; PinControl.Label.SetBinding(Label.TextProperty, s => s.LabelText); PinControl.Entry.SetBinding(Entry.TextProperty, s => s.PIN); @@ -76,9 +77,9 @@ namespace Bit.App.Pages PinControl.Entry.Focus(); } - protected void PinEntered() + protected void PinEntered(object sender, EventArgs args) { - if(Model.PIN == "1234") + if(Model.PIN == _authService.PIN) { PinControl.Entry.Unfocus(); Navigation.PopModalAsync(); diff --git a/src/App/Pages/SettingsPage.cs b/src/App/Pages/SettingsPage.cs index 79b088c4f..0cf56231a 100644 --- a/src/App/Pages/SettingsPage.cs +++ b/src/App/Pages/SettingsPage.cs @@ -215,12 +215,28 @@ namespace Bit.App.Pages return; } - _settings.AddOrUpdateValue(Constants.SettingPinUnlockOn, cell.On); if(cell.On) { - _settings.AddOrUpdateValue(Constants.SettingFingerprintUnlockOn, false); - FingerprintCell.On = false; + var pinPage = new SettingsPinPage(); + pinPage.OnPinEntered += PinEntered; + Navigation.PushAsync(pinPage); } + else + { + _settings.AddOrUpdateValue(Constants.SettingPinUnlockOn, false); + } + } + + private void PinEntered(object sender, EventArgs args) + { + var page = sender as SettingsPinPage; + page.Navigation.PopAsync(); + + _authService.PIN = page.Model.PIN; + + _settings.AddOrUpdateValue(Constants.SettingPinUnlockOn, true); + _settings.AddOrUpdateValue(Constants.SettingFingerprintUnlockOn, false); + FingerprintCell.On = false; } private void FoldersCell_Tapped(object sender, EventArgs e) diff --git a/src/App/Pages/SettingsPinPage.cs b/src/App/Pages/SettingsPinPage.cs new file mode 100644 index 000000000..12bfcb095 --- /dev/null +++ b/src/App/Pages/SettingsPinPage.cs @@ -0,0 +1,71 @@ +using System; +using System.Threading.Tasks; +using Acr.UserDialogs; +using Bit.App.Abstractions; +using Bit.App.Resources; +using Xamarin.Forms; +using XLabs.Ioc; +using Plugin.Settings.Abstractions; +using Bit.App.Models.Page; +using Bit.App.Controls; + +namespace Bit.App.Pages +{ + public class SettingsPinPage : ContentPage + { + private readonly IUserDialogs _userDialogs; + private readonly ISettings _settings; + + public SettingsPinPage() + { + _userDialogs = Resolver.Resolve(); + _settings = Resolver.Resolve(); + + Init(); + } + + public PinPageModel Model { get; set; } = new PinPageModel(); + public PinControl PinControl { get; set; } + public EventHandler OnPinEntered; + + public void Init() + { + PinControl = new PinControl(); + PinControl.OnPinEntered += PinEntered; + PinControl.Label.SetBinding(Label.TextProperty, s => s.LabelText); + PinControl.Entry.SetBinding(Entry.TextProperty, s => s.PIN); + + var stackLayout = new StackLayout + { + Padding = new Thickness(30, 40), + Spacing = 10, + Children = { PinControl.Label, PinControl.Entry } + }; + + var tgr = new TapGestureRecognizer(); + tgr.Tapped += Tgr_Tapped; + + Title = "Set PIN"; + Content = stackLayout; + Content.GestureRecognizers.Add(tgr); + BackgroundImage = "bg.png"; + BindingContext = Model; + } + + private void Tgr_Tapped(object sender, EventArgs e) + { + PinControl.Entry.Focus(); + } + + protected override void OnAppearing() + { + base.OnAppearing(); + PinControl.Entry.Focus(); + } + + protected void PinEntered(object sender, EventArgs args) + { + OnPinEntered.Invoke(this, null); + } + } +} diff --git a/src/App/Services/AuthService.cs b/src/App/Services/AuthService.cs index f309f466e..6cd273f4d 100644 --- a/src/App/Services/AuthService.cs +++ b/src/App/Services/AuthService.cs @@ -11,6 +11,7 @@ namespace Bit.App.Services { private const string TokenKey = "token"; private const string UserIdKey = "userId"; + private const string PinKey = "pin"; private readonly ISecureStorageService _secureStorage; private readonly ISettings _settings; @@ -19,6 +20,7 @@ namespace Bit.App.Services private string _token; private string _userId; + private string _pin; public AuthService( ISecureStorageService secureStorage, @@ -60,8 +62,9 @@ namespace Bit.App.Services else { _secureStorage.Delete(TokenKey); - _token = null; } + + _token = value; } } @@ -86,8 +89,9 @@ namespace Bit.App.Services else { _settings.Remove(UserIdKey); - _userId = null; } + + _userId = value; } } @@ -99,6 +103,40 @@ namespace Bit.App.Services } } + public string PIN + { + get + { + if(_pin != null) + { + return _pin; + } + + var pinBytes = _secureStorage.Retrieve(PinKey); + if(pinBytes == null) + { + return null; + } + + _pin = Encoding.UTF8.GetString(pinBytes, 0, pinBytes.Length); + return _pin; + } + set + { + if(value != null) + { + var pinBytes = Encoding.UTF8.GetBytes(value); + _secureStorage.Store(PinKey, pinBytes); + } + else + { + _secureStorage.Delete(PinKey); + } + + _pin = value; + } + } + public void LogOut() { Token = null;