basic autofill

This commit is contained in:
kspearrin 2018-09-20 16:44:06 -04:00
parent 0baa07daa2
commit 6904ea118b
13 changed files with 1035 additions and 54 deletions

View File

@ -41,6 +41,11 @@ namespace Bit.Android.Services
TrackEvent("AutofillService", eventName, label);
}
public void TrackExtensionEvent(string eventName, string label = null)
{
TrackExtensionEvent(eventName, label);
}
public void TrackEvent(string category, string eventName, string label = null)
{
var builder = new HitBuilders.EventBuilder();

View File

@ -7,6 +7,7 @@ namespace Bit.App.Abstractions
void TrackPage(string pageName);
void TrackAppEvent(string eventName, string label = null);
void TrackExtensionEvent(string eventName, string label = null);
void TrackAutofillExtensionEvent(string eventName, string label = null);
void TrackEvent(string category, string eventName, string label = null);
void TrackException(string message, bool fatal);
void Dispatch(Action completionHandler = null);

View File

@ -13,6 +13,10 @@ namespace Bit.Android.Services
{
}
public void TrackAutofillExtensionEvent(string eventName, string label = null)
{
}
public void TrackEvent(string category, string eventName, string label = null)
{
}

View File

@ -4,13 +4,16 @@ using Bit.App.Repositories;
using Bit.App.Resources;
using Bit.App.Services;
using Bit.iOS.Autofill.Models;
using Bit.iOS.Core;
using Bit.iOS.Core.Services;
using Bit.iOS.Core.Utilities;
using Foundation;
using Plugin.Connectivity;
using Plugin.Fingerprint;
using Plugin.Settings.Abstractions;
using SimpleInjector;
using System;
using System.Diagnostics;
using UIKit;
using XLabs.Ioc;
using XLabs.Ioc.SimpleInjectorContainer;
@ -19,7 +22,9 @@ namespace Bit.iOS.Autofill
{
public partial class CredentialProviderViewController : ASCredentialProviderViewController
{
private Context _context = new Context();
private Context _context = new Context();
private bool _setupHockeyApp = false;
private IGoogleAnalyticsService _googleAnalyticsService;
public CredentialProviderViewController (IntPtr handle) : base (handle)
{
@ -31,14 +36,42 @@ namespace Bit.iOS.Autofill
SetCulture();
base.ViewDidLoad();
_context.ExtContext = ExtensionContext;
// TODO: HockeyApp
_googleAnalyticsService = Resolver.Resolve<IGoogleAnalyticsService>();
if (!_setupHockeyApp)
{
var appIdService = Resolver.Resolve<IAppIdService>();
var crashManagerDelegate = new HockeyAppCrashManagerDelegate(appIdService, Resolver.Resolve<IAuthService>());
var manager = HockeyApp.iOS.BITHockeyManager.SharedHockeyManager;
manager.Configure("51f96ae568ba45f699a18ad9f63046c3", crashManagerDelegate);
manager.CrashManager.CrashManagerStatus = HockeyApp.iOS.BITCrashManagerStatus.AutoSend;
manager.UserId = appIdService.AppId;
manager.StartManager();
manager.Authenticator.AuthenticateInstallation();
_setupHockeyApp = true;
}
}
public override void PrepareCredentialList(ASCredentialServiceIdentifier[] serviceIdentifiers)
{
System.Diagnostics.Debug.WriteLine("AUTOFILL Got identifiers " + serviceIdentifiers.Length);
_context.ServiceIdentifiers = serviceIdentifiers;
_context.UrlString = serviceIdentifiers[0].Identifier;
base.PrepareCredentialList(serviceIdentifiers);
var authService = Resolver.Resolve<IAuthService>();
if (!authService.IsAuthenticated)
{
var alert = Dialogs.CreateAlert(null, AppResources.MustLogInMainApp, AppResources.Ok, (a) =>
{
CompleteRequest();
});
PresentViewController(alert, true, null);
return;
}
PerformSegue("loginListSegue", this);
}
public override void ProvideCredentialWithoutUserInteraction(ASPasswordCredentialIdentity credentialIdentity)
@ -54,6 +87,55 @@ namespace Bit.iOS.Autofill
public override void PrepareInterfaceForExtensionConfiguration()
{
base.PrepareInterfaceForExtensionConfiguration();
}
public void CompleteRequest(string username = null, string password = null, string totp = null)
{
if(string.IsNullOrWhiteSpace(username) && string.IsNullOrWhiteSpace(password)) {
_googleAnalyticsService.TrackAutofillExtensionEvent("Canceled");
var err = new NSError(new NSString("ASExtensionErrorDomain"),
Convert.ToInt32(ASExtensionErrorCode.UserCanceled), null);
_googleAnalyticsService.Dispatch(() =>
{
NSRunLoop.Main.BeginInvokeOnMainThread(() =>
{
ExtensionContext.CancelRequest(err);
});
});
return;
}
if(!string.IsNullOrWhiteSpace(totp))
{
UIPasteboard.General.String = totp;
}
_googleAnalyticsService.TrackAutofillExtensionEvent("AutoFilled");
var cred = new ASPasswordCredential(username, password);
_googleAnalyticsService.Dispatch(() =>
{
NSRunLoop.Main.BeginInvokeOnMainThread(() =>
{
ExtensionContext.CompleteRequest(cred, null);
});
});
}
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
{
var navController = segue.DestinationViewController as UINavigationController;
if (navController != null)
{
var listLoginController = navController.TopViewController as LoginListViewController;
if (listLoginController != null)
{
listLoginController.Context = _context;
listLoginController.CPViewController = this;
}
}
}
private void SetIoc()

View File

@ -14,14 +14,6 @@ namespace Bit.iOS.Autofill
[Register ("CredentialProviderViewController")]
partial class CredentialProviderViewController
{
[Action ("cancel:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void cancel (UIKit.UIBarButtonItem sender);
[Action ("passwordSelected:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void passwordSelected (UIKit.UIButton sender);
void ReleaseDesignerOutlets ()
{
}

View File

@ -0,0 +1,273 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Bit.App.Abstractions;
using Bit.iOS.Autofill.Models;
using Foundation;
using UIKit;
using XLabs.Ioc;
using Plugin.Settings.Abstractions;
using Bit.iOS.Core.Utilities;
using System.Threading.Tasks;
using Bit.iOS.Core;
using MobileCoreServices;
using Bit.iOS.Core.Controllers;
using Bit.App.Resources;
using Bit.App.Models;
using Bit.App.Utilities;
using Bit.iOS.Core.Models;
namespace Bit.iOS.Autofill
{
public partial class LoginListViewController : ExtendedUITableViewController
{
public LoginListViewController(IntPtr handle) : base(handle)
{ }
public Context Context { get; set; }
public CredentialProviderViewController CPViewController { get; set; }
public override void ViewWillAppear(bool animated)
{
UINavigationBar.Appearance.ShadowImage = new UIImage();
UINavigationBar.Appearance.SetBackgroundImage(new UIImage(), UIBarMetrics.Default);
base.ViewWillAppear(animated);
}
public async override void ViewDidLoad()
{
base.ViewDidLoad();
NavItem.Title = AppResources.Items;
CancelBarButton.Title = AppResources.Cancel;
TableView.RowHeight = UITableView.AutomaticDimension;
TableView.EstimatedRowHeight = 44;
TableView.Source = new TableSource(this);
await ((TableSource)TableView.Source).LoadItemsAsync();
}
partial void CancelBarButton_Activated(UIBarButtonItem sender)
{
CPViewController.CompleteRequest(null, null, null);
}
partial void AddBarButton_Activated(UIBarButtonItem sender)
{
PerformSegue("loginAddSegue", this);
}
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
{
var navController = segue.DestinationViewController as UINavigationController;
if(navController != null)
{
/*
var addLoginController = navController.TopViewController as LoginAddViewController;
if(addLoginController != null)
{
addLoginController.Context = Context;
addLoginController.LoginListController = this;
}
*/
}
}
public void DismissModal()
{
DismissViewController(true, async () =>
{
await ((TableSource)TableView.Source).LoadItemsAsync();
TableView.ReloadData();
});
}
public class TableSource : UITableViewSource
{
private const string CellIdentifier = "TableCell";
private IEnumerable<CipherViewModel> _tableItems = new List<CipherViewModel>();
private Context _context;
private LoginListViewController _controller;
private ICipherService _cipherService;
private ISettings _settings;
private bool _accessPremium;
public TableSource(LoginListViewController controller)
{
_context = controller.Context;
_controller = controller;
_accessPremium = Helpers.CanAccessPremium();
_cipherService = Resolver.Resolve<ICipherService>();
_settings = Resolver.Resolve<ISettings>();
}
public async Task LoadItemsAsync()
{
var combinedLogins = new List<Cipher>();
var logins = await _cipherService.GetAllAsync(_context.UrlString);
if(logins?.Item1 != null)
{
combinedLogins.AddRange(logins.Item1);
}
if(logins?.Item2 != null)
{
combinedLogins.AddRange(logins.Item2);
}
_tableItems = combinedLogins.Select(s => new CipherViewModel(s))
.OrderBy(s => s.Name)
.ThenBy(s => s.Username)
.ToList() ?? new List<CipherViewModel>();
}
public IEnumerable<CipherViewModel> TableItems { get; set; }
public override nint RowsInSection(UITableView tableview, nint section)
{
return _tableItems == null || _tableItems.Count() == 0 ? 1 : _tableItems.Count();
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
if(_tableItems == null || _tableItems.Count() == 0)
{
var noDataCell = new UITableViewCell(UITableViewCellStyle.Default, "NoDataCell");
noDataCell.TextLabel.Text = AppResources.NoItemsTap;
noDataCell.TextLabel.TextAlignment = UITextAlignment.Center;
noDataCell.TextLabel.LineBreakMode = UILineBreakMode.WordWrap;
noDataCell.TextLabel.Lines = 0;
return noDataCell;
}
var cell = tableView.DequeueReusableCell(CellIdentifier);
// if there are no cells to reuse, create a new one
if(cell == null)
{
Debug.WriteLine("BW Log, Make new cell for list.");
cell = new UITableViewCell(UITableViewCellStyle.Subtitle, CellIdentifier);
cell.DetailTextLabel.TextColor = cell.DetailTextLabel.TintColor = new UIColor(red: 0.47f, green: 0.47f, blue: 0.47f, alpha: 1.0f);
}
return cell;
}
public override void WillDisplay(UITableView tableView, UITableViewCell cell, NSIndexPath indexPath)
{
if(_tableItems == null || _tableItems.Count() == 0 || cell == null)
{
return;
}
var item = _tableItems.ElementAt(indexPath.Row);
cell.TextLabel.Text = item.Name;
cell.DetailTextLabel.Text = item.Username;
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
tableView.DeselectRow(indexPath, true);
tableView.EndEditing(true);
if(_tableItems == null || _tableItems.Count() == 0)
{
_controller.PerformSegue("loginAddSegue", this);
return;
}
var item = _tableItems.ElementAt(indexPath.Row);
if(item == null)
{
_controller.CPViewController.CompleteRequest(null, null, null);
return;
}
if(!string.IsNullOrWhiteSpace(item.Password))
{
string totp = null;
if(!_settings.GetValueOrDefault(App.Constants.SettingDisableTotpCopy, false))
{
totp = GetTotp(item);
}
_controller.CPViewController.CompleteRequest(item.Username, item.Password, totp);
}
else if(!string.IsNullOrWhiteSpace(item.Username) || !string.IsNullOrWhiteSpace(item.Password) ||
!string.IsNullOrWhiteSpace(item.Totp.Value))
{
var sheet = Dialogs.CreateActionSheet(item.Name, _controller);
if(!string.IsNullOrWhiteSpace(item.Username))
{
sheet.AddAction(UIAlertAction.Create(AppResources.CopyUsername, UIAlertActionStyle.Default, a =>
{
UIPasteboard clipboard = UIPasteboard.General;
clipboard.String = item.Username;
var alert = Dialogs.CreateMessageAlert(AppResources.CopyUsername);
_controller.PresentViewController(alert, true, () =>
{
_controller.DismissViewController(true, null);
});
}));
}
if(!string.IsNullOrWhiteSpace(item.Password))
{
sheet.AddAction(UIAlertAction.Create(AppResources.CopyPassword, UIAlertActionStyle.Default, a =>
{
UIPasteboard clipboard = UIPasteboard.General;
clipboard.String = item.Password;
var alert = Dialogs.CreateMessageAlert(AppResources.CopiedPassword);
_controller.PresentViewController(alert, true, () =>
{
_controller.DismissViewController(true, null);
});
}));
}
if(!string.IsNullOrWhiteSpace(item.Totp.Value))
{
sheet.AddAction(UIAlertAction.Create(AppResources.CopyTotp, UIAlertActionStyle.Default, a =>
{
var totp = GetTotp(item);
if(string.IsNullOrWhiteSpace(totp))
{
return;
}
UIPasteboard clipboard = UIPasteboard.General;
clipboard.String = totp;
var alert = Dialogs.CreateMessageAlert(AppResources.CopiedTotp);
_controller.PresentViewController(alert, true, () =>
{
_controller.DismissViewController(true, null);
});
}));
}
sheet.AddAction(UIAlertAction.Create(AppResources.Cancel, UIAlertActionStyle.Cancel, null));
_controller.PresentViewController(sheet, true, null);
}
else
{
var alert = Dialogs.CreateAlert(null, AppResources.NoUsernamePasswordConfigured, AppResources.Ok);
_controller.PresentViewController(alert, true, null);
}
}
private string GetTotp(CipherViewModel item)
{
string totp = null;
if(_accessPremium)
{
if(item != null && !string.IsNullOrWhiteSpace(item.Totp.Value))
{
totp = Crypto.Totp(item.Totp.Value);
}
}
return totp;
}
}
}
}

View File

@ -0,0 +1,55 @@
// WARNING
//
// This file has been generated automatically by Visual Studio from the outlets and
// actions declared in your storyboard file.
// Manual changes to this file will not be maintained.
//
using Foundation;
using System;
using System.CodeDom.Compiler;
using UIKit;
namespace Bit.iOS.Autofill
{
[Register ("LoginListViewController")]
partial class LoginListViewController
{
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIBarButtonItem AddBarButton { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UIBarButtonItem CancelBarButton { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UIKit.UINavigationItem NavItem { get; set; }
[Action ("AddBarButton_Activated:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void AddBarButton_Activated (UIKit.UIBarButtonItem sender);
[Action ("CancelBarButton_Activated:")]
[GeneratedCode ("iOS Designer", "1.0")]
partial void CancelBarButton_Activated (UIKit.UIBarButtonItem sender);
void ReleaseDesignerOutlets ()
{
if (AddBarButton != null) {
AddBarButton.Dispose ();
AddBarButton = null;
}
if (CancelBarButton != null) {
CancelBarButton.Dispose ();
CancelBarButton = null;
}
if (NavItem != null) {
NavItem.Dispose ();
NavItem = null;
}
}
}
}

View File

@ -1,57 +1,612 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14092" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Xki-Si-B7m">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="43">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14081.1"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14283.14"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Credential Provider View Controller-->
<scene sceneID="Uma-9u-xWV">
<!--Loading View Controller-->
<scene sceneID="42">
<objects>
<viewController id="Xki-Si-B7m" customClass="CredentialProviderViewController" customModuleProvider="" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="BuU-Ak-iZz">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<viewController id="43" customClass="CredentialProviderViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="40"/>
<viewControllerLayoutGuide type="bottom" id="41"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="44">
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3wq-kG-lGu">
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
<items>
<navigationItem id="cbj-pk-SYj">
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="bEZ-MG-jDy">
<connections>
<action selector="cancel:" destination="Xki-Si-B7m" id="6ap-3Q-iEX"/>
</connections>
</barButtonItem>
</navigationItem>
</items>
</navigationBar>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="a7v-ug-QzG">
<rect key="frame" x="87.5" y="327" width="199" height="33"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<state key="normal" title="Return Example Password"/>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="logo.png" translatesAutoresizingMaskIntoConstraints="NO" id="1713">
<rect key="frame" x="66" y="316" width="282" height="44"/>
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="1713" firstAttribute="centerY" secondItem="44" secondAttribute="centerY" constant="-30" id="1763"/>
<constraint firstItem="1713" firstAttribute="centerX" secondItem="44" secondAttribute="centerX" id="1764"/>
</constraints>
</view>
<connections>
<segue destination="oCZ-GQ-aOK" kind="show" identifier="loginListSegue" id="1679"/>
<segue destination="6512" kind="presentation" identifier="lockFingerprintSegue" id="8446"/>
<segue destination="6815" kind="presentation" identifier="lockPinSegue" id="8924"/>
<segue destination="6855" kind="presentation" identifier="lockPasswordSegue" id="9874"/>
<segue destination="1845" kind="presentation" identifier="newLoginSegue" modalPresentationStyle="fullScreen" modalTransitionStyle="coverVertical" id="10498"/>
<segue destination="10580" kind="presentation" identifier="setupSegue" modalTransitionStyle="coverVertical" id="11089"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="45" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-374" y="560"/>
</scene>
<!--Navigation Controller-->
<!--Navigation Controller-->
<scene sceneID="RvZ-Bc-vCe">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="oCZ-GQ-aOK" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="8A5-AR-QHS">
<rect key="frame" x="0.0" y="20" width="414" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<color key="tintColor" red="0.0" green="0.52549019607843139" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="barTintColor" red="0.23529411764705882" green="0.55294117647058827" blue="0.73725490196078436" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<textAttributes key="titleTextAttributes">
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</textAttributes>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="2304" kind="relationship" relationship="rootViewController" id="4562"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Kkn-u3-rq1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="399" y="561"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="1844">
<objects>
<navigationController definesPresentationContext="YES" id="1845" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="1848">
<rect key="frame" x="0.0" y="20" width="414" height="50"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<color key="barTintColor" red="0.23529411764705882" green="0.55294117647058827" blue="0.73725490196078436" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<textAttributes key="titleTextAttributes">
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</textAttributes>
</navigationBar>
<connections>
<segue destination="2087" kind="relationship" relationship="rootViewController" id="2253"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="1849" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1932" y="-270"/>
</scene>
<!--Add Login-->
<scene sceneID="2086">
<objects>
<tableViewController id="2087" customClass="LoginAddViewController" sceneMemberID="viewController">
<tableView key="view" opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" allowsSelection="NO" rowHeight="50" sectionHeaderHeight="22" sectionFooterHeight="22" id="2088">
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="sectionIndexBackgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<sections/>
<connections>
<outlet property="dataSource" destination="2087" id="2089"/>
<outlet property="delegate" destination="2087" id="2090"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Add Login" id="2252">
<barButtonItem key="leftBarButtonItem" title="Cancel" id="3747">
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="CancelBarButton_Activated:" destination="2087" id="3751"/>
</connections>
</barButtonItem>
<barButtonItem key="rightBarButtonItem" title="Save" id="3748">
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="SaveBarButton_Activated:" destination="2087" id="3752"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="CancelBarButton" destination="3747" id="name-outlet-3747"/>
<outlet property="NavItem" destination="2252" id="name-outlet-2252"/>
<outlet property="SaveBarButton" destination="3748" id="name-outlet-3748"/>
<segue destination="4574" kind="show" identifier="passwordGeneratorSegue" id="4805"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="2093" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2632" y="-276"/>
</scene>
<!--Logins-->
<scene sceneID="2303">
<objects>
<tableViewController id="2304" customClass="LoginListViewController" sceneMemberID="viewController">
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="2305">
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<prototypes>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="3763" detailTextLabel="3764" rowHeight="44" style="IBUITableViewCellStyleSubtitle" id="3761">
<rect key="frame" x="0.0" y="22" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="3761" id="3762">
<rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="3763">
<rect key="frame" x="20" y="4" width="35" height="21.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Subtitle" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="3764">
<rect key="frame" x="20" y="25.5" width="44" height="14.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</prototypes>
<connections>
<outlet property="dataSource" destination="2304" id="2306"/>
<outlet property="delegate" destination="2304" id="2307"/>
</connections>
</tableView>
<toolbarItems/>
<navigationItem key="navigationItem" title="Logins" id="3734">
<barButtonItem key="leftBarButtonItem" title="Cancel" id="3735">
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="CancelBarButton_Activated:" destination="2304" id="3750"/>
</connections>
</barButtonItem>
<barButtonItem key="rightBarButtonItem" systemItem="add" id="3736">
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="AddBarButton_Activated:" destination="2304" id="3749"/>
</connections>
</barButtonItem>
</navigationItem>
<simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
<connections>
<outlet property="AddBarButton" destination="3736" id="name-outlet-3736"/>
<outlet property="CancelBarButton" destination="3735" id="name-outlet-3735"/>
<outlet property="NavItem" destination="3734" id="name-outlet-3734"/>
<segue destination="1845" kind="presentation" identifier="loginAddSegue" modalPresentationStyle="fullScreen" modalTransitionStyle="coverVertical" id="3731"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="2310" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1157" y="566"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="4573">
<objects>
<navigationController definesPresentationContext="YES" id="4574" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="4577">
<rect key="frame" x="0.0" y="20" width="414" height="50"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<color key="tintColor" red="0.0" green="0.52549019607843139" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="barTintColor" red="0.23529411764705882" green="0.55294117647058827" blue="0.73725490196078436" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<textAttributes key="titleTextAttributes">
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</textAttributes>
</navigationBar>
<connections>
<segue destination="4576" kind="relationship" relationship="rootViewController" id="4575"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="4578" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3369" y="-276"/>
</scene>
<!--Generate Password-->
<scene sceneID="4579">
<objects>
<viewController id="4576" customClass="PasswordGeneratorViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="4571"/>
<viewControllerLayoutGuide type="bottom" id="4572"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="4930">
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<containerView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4933">
<rect key="frame" x="0.0" y="160.5" width="414" height="575.5"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="passwordSelected:" destination="Xki-Si-B7m" eventType="touchUpInside" id="ODd-lr-mud"/>
<segue destination="4912" kind="embed" id="6480"/>
</connections>
</containerView>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Label" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="4940">
<rect key="frame" x="15" y="105" width="384" height="20.5"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="4933" secondAttribute="trailing" id="6484"/>
<constraint firstItem="4933" firstAttribute="top" secondItem="4940" secondAttribute="bottom" constant="35" id="6485"/>
<constraint firstItem="4933" firstAttribute="leading" secondItem="4930" secondAttribute="leading" id="6486"/>
<constraint firstItem="4940" firstAttribute="leading" secondItem="4930" secondAttribute="leading" constant="15" id="6487"/>
<constraint firstItem="4940" firstAttribute="top" secondItem="4571" secondAttribute="bottom" constant="35" id="6488"/>
<constraint firstAttribute="trailing" secondItem="4940" secondAttribute="trailing" constant="15" id="6489"/>
<constraint firstItem="4572" firstAttribute="top" secondItem="4933" secondAttribute="bottom" id="6490"/>
</constraints>
</view>
<navigationItem key="navigationItem" title="Generate Password" id="4580">
<barButtonItem key="leftBarButtonItem" title="Cancel" id="4807">
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="CancelBarButton_Activated:" destination="4576" id="4887"/>
</connections>
</barButtonItem>
<barButtonItem key="rightBarButtonItem" title="Select" id="4808">
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<action selector="SelectBarButton_Activated:" destination="4576" id="4810"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="BaseView" destination="4930" id="name-outlet-4930"/>
<outlet property="CancelBarButton" destination="4807" id="name-outlet-4807"/>
<outlet property="NavItem" destination="4580" id="name-outlet-4580"/>
<outlet property="OptionsContainer" destination="4933" id="name-outlet-4933"/>
<outlet property="PasswordLabel" destination="4940" id="name-outlet-4940"/>
<outlet property="SelectBarButton" destination="4808" id="name-outlet-4808"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="4582" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="4045" y="-272"/>
</scene>
<!--Table View Controller-->
<scene sceneID="4911">
<objects>
<tableViewController id="4912" sceneMemberID="viewController">
<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="4913">
<rect key="frame" x="0.0" y="0.0" width="414" height="575.5"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="dataSource" destination="4912" id="4914"/>
<outlet property="delegate" destination="4912" id="4915"/>
</connections>
</tableView>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="4918" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="4708" y="-194"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="6511">
<objects>
<navigationController definesPresentationContext="YES" id="6512" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="6515">
<rect key="frame" x="0.0" y="20" width="414" height="50"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="barTintColor" red="0.23529411764705882" green="0.55294117647058827" blue="0.73725490196078436" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<textAttributes key="titleTextAttributes">
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</textAttributes>
</navigationBar>
<connections>
<segue destination="6514" kind="relationship" relationship="rootViewController" id="6513"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="6516" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="296" y="1394"/>
</scene>
<!--Verify Fingerprint-->
<scene sceneID="6517">
<objects>
<viewController id="6514" customClass="LockFingerprintViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="6509"/>
<viewControllerLayoutGuide type="bottom" id="6510"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="6519">
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6777">
<rect key="frame" x="30" y="655" width="354" height="41"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<inset key="contentEdgeInsets" minX="0.0" minY="10" maxX="0.0" maxY="10"/>
<state key="normal" title="Use Fingerprint To Unlock">
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
</button>
<button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="11144">
<rect key="frame" x="254.5" y="234" width="91" height="92"/>
<color key="tintColor" red="0.46666666666666667" green="0.46666666666666667" blue="0.46666666666666667" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<state key="normal" image="fingerprint.png">
<color key="titleColor" red="0.46666666666666667" green="0.46666666666666667" blue="0.46666666666666667" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="titleShadowColor" red="0.5" green="0.5" blue="0.5" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</state>
<connections>
<action selector="FingerprintButton_TouchUpInside:" destination="6514" eventType="touchUpInside" id="11149"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="Ky8-vK-JVj" firstAttribute="top" secondItem="3wq-kG-lGu" secondAttribute="top" id="BIN-jb-uNd"/>
<constraint firstItem="3wq-kG-lGu" firstAttribute="width" secondItem="BuU-Ak-iZz" secondAttribute="width" id="UkD-v4-BcH"/>
<constraint firstItem="a7v-ug-QzG" firstAttribute="centerY" secondItem="Ky8-vK-JVj" secondAttribute="centerY" id="fAC-0v-NFE"/>
<constraint firstItem="a7v-ug-QzG" firstAttribute="centerX" secondItem="3wq-kG-lGu" secondAttribute="centerX" id="io1-ZS-gwn"/>
<constraint firstItem="3wq-kG-lGu" firstAttribute="centerX" secondItem="BuU-Ak-iZz" secondAttribute="centerX" id="rtV-5c-0bl"/>
<constraint firstAttribute="trailing" secondItem="6777" secondAttribute="trailing" constant="30" id="6783"/>
<constraint firstItem="6777" firstAttribute="leading" secondItem="6519" secondAttribute="leading" constant="30" id="6784"/>
<constraint firstItem="6510" firstAttribute="top" secondItem="6777" secondAttribute="bottom" constant="40" id="6785"/>
<constraint firstItem="6777" firstAttribute="centerX" secondItem="6519" secondAttribute="centerX" id="6786"/>
<constraint firstAttribute="centerY" secondItem="11144" secondAttribute="centerY" constant="60" id="11147"/>
<constraint firstItem="11144" firstAttribute="centerX" secondItem="6519" secondAttribute="centerX" id="11148"/>
</constraints>
<viewLayoutGuide key="safeArea" id="Ky8-vK-JVj"/>
</view>
<navigationItem key="navigationItem" title="Verify Fingerprint" id="6518">
<barButtonItem key="leftBarButtonItem" title="Cancel" id="6800">
<connections>
<action selector="CancelButton_Activated:" destination="6514" id="7293"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="CancelButton" destination="6800" id="name-outlet-6800"/>
<outlet property="FingerprintButton" destination="11144" id="name-outlet-11144"/>
<outlet property="NavItem" destination="6518" id="name-outlet-6518"/>
<outlet property="UseButton" destination="6777" id="name-outlet-6777"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="RwB-HB-TSk" userLabel="First Responder" sceneMemberID="firstResponder"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="6520" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="983" y="1390"/>
</scene>
<!--Verify PIN-->
<scene sceneID="6801">
<objects>
<viewController id="6802" customClass="LockPinViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="6812"/>
<viewControllerLayoutGuide type="bottom" id="6810"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="6805">
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" misplaced="YES" text="- - - -" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="7373">
<rect key="frame" x="30" y="104" width="540" height="17"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" name="Menlo-Regular" family="Menlo" pointSize="40"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="7350">
<rect key="frame" x="30" y="79" width="540" height="77"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<color key="tintColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" name="Menlo-Regular" family="Menlo" pointSize="14"/>
<textInputTraits key="textInputTraits" keyboardType="numberPad"/>
</textField>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Enter your PIN Code." textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="10516">
<rect key="frame" x="30" y="192" width="354" height="20.5"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.3333333432674408" green="0.3333333432674408" blue="0.3333333432674408" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="7350" firstAttribute="leading" secondItem="6805" secondAttribute="leading" constant="30" id="7351"/>
<constraint firstAttribute="trailing" secondItem="7350" secondAttribute="trailing" constant="30" id="7352"/>
<constraint firstItem="7350" firstAttribute="top" secondItem="6812" secondAttribute="bottom" constant="15" id="7353"/>
<constraint firstItem="7373" firstAttribute="leading" secondItem="6805" secondAttribute="leading" constant="30" id="7374"/>
<constraint firstAttribute="trailing" secondItem="7373" secondAttribute="trailing" constant="30" id="7375"/>
<constraint firstItem="7373" firstAttribute="top" secondItem="6812" secondAttribute="bottom" constant="40" id="7376"/>
<constraint firstItem="7350" firstAttribute="height" secondItem="7373" secondAttribute="height" constant="60" id="7394"/>
<constraint firstItem="10516" firstAttribute="leading" secondItem="6805" secondAttribute="leading" constant="30" id="10517"/>
<constraint firstAttribute="trailing" secondItem="10516" secondAttribute="trailing" constant="30" id="10518"/>
<constraint firstItem="10516" firstAttribute="top" secondItem="7350" secondAttribute="bottom" id="10519"/>
</constraints>
</view>
<navigationItem key="navigationItem" title="Verify PIN" id="6803">
<barButtonItem key="leftBarButtonItem" title="Cancel" id="6804">
<connections>
<action selector="CancelButton_Activated:" destination="6802" id="7313"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="CancelButton" destination="6804" id="name-outlet-6804"/>
<outlet property="InstructionLabel" destination="10516" id="name-outlet-10516"/>
<outlet property="NavItem" destination="6803" id="name-outlet-6803"/>
<outlet property="PinLabel" destination="7373" id="name-outlet-7373"/>
<outlet property="PinTextField" destination="7350" id="name-outlet-7350"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="6813" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="975" y="2083"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="6814">
<objects>
<navigationController definesPresentationContext="YES" id="6815" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="6817">
<rect key="frame" x="0.0" y="20" width="414" height="50"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="barTintColor" red="0.23529411764705882" green="0.55294117647058827" blue="0.73725490196078436" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<textAttributes key="titleTextAttributes">
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</textAttributes>
</navigationBar>
<connections>
<segue destination="6802" kind="relationship" relationship="rootViewController" id="6816"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="6818" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="306" y="2083"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="6854">
<objects>
<navigationController definesPresentationContext="YES" id="6855" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="6857">
<rect key="frame" x="0.0" y="20" width="414" height="50"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="barTintColor" red="0.23529411764705882" green="0.55294117647058827" blue="0.73725490196078436" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<textAttributes key="titleTextAttributes">
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</textAttributes>
</navigationBar>
<connections>
<segue destination="7413" kind="relationship" relationship="rootViewController" id="8266"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="6858" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="306" y="2759"/>
</scene>
<!--Verify Master Password-->
<scene sceneID="7412">
<objects>
<tableViewController id="7413" customClass="LockPasswordViewController" sceneMemberID="viewController">
<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="414" height="736"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="dataSource" destination="7413" id="7415"/>
<outlet property="delegate" destination="7413" id="7416"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Verify Master Password" id="8265">
<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="CancelButton" destination="8268" id="name-outlet-8268"/>
<outlet property="MainTableView" destination="7414" id="name-outlet-7414"/>
<outlet property="NavItem" destination="8265" id="name-outlet-8265"/>
<outlet property="SubmitButton" destination="8269" id="name-outlet-8269"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="7419" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="977" y="2775"/>
</scene>
<!--Setup View Controller-->
<scene sceneID="10573">
<objects>
<viewController id="10570" customClass="SetupViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="10565"/>
<viewControllerLayoutGuide type="bottom" id="10566"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="10575">
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Extension Activated!" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="11092">
<rect key="frame" x="15" y="100" width="384" height="20.5"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" misplaced="YES" textAlignment="center" lineBreakMode="wordWrap" numberOfLines="0" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="11093">
<rect key="frame" x="15" y="134.5" width="570" height="41"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" misplaced="YES" image="ext-icon.png" translatesAutoresizingMaskIntoConstraints="NO" id="11094">
<rect key="frame" x="255" y="205.5" width="90" height="90"/>
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="11092" firstAttribute="leading" secondItem="10575" secondAttribute="leading" constant="15" id="11114"/>
<constraint firstAttribute="trailing" secondItem="11092" secondAttribute="trailing" constant="15" id="11115"/>
<constraint firstItem="11092" firstAttribute="top" secondItem="10565" secondAttribute="bottom" constant="30" id="11116"/>
<constraint firstItem="11093" firstAttribute="leading" secondItem="10575" secondAttribute="leading" constant="15" id="11119"/>
<constraint firstAttribute="trailing" secondItem="11093" secondAttribute="trailing" constant="15" id="11120"/>
<constraint firstItem="11093" firstAttribute="top" secondItem="11092" secondAttribute="bottom" constant="20" id="11121"/>
<constraint firstItem="11094" firstAttribute="centerX" secondItem="10575" secondAttribute="centerX" id="11122"/>
<constraint firstItem="11094" firstAttribute="top" secondItem="11093" secondAttribute="bottom" constant="30" id="11123"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="10574">
<barButtonItem key="leftBarButtonItem" title="Back" id="11091">
<connections>
<action selector="BackButton_Activated:" destination="10570" id="11124"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="ActivatedLabel" destination="11092" id="name-outlet-11092"/>
<outlet property="BackButton" destination="11091" id="name-outlet-11091"/>
<outlet property="DescriptionLabel" destination="11093" id="name-outlet-11093"/>
<outlet property="IconImage" destination="11094" id="name-outlet-11094"/>
<outlet property="NavItem" destination="10574" id="name-outlet-10574"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="10576" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1129" y="-264"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="10579">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="10580" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="10583">
<rect key="frame" x="0.0" y="20" width="414" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="barTintColor" red="0.23529411764705882" green="0.55294117647058827" blue="0.73725490196078436" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<textAttributes key="titleTextAttributes">
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</textAttributes>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="10570" kind="relationship" relationship="rootViewController" id="10939"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="10584" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="362" y="-267"/>
</scene>
</scenes>
</document>
<resources>
<image name="fingerprint.png" width="91" height="92"/>
<image name="logo.png" width="282" height="44"/>
</resources>
</document>

View File

@ -1,9 +1,12 @@
using Foundation;
using AuthenticationServices;
using Foundation;
namespace Bit.iOS.Autofill.Models
{
public class Context
{
public NSExtensionContext ExtContext { get; set; }
public ASCredentialServiceIdentifier[] ServiceIdentifiers { get; set; }
public string UrlString { get; set; }
}
}

View File

@ -214,6 +214,10 @@
<Compile Include="CredentialProviderViewController.designer.cs">
<DependentUpon>CredentialProviderViewController.cs</DependentUpon>
</Compile>
<Compile Include="LoginListViewController.cs" />
<Compile Include="LoginListViewController.designer.cs">
<DependentUpon>LoginListViewController.cs</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />

View File

@ -4,7 +4,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
namespace Bit.iOS.Extension.Models
namespace Bit.iOS.Core.Models
{
public class CipherViewModel
{

View File

@ -33,6 +33,11 @@ namespace Bit.iOS.Core.Services
TrackEvent("Extension", eventName, label);
}
public void TrackAutofillExtensionEvent(string eventName, string label = null)
{
TrackEvent("AutofillExtension", eventName, label);
}
public void TrackEvent(string category, string eventName, string label = null)
{
var dict = DictionaryBuilder.CreateEvent(category, eventName, label, null).Build();

View File

@ -38,6 +38,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\" />
<Folder Include="Models\" />
</ItemGroup>
<ItemGroup>
<Compile Include="Constants.cs" />
@ -64,6 +65,7 @@
<Compile Include="Views\SwitchTableViewCell.cs" />
<Compile Include="Views\FormEntryTableViewCell.cs" />
<Compile Include="Views\Toast.cs" />
<Compile Include="Models\CipherViewModel.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\App\App.csproj">