mirror of
https://github.com/bitwarden/android.git
synced 2024-12-24 18:08:26 +03:00
password lock VC for extension
This commit is contained in:
parent
c2cb5ac7c9
commit
047f5b100f
4 changed files with 208 additions and 35 deletions
|
@ -8,13 +8,14 @@ namespace Bit.iOS.Core.Views
|
||||||
public FormEntryTableViewCell(
|
public FormEntryTableViewCell(
|
||||||
string labelName = null,
|
string labelName = null,
|
||||||
bool useTextView = false,
|
bool useTextView = false,
|
||||||
nfloat? height = null)
|
nfloat? height = null,
|
||||||
|
bool useLabelAsPlaceholder = false)
|
||||||
: base(UITableViewCellStyle.Default, nameof(FormEntryTableViewCell))
|
: base(UITableViewCellStyle.Default, nameof(FormEntryTableViewCell))
|
||||||
{
|
{
|
||||||
var descriptor = UIFontDescriptor.PreferredBody;
|
var descriptor = UIFontDescriptor.PreferredBody;
|
||||||
var pointSize = descriptor.PointSize;
|
var pointSize = descriptor.PointSize;
|
||||||
|
|
||||||
if(labelName != null)
|
if(labelName != null && !useLabelAsPlaceholder)
|
||||||
{
|
{
|
||||||
Label = new UILabel
|
Label = new UILabel
|
||||||
{
|
{
|
||||||
|
@ -42,7 +43,7 @@ namespace Bit.iOS.Core.Views
|
||||||
NSLayoutConstraint.Create(ContentView, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, TextView, NSLayoutAttribute.Bottom, 1f, 10f)
|
NSLayoutConstraint.Create(ContentView, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, TextView, NSLayoutAttribute.Bottom, 1f, 10f)
|
||||||
});
|
});
|
||||||
|
|
||||||
if(labelName != null)
|
if(labelName != null && !useLabelAsPlaceholder)
|
||||||
{
|
{
|
||||||
ContentView.AddConstraint(
|
ContentView.AddConstraint(
|
||||||
NSLayoutConstraint.Create(TextView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, Label, NSLayoutAttribute.Bottom, 1f, 10f));
|
NSLayoutConstraint.Create(TextView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, Label, NSLayoutAttribute.Bottom, 1f, 10f));
|
||||||
|
@ -69,6 +70,11 @@ namespace Bit.iOS.Core.Views
|
||||||
ClearButtonMode = UITextFieldViewMode.WhileEditing
|
ClearButtonMode = UITextFieldViewMode.WhileEditing
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if(useLabelAsPlaceholder)
|
||||||
|
{
|
||||||
|
TextField.Placeholder = labelName;
|
||||||
|
}
|
||||||
|
|
||||||
ContentView.Add(TextField);
|
ContentView.Add(TextField);
|
||||||
ContentView.AddConstraints(new NSLayoutConstraint[] {
|
ContentView.AddConstraints(new NSLayoutConstraint[] {
|
||||||
NSLayoutConstraint.Create(TextField, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Leading, 1f, 15f),
|
NSLayoutConstraint.Create(TextField, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Leading, 1f, 15f),
|
||||||
|
@ -76,7 +82,7 @@ namespace Bit.iOS.Core.Views
|
||||||
NSLayoutConstraint.Create(ContentView, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, TextField, NSLayoutAttribute.Bottom, 1f, 10f)
|
NSLayoutConstraint.Create(ContentView, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, TextField, NSLayoutAttribute.Bottom, 1f, 10f)
|
||||||
});
|
});
|
||||||
|
|
||||||
if(labelName != null)
|
if(labelName != null && !useLabelAsPlaceholder)
|
||||||
{
|
{
|
||||||
ContentView.AddConstraint(
|
ContentView.AddConstraint(
|
||||||
NSLayoutConstraint.Create(TextField, NSLayoutAttribute.Top, NSLayoutRelation.Equal, Label, NSLayoutAttribute.Bottom, 1f, 10f));
|
NSLayoutConstraint.Create(TextField, NSLayoutAttribute.Top, NSLayoutRelation.Equal, Label, NSLayoutAttribute.Bottom, 1f, 10f));
|
||||||
|
@ -94,7 +100,7 @@ namespace Bit.iOS.Core.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(labelName != null)
|
if(labelName != null && !useLabelAsPlaceholder)
|
||||||
{
|
{
|
||||||
ContentView.AddConstraints(new NSLayoutConstraint[] {
|
ContentView.AddConstraints(new NSLayoutConstraint[] {
|
||||||
NSLayoutConstraint.Create(Label, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Leading, 1f, 15f),
|
NSLayoutConstraint.Create(Label, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Leading, 1f, 15f),
|
||||||
|
|
|
@ -5,17 +5,27 @@ using XLabs.Ioc;
|
||||||
using Plugin.Settings.Abstractions;
|
using Plugin.Settings.Abstractions;
|
||||||
using Foundation;
|
using Foundation;
|
||||||
using MobileCoreServices;
|
using MobileCoreServices;
|
||||||
|
using Bit.iOS.Core.Views;
|
||||||
|
using Bit.App.Resources;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.iOS.Core.Utilities;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Bit.iOS.Extension
|
namespace Bit.iOS.Extension
|
||||||
{
|
{
|
||||||
public partial class LockPasswordViewController : UIViewController
|
public partial class LockPasswordViewController : UITableViewController
|
||||||
{
|
{
|
||||||
private ISettings _settings;
|
private ISettings _settings;
|
||||||
|
private IAuthService _authService;
|
||||||
|
private ICryptoService _cryptoService;
|
||||||
|
|
||||||
public LockPasswordViewController(IntPtr handle) : base(handle)
|
public LockPasswordViewController(IntPtr handle) : base(handle)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public Context Context { get; set; }
|
public Context Context { get; set; }
|
||||||
|
public FormEntryTableViewCell MasterPasswordCell { get; set; } = new FormEntryTableViewCell(
|
||||||
|
AppResources.MasterPassword, useLabelAsPlaceholder: true);
|
||||||
|
|
||||||
public override void ViewWillAppear(bool animated)
|
public override void ViewWillAppear(bool animated)
|
||||||
{
|
{
|
||||||
|
@ -27,14 +37,72 @@ namespace Bit.iOS.Extension
|
||||||
public override void ViewDidLoad()
|
public override void ViewDidLoad()
|
||||||
{
|
{
|
||||||
_settings = Resolver.Resolve<ISettings>();
|
_settings = Resolver.Resolve<ISettings>();
|
||||||
|
_authService = Resolver.Resolve<IAuthService>();
|
||||||
|
_cryptoService = Resolver.Resolve<ICryptoService>();
|
||||||
|
|
||||||
View.BackgroundColor = new UIColor(red: 0.94f, green: 0.94f, blue: 0.96f, alpha: 1.0f);
|
View.BackgroundColor = new UIColor(red: 0.94f, green: 0.94f, blue: 0.96f, alpha: 1.0f);
|
||||||
|
|
||||||
var descriptor = UIFontDescriptor.PreferredBody;
|
var descriptor = UIFontDescriptor.PreferredBody;
|
||||||
|
|
||||||
|
MasterPasswordCell.TextField.SecureTextEntry = true;
|
||||||
|
MasterPasswordCell.TextField.ReturnKeyType = UIReturnKeyType.Go;
|
||||||
|
MasterPasswordCell.TextField.ShouldReturn += (UITextField tf) =>
|
||||||
|
{
|
||||||
|
CheckPassword();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
TableView.RowHeight = UITableView.AutomaticDimension;
|
||||||
|
TableView.EstimatedRowHeight = 70;
|
||||||
|
TableView.Source = new TableSource(this);
|
||||||
|
TableView.AllowsSelection = true;
|
||||||
|
|
||||||
base.ViewDidLoad();
|
base.ViewDidLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void ViewDidAppear(bool animated)
|
||||||
|
{
|
||||||
|
base.ViewDidAppear(animated);
|
||||||
|
MasterPasswordCell.TextField.BecomeFirstResponder();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void SubmitButton_Activated(UIBarButtonItem sender)
|
||||||
|
{
|
||||||
|
CheckPassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckPassword()
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(MasterPasswordCell.TextField.Text))
|
||||||
|
{
|
||||||
|
var alert = Dialogs.CreateAlert(AppResources.AnErrorHasOccurred,
|
||||||
|
string.Format(AppResources.ValidationFieldRequired, AppResources.MasterPassword), AppResources.Ok);
|
||||||
|
PresentViewController(alert, true, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var key = _cryptoService.MakeKeyFromPassword(MasterPasswordCell.TextField.Text, _authService.Email);
|
||||||
|
if(key.SequenceEqual(_cryptoService.Key))
|
||||||
|
{
|
||||||
|
MasterPasswordCell.TextField.ResignFirstResponder();
|
||||||
|
DismissModalViewController(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: keep track of invalid attempts and logout?
|
||||||
|
|
||||||
|
var alert = Dialogs.CreateAlert(AppResources.AnErrorHasOccurred,
|
||||||
|
string.Format(null, "Invalid Master Password. Try again."), AppResources.Ok, (a) =>
|
||||||
|
{
|
||||||
|
|
||||||
|
MasterPasswordCell.TextField.Text = string.Empty;
|
||||||
|
MasterPasswordCell.TextField.BecomeFirstResponder();
|
||||||
|
});
|
||||||
|
|
||||||
|
PresentViewController(alert, true, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
partial void CancelButton_Activated(UIBarButtonItem sender)
|
partial void CancelButton_Activated(UIBarButtonItem sender)
|
||||||
{
|
{
|
||||||
CompleteRequest();
|
CompleteRequest();
|
||||||
|
@ -48,5 +116,76 @@ namespace Bit.iOS.Extension
|
||||||
|
|
||||||
Context.ExtContext.CompleteRequest(returningItems, null);
|
Context.ExtContext.CompleteRequest(returningItems, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TableSource : UITableViewSource
|
||||||
|
{
|
||||||
|
private LockPasswordViewController _controller;
|
||||||
|
|
||||||
|
public TableSource(LockPasswordViewController controller)
|
||||||
|
{
|
||||||
|
_controller = controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
|
||||||
|
{
|
||||||
|
if(indexPath.Section == 0)
|
||||||
|
{
|
||||||
|
if(indexPath.Row == 0)
|
||||||
|
{
|
||||||
|
return _controller.MasterPasswordCell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new UITableViewCell();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override nfloat GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
|
||||||
|
{
|
||||||
|
return UITableView.AutomaticDimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override nint NumberOfSections(UITableView tableView)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override nint RowsInSection(UITableView tableview, nint section)
|
||||||
|
{
|
||||||
|
if(section == 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override nfloat GetHeightForHeader(UITableView tableView, nint section)
|
||||||
|
{
|
||||||
|
return UITableView.AutomaticDimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string TitleForHeader(UITableView tableView, nint section)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
|
||||||
|
{
|
||||||
|
tableView.DeselectRow(indexPath, true);
|
||||||
|
tableView.EndEditing(true);
|
||||||
|
|
||||||
|
var cell = tableView.CellAt(indexPath);
|
||||||
|
if(cell == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectableCell = cell as ISelectable;
|
||||||
|
if(selectableCell != null)
|
||||||
|
{
|
||||||
|
selectableCell.Select();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,16 +18,38 @@ namespace Bit.iOS.Extension
|
||||||
[GeneratedCode ("iOS Designer", "1.0")]
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
UIKit.UIBarButtonItem CancelButton { get; set; }
|
UIKit.UIBarButtonItem CancelButton { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UITableView MainTableView { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UIBarButtonItem SubmitButton { get; set; }
|
||||||
|
|
||||||
[Action ("CancelButton_Activated:")]
|
[Action ("CancelButton_Activated:")]
|
||||||
[GeneratedCode ("iOS Designer", "1.0")]
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
partial void CancelButton_Activated (UIKit.UIBarButtonItem sender);
|
partial void CancelButton_Activated (UIKit.UIBarButtonItem sender);
|
||||||
|
|
||||||
|
[Action ("SubmitButton_Activated:")]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
partial void SubmitButton_Activated (UIKit.UIBarButtonItem sender);
|
||||||
|
|
||||||
void ReleaseDesignerOutlets ()
|
void ReleaseDesignerOutlets ()
|
||||||
{
|
{
|
||||||
if (CancelButton != null) {
|
if (CancelButton != null) {
|
||||||
CancelButton.Dispose ();
|
CancelButton.Dispose ();
|
||||||
CancelButton = null;
|
CancelButton = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (MainTableView != null) {
|
||||||
|
MainTableView.Dispose ();
|
||||||
|
MainTableView = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SubmitButton != null) {
|
||||||
|
SubmitButton.Dispose ();
|
||||||
|
SubmitButton = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -424,34 +424,6 @@
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="1886" y="1931"/>
|
<point key="canvasLocation" x="1886" y="1931"/>
|
||||||
</scene>
|
</scene>
|
||||||
<scene sceneID="6841">
|
|
||||||
<objects>
|
|
||||||
<viewController id="6842" sceneMemberID="viewController" customClass="LockPasswordViewController">
|
|
||||||
<layoutGuides>
|
|
||||||
<viewControllerLayoutGuide type="top" id="6852"/>
|
|
||||||
<viewControllerLayoutGuide type="bottom" id="6850"/>
|
|
||||||
</layoutGuides>
|
|
||||||
<view key="view" contentMode="scaleToFill" id="6845">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
|
||||||
<subviews/>
|
|
||||||
</view>
|
|
||||||
<navigationItem key="navigationItem" title="Verify Master Password" id="6843">
|
|
||||||
<barButtonItem key="leftBarButtonItem" id="6844" title="Cancel">
|
|
||||||
<connections>
|
|
||||||
<action selector="CancelButton_Activated:" destination="6842" id="7331"/>
|
|
||||||
</connections>
|
|
||||||
</barButtonItem>
|
|
||||||
</navigationItem>
|
|
||||||
<connections>
|
|
||||||
<outlet property="CancelButton" destination="6844" id="name-outlet-6844"/>
|
|
||||||
</connections>
|
|
||||||
</viewController>
|
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="6853" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
|
||||||
</objects>
|
|
||||||
<point key="canvasLocation" x="2653" y="2664"/>
|
|
||||||
</scene>
|
|
||||||
<scene sceneID="6854">
|
<scene sceneID="6854">
|
||||||
<objects>
|
<objects>
|
||||||
<navigationController definesPresentationContext="YES" id="6855" sceneMemberID="viewController">
|
<navigationController definesPresentationContext="YES" id="6855" sceneMemberID="viewController">
|
||||||
|
@ -460,13 +432,47 @@
|
||||||
<rect key="frame" x="0.0" y="20" width="600" height="44"/>
|
<rect key="frame" x="0.0" y="20" width="600" height="44"/>
|
||||||
</navigationBar>
|
</navigationBar>
|
||||||
<connections>
|
<connections>
|
||||||
<segue destination="6842" kind="relationship" relationship="rootViewController" id="6856"/>
|
<segue id="8266" destination="7413" kind="relationship" relationship="rootViewController"/>
|
||||||
</connections>
|
</connections>
|
||||||
</navigationController>
|
</navigationController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="6858" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="6858" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="1878" y="2669"/>
|
<point key="canvasLocation" x="1878" y="2669"/>
|
||||||
</scene>
|
</scene>
|
||||||
|
<scene sceneID="7412">
|
||||||
|
<objects>
|
||||||
|
<tableViewController id="7413" sceneMemberID="viewController" customClass="LockPasswordViewController">
|
||||||
|
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="7414">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
<connections>
|
||||||
|
<outlet property="dataSource" destination="7413" id="7415"/>
|
||||||
|
<outlet property="delegate" destination="7413" id="7416"/>
|
||||||
|
</connections>
|
||||||
|
</tableView>
|
||||||
|
<navigationItem title="Verify Master Password" id="8265" key="navigationItem">
|
||||||
|
<barButtonItem key="leftBarButtonItem" title="Cancel" id="8268">
|
||||||
|
<connections>
|
||||||
|
<action selector="CancelButton_Activated:" destination="7413" id="8287"/>
|
||||||
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
<barButtonItem key="rightBarButtonItem" title="Submit" id="8269">
|
||||||
|
<connections>
|
||||||
|
<action selector="SubmitButton_Activated:" destination="7413" id="8288"/>
|
||||||
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
</navigationItem>
|
||||||
|
<connections>
|
||||||
|
<outlet property="SubmitButton" destination="8269" id="name-outlet-8269"/>
|
||||||
|
<outlet property="CancelButton" destination="8268" id="name-outlet-8268"/>
|
||||||
|
<outlet property="MainTableView" destination="7414" id="name-outlet-7414"/>
|
||||||
|
</connections>
|
||||||
|
</tableViewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="7419" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="2532" y="2675"/>
|
||||||
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="logo.png" width="282" height="44"/>
|
<image name="logo.png" width="282" height="44"/>
|
||||||
|
|
Loading…
Reference in a new issue