Merge branch 'release/0.2.7'
This commit is contained in:
commit
d635eea136
24 changed files with 609 additions and 472 deletions
|
|
@ -29,7 +29,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
SVProgressHUD.setMinimumSize(CGSize(width: 150, height: 100))
|
||||
passcodeLockPresenter.present()
|
||||
if let shortcutItem = launchOptions?[UIApplicationLaunchOptionsKey.shortcutItem] as? UIApplicationShortcutItem {
|
||||
if shortcutItem.type == "me.mssun.passforios.search" {
|
||||
var searchType = Bundle.main.bundleIdentifier!
|
||||
searchType.append("search")
|
||||
if shortcutItem.type == searchType {
|
||||
self.perform(#selector(postSearchNotification), with: nil, afterDelay: 0.4)
|
||||
}
|
||||
}
|
||||
|
|
@ -42,7 +44,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||
}
|
||||
|
||||
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) {
|
||||
if shortcutItem.type == "me.mssun.passforios.search" {
|
||||
var searchType = Bundle.main.bundleIdentifier!
|
||||
searchType.append("search")
|
||||
if shortcutItem.type == searchType {
|
||||
let tabBarController = self.window!.rootViewController as! UITabBarController
|
||||
tabBarController.selectedIndex = 0
|
||||
let navigationController = tabBarController.selectedViewController as! UINavigationController
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12120" systemVersion="16E195" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="YoR-iB-XAd">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="YoR-iB-XAd">
|
||||
<device id="retina5_5" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
|
|
@ -31,18 +31,18 @@
|
|||
<rect key="frame" x="0.0" y="28" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="bEm-K1-de5" id="kV8-N2-jWc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Eu3-i0-M5v">
|
||||
<rect key="frame" x="15" y="11" width="34" height="21"/>
|
||||
<rect key="frame" x="15" y="11.999999999999998" width="33.333333333333336" height="20.333333333333332"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="jms-aX-6FT">
|
||||
<rect key="frame" x="335" y="11" width="44" height="21"/>
|
||||
<rect key="frame" x="335" y="11.999999999999998" width="44" height="20.333333333333332"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
|
||||
|
|
@ -89,11 +89,11 @@
|
|||
<rect key="frame" x="0.0" y="35" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="55g-T3-9ak" id="dKn-cO-EJa">
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="General" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="dOt-Rj-vWD">
|
||||
<rect key="frame" x="15" y="0.0" width="364" height="43"/>
|
||||
<rect key="frame" x="15" y="0.0" width="364" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
|
|
@ -109,18 +109,18 @@
|
|||
<rect key="frame" x="0.0" y="79" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="2rc-ZW-XKd" id="CpT-zb-QEP">
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Password Repository" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="gWn-ib-STb">
|
||||
<rect key="frame" x="15" y="11" width="161" height="21"/>
|
||||
<rect key="frame" x="15" y="11.999999999999998" width="160.33333333333334" height="20.333333333333332"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Not Set" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Myq-fV-riz">
|
||||
<rect key="frame" x="321" y="11" width="58" height="21"/>
|
||||
<rect key="frame" x="321.33333333333331" y="11.999999999999998" width="57.666666666666664" height="20.333333333333332"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.5568627451" green="0.5568627451" blue="0.57647058819999997" alpha="1" colorSpace="calibratedRGB"/>
|
||||
|
|
@ -136,18 +136,18 @@
|
|||
<rect key="frame" x="0.0" y="123" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="1ze-MS-Xbj" id="W7U-oL-hOh">
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="PGP Key" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="RR9-xr-9ko">
|
||||
<rect key="frame" x="15" y="11" width="66" height="21"/>
|
||||
<rect key="frame" x="15" y="11.999999999999998" width="66" height="20.333333333333332"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Not Set" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="7lc-Vh-G9W">
|
||||
<rect key="frame" x="321" y="11" width="58" height="21"/>
|
||||
<rect key="frame" x="321.33333333333331" y="11.999999999999998" width="57.666666666666664" height="20.333333333333332"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="calibratedRGB"/>
|
||||
|
|
@ -161,21 +161,21 @@
|
|||
<tableViewSection headerTitle="SECURITY" id="Cx7-e4-wCO">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="passcodeTableViewCell" textLabel="RaZ-6t-0CU" detailTextLabel="HXb-ZX-HUv" style="IBUITableViewCellStyleValue1" id="6Y0-mj-qhA">
|
||||
<rect key="frame" x="0.0" y="224" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="223" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="6Y0-mj-qhA" id="qlv-tQ-Xmc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Passcode Lock" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="RaZ-6t-0CU">
|
||||
<rect key="frame" x="15" y="11" width="115" height="21"/>
|
||||
<rect key="frame" x="15" y="11.999999999999998" width="115" height="20.333333333333332"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Off" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="HXb-ZX-HUv">
|
||||
<rect key="frame" x="354" y="11" width="25" height="21"/>
|
||||
<rect key="frame" x="354.66666666666669" y="11.999999999999998" width="24.333333333333332" height="20.333333333333332"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.5568627451" green="0.5568627451" blue="0.57647058819999997" alpha="1" colorSpace="calibratedRGB"/>
|
||||
|
|
@ -185,14 +185,14 @@
|
|||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="touchIDTableViewCell" textLabel="H2E-hP-Gyf" style="IBUITableViewCellStyleDefault" id="wB7-Km-Oel">
|
||||
<rect key="frame" x="0.0" y="268" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="267" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="wB7-Km-Oel" id="m90-X7-DbI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="43"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Touch ID" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="H2E-hP-Gyf">
|
||||
<rect key="frame" x="15" y="0.0" width="384" height="43"/>
|
||||
<rect key="frame" x="15" y="0.0" width="384" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
|
|
@ -206,14 +206,14 @@
|
|||
<tableViewSection id="6U8-ue-MhL">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="advancedTableViewCell" textLabel="MKj-d0-8q3" style="IBUITableViewCellStyleDefault" id="tQN-gu-iRe">
|
||||
<rect key="frame" x="0.0" y="348" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="347" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tQN-gu-iRe" id="Xs0-LN-r43">
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Advanced" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="MKj-d0-8q3">
|
||||
<rect key="frame" x="15" y="0.0" width="364" height="43"/>
|
||||
<rect key="frame" x="15" y="0.0" width="364" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
|
|
@ -230,14 +230,14 @@
|
|||
<tableViewSection id="T7L-rR-R9W">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="aboutTableViewCell" textLabel="oqz-Hr-RAl" imageView="Fgk-EG-6cx" style="IBUITableViewCellStyleDefault" id="osS-xk-WRP">
|
||||
<rect key="frame" x="0.0" y="428" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="427" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="osS-xk-WRP" id="G6j-ij-rNr">
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="About" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="oqz-Hr-RAl">
|
||||
<rect key="frame" x="15" y="0.0" width="364" height="43"/>
|
||||
<rect key="frame" x="15" y="0.0" width="364" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
|
|
@ -288,7 +288,7 @@
|
|||
<rect key="frame" x="0.0" y="28" width="414" height="54"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" tableViewCell="OfB-1N-1Am" id="fh0-au-C6q">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="53"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="54"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" tag="201" contentMode="left" verticalHuggingPriority="251" preservesSuperviewLayoutMargins="YES" text="2017/04/04" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GLC-qL-55P">
|
||||
|
|
@ -348,7 +348,7 @@
|
|||
<tableViewSection headerTitle="Git Repository URL" id="pbe-W6-w4V">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="gitRepositoryURLTabelViewCell" rowHeight="52" id="FRr-pf-aPO">
|
||||
<rect key="frame" x="0.0" y="56" width="414" height="52"/>
|
||||
<rect key="frame" x="0.0" y="55" width="414" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" tableViewCell="FRr-pf-aPO" id="60A-PS-qGe">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
|
||||
|
|
@ -378,7 +378,7 @@
|
|||
<tableViewSection headerTitle="Username" id="fRu-A2-SCk">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" reuseIdentifier="usernameTableVIewCell" rowHeight="52" id="tnj-5U-kMB">
|
||||
<rect key="frame" x="0.0" y="165" width="414" height="52"/>
|
||||
<rect key="frame" x="0.0" y="163" width="414" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" tableViewCell="tnj-5U-kMB" id="f0c-pI-MSJ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
|
||||
|
|
@ -407,7 +407,7 @@
|
|||
<tableViewSection headerTitle="Authentication Method" id="h0N-tI-shZ">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="2" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="KrP-nb-haa">
|
||||
<rect key="frame" x="0.0" y="274" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="271" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KrP-nb-haa" id="1uB-oE-kfI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="43"/>
|
||||
|
|
@ -438,7 +438,7 @@
|
|||
<inset key="separatorInset" minX="62" minY="0.0" maxX="0.0" maxY="0.0"/>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" accessoryType="detailButton" hidesAccessoryWhenEditing="NO" indentationLevel="2" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="Qmt-bo-CuJ">
|
||||
<rect key="frame" x="0.0" y="318" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="315" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Qmt-bo-CuJ" id="p3u-8b-h3U">
|
||||
<rect key="frame" x="0.0" y="0.0" width="367" height="43"/>
|
||||
|
|
@ -519,7 +519,7 @@
|
|||
<rect key="frame" x="0.0" y="35" width="414" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="BYZ-9g-xZy" id="Zfn-rK-sN1">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Public Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dWi-eh-7Eq">
|
||||
|
|
@ -553,7 +553,7 @@
|
|||
<rect key="frame" x="0.0" y="87" width="414" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="vpk-J8-j7t" id="1td-qT-6ts">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Private Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qht-RC-Yeg">
|
||||
|
|
@ -648,7 +648,7 @@
|
|||
</objects>
|
||||
<point key="canvasLocation" x="4954" y="-1027"/>
|
||||
</scene>
|
||||
<!--Scanner-->
|
||||
<!--Scan OTP QR Codes-->
|
||||
<scene sceneID="AuR-rQ-G3V">
|
||||
<objects>
|
||||
<viewController id="A9p-Qb-WmU" customClass="OTPScannerController" customModule="pass" customModuleProvider="target" sceneMemberID="viewController">
|
||||
|
|
@ -678,7 +678,7 @@
|
|||
<constraint firstAttribute="trailingMargin" secondItem="lOI-p4-BGb" secondAttribute="trailing" constant="30" id="qNb-4K-GGl"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" title="Scanner" id="Hlb-5I-bfE">
|
||||
<navigationItem key="navigationItem" title="Scan OTP QR Codes" id="Hlb-5I-bfE">
|
||||
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="KBZ-N2-OGE">
|
||||
<connections>
|
||||
<segue destination="0gD-ix-2NF" kind="unwind" unwindAction="cancelOTPScannerWithSegue:" id="nZe-B6-MNt"/>
|
||||
|
|
@ -912,45 +912,11 @@ Phone Support PIN #: 84719</string>
|
|||
<sections>
|
||||
<tableViewSection id="7c6-yg-Aab">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="publicKeyURLTableViewCell" rowHeight="52" id="Jy1-4S-Lvf">
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="privateKeyURLTableViewCell" rowHeight="52" id="MA5-lE-8dT">
|
||||
<rect key="frame" x="0.0" y="35" width="414" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Jy1-4S-Lvf" id="tJE-ww-okf">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Public Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Oys-xP-ZrB">
|
||||
<rect key="frame" x="15" y="8" width="391" height="15"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
|
||||
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Public Key URL" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="Q1j-Z4-Ae8">
|
||||
<rect key="frame" x="15" y="23" width="391" height="21"/>
|
||||
<nil key="textColor"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="URL" returnKeyType="next"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="hqC-Ic-NMi" id="grO-WT-wLU"/>
|
||||
<outlet property="nextField" destination="4iJ-oB-R1f" id="4oy-bE-Mh5"/>
|
||||
</connections>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="Q1j-Z4-Ae8" firstAttribute="leading" secondItem="Oys-xP-ZrB" secondAttribute="leading" id="1dT-YN-mgp"/>
|
||||
<constraint firstItem="Q1j-Z4-Ae8" firstAttribute="top" secondItem="Oys-xP-ZrB" secondAttribute="bottom" id="28u-dV-vgj"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="Oys-xP-ZrB" secondAttribute="trailing" id="EAa-jy-gKh"/>
|
||||
<constraint firstItem="Oys-xP-ZrB" firstAttribute="leading" secondItem="tJE-ww-okf" secondAttribute="leadingMargin" constant="7" id="Ivp-CN-Uv6"/>
|
||||
<constraint firstAttribute="topMargin" secondItem="Oys-xP-ZrB" secondAttribute="top" id="auJ-Xy-l2r"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="Q1j-Z4-Ae8" secondAttribute="trailing" id="dHQ-mx-Xuw"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="privateKeyURLTableViewCell" rowHeight="52" id="MA5-lE-8dT">
|
||||
<rect key="frame" x="0.0" y="87" width="414" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="MA5-lE-8dT" id="pTv-Wj-psC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Private Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="C2w-dd-roS">
|
||||
|
|
@ -996,7 +962,6 @@ Phone Support PIN #: 84719</string>
|
|||
</navigationItem>
|
||||
<connections>
|
||||
<outlet property="privateKeyURLTextField" destination="4iJ-oB-R1f" id="scx-lz-dUW"/>
|
||||
<outlet property="publicKeyURLTextField" destination="Q1j-Z4-Ae8" id="nfA-W3-kJ2"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="eY3-aM-BJB" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
|
|
@ -1056,14 +1021,14 @@ Phone Support PIN #: 84719</string>
|
|||
<tableViewSection headerTitle="GPG Configuration" id="ugP-R2-9M7">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="Jwg-mt-woS" style="IBUITableViewCellStyleDefault" id="tHt-Ro-0HF" userLabel="Encrypt in ASCII-Armored">
|
||||
<rect key="frame" x="0.0" y="56" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="55" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tHt-Ro-0HF" id="Epj-ei-NtS">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="43"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Encrypt in ASCII-Armored" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Jwg-mt-woS">
|
||||
<rect key="frame" x="15" y="0.0" width="384" height="43"/>
|
||||
<rect key="frame" x="15" y="0.0" width="384" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
|
|
@ -1077,21 +1042,21 @@ Phone Support PIN #: 84719</string>
|
|||
<tableViewSection headerTitle="Git Configuration" id="ihT-OG-HTv">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="87a-xY-AbR" detailTextLabel="2qr-d7-0SK" style="IBUITableViewCellStyleValue1" id="SVj-jD-qPT" userLabel="Git Signature">
|
||||
<rect key="frame" x="0.0" y="157" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="155" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="SVj-jD-qPT" id="HaO-5w-qZt">
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="381" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Git Signature" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="87a-xY-AbR">
|
||||
<rect key="frame" x="15" y="11" width="100" height="21"/>
|
||||
<rect key="frame" x="15.000000000000007" y="11.999999999999998" width="99.666666666666671" height="20.333333333333332"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Not Set" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="2qr-d7-0SK">
|
||||
<rect key="frame" x="321" y="11" width="58" height="21"/>
|
||||
<rect key="frame" x="321.33333333333331" y="11.999999999999998" width="57.666666666666664" height="20.333333333333332"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.5568627451" green="0.5568627451" blue="0.57647058819999997" alpha="1" colorSpace="calibratedRGB"/>
|
||||
|
|
@ -1108,14 +1073,14 @@ Phone Support PIN #: 84719</string>
|
|||
<tableViewSection headerTitle="PasswordStore Data" id="aVR-FE-jMg">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="zrl-v3-fxg" style="IBUITableViewCellStyleDefault" id="Jm8-B5-wKx" userLabel="Discard Changes Table View Cell">
|
||||
<rect key="frame" x="0.0" y="258" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="255" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Jm8-B5-wKx" id="tjS-Q6-y2M">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="43"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Discard All Local Changes" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="zrl-v3-fxg">
|
||||
<rect key="frame" x="15" y="0.0" width="384" height="43"/>
|
||||
<rect key="frame" x="15" y="0.0" width="384" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.50196081400000003" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
|
|
@ -1125,14 +1090,14 @@ Phone Support PIN #: 84719</string>
|
|||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="K2K-Bx-g7Z" style="IBUITableViewCellStyleDefault" id="NI1-Kd-hyH">
|
||||
<rect key="frame" x="0.0" y="302" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="299" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="NI1-Kd-hyH" id="yLe-T2-TWF">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="43"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Erase All Password Store Data" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="K2K-Bx-g7Z">
|
||||
<rect key="frame" x="15" y="0.0" width="384" height="43"/>
|
||||
<rect key="frame" x="15" y="0.0" width="384" height="43.666666666666664"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="0.50196081400000003" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
|
|
@ -1276,11 +1241,11 @@ Phone Support PIN #: 84719</string>
|
|||
<rect key="frame" x="0.0" y="35" width="414" height="170"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Pv0-ev-stj" id="ywz-II-W1g">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="169"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="169.66666666666666"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="ASCII-Armor Keys" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="M32-yr-IfE">
|
||||
<rect key="frame" x="15" y="17" width="122" height="17"/>
|
||||
<rect key="frame" x="15.000000000000007" y="17" width="121.66666666666667" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="14"/>
|
||||
<nil key="textColor"/>
|
||||
|
|
@ -1337,10 +1302,10 @@ Cgo
|
|||
<tableViewSection headerTitle="ASCII-Armor Encrypted Public Key" id="MZz-mp-v5N">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="pgpKeyURLTableViewCell" rowHeight="160" id="Lom-iT-l16">
|
||||
<rect key="frame" x="0.0" y="245" width="414" height="160"/>
|
||||
<rect key="frame" x="0.0" y="244" width="414" height="160"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Lom-iT-l16" id="eya-Tv-r0q">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="159"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="160"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oyB-oI-1fS">
|
||||
|
|
@ -1363,10 +1328,10 @@ Cgo
|
|||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="F0i-XE-PGt" userLabel="scanQRCodeCell">
|
||||
<rect key="frame" x="0.0" y="405" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="404" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="F0i-XE-PGt" id="xO8-yL-W9a">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="43"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
|
|
@ -1375,10 +1340,10 @@ Cgo
|
|||
<tableViewSection headerTitle="ASCII-ARMOR ENCRYPTED PRIVATE KEY" id="0RP-Jn-j5G">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="pgpKeyURLTableViewCell" rowHeight="160" id="J8U-ev-FRQ">
|
||||
<rect key="frame" x="0.0" y="489" width="414" height="160"/>
|
||||
<rect key="frame" x="0.0" y="487" width="414" height="160"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="J8U-ev-FRQ" id="eb0-vb-Fcc">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="159"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="160"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lrQ-Ln-ZOv">
|
||||
|
|
@ -1401,10 +1366,10 @@ Cgo
|
|||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="b0Z-rW-sAE" userLabel="scanQRCodeCell">
|
||||
<rect key="frame" x="0.0" y="649" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="647" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="b0Z-rW-sAE" id="UZX-pP-UWB">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="43"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
|
|
@ -1482,7 +1447,7 @@ Cgo
|
|||
<scene sceneID="zWR-BT-dXv">
|
||||
<objects>
|
||||
<tableViewController id="WgM-cY-mig" customClass="GitSSHKeyArmorSettingTableViewController" customModule="pass" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="1" id="e2Q-qC-LUk">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="1" id="e2Q-qC-LUk">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
|
||||
|
|
@ -1493,18 +1458,18 @@ Cgo
|
|||
<rect key="frame" x="0.0" y="35" width="414" height="170"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="EMz-nP-2Om" id="XW5-mL-PRC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="169"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="169.66666666666666"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="ASCII-Armor Keys" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="i78-t7-fP9">
|
||||
<rect key="frame" x="15" y="36" width="122" height="17"/>
|
||||
<rect key="frame" x="15.000000000000007" y="45" width="121.66666666666667" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="14"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" usesAttributedText="YES" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Oit-sd-wa5">
|
||||
<rect key="frame" x="15" y="53" width="344" height="80"/>
|
||||
<rect key="frame" x="15" y="61.999999999999993" width="344" height="64.333333333333329"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<attributedString key="attributedText">
|
||||
<fragment>
|
||||
|
|
@ -1517,9 +1482,7 @@ Cgo
|
|||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0" allowsDefaultTighteningForTruncation="NO"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment>
|
||||
<string key="content"> $ cat ~/.ssh/id_rsa.pub
|
||||
$ cat ~/.ssh/id_rsa</string>
|
||||
<fragment content=" $ cat ~/.ssh/id_rsa">
|
||||
<attributes>
|
||||
<color key="NSColor" white="0.40782000000000002" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<font key="NSFont" size="13" name="Menlo-Regular"/>
|
||||
|
|
@ -1534,40 +1497,13 @@ Cgo
|
|||
</tableViewCell>
|
||||
</cells>
|
||||
</tableViewSection>
|
||||
<tableViewSection headerTitle="ASCII-Armor Encrypted Public Key" id="w4D-Mh-0pP">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="pgpKeyURLTableViewCell" rowHeight="160" id="3po-uS-Nch">
|
||||
<rect key="frame" x="0.0" y="245" width="414" height="160"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="3po-uS-Nch" id="pet-if-EHU">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="159"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Y9t-DD-6uH">
|
||||
<rect key="frame" x="15" y="8" width="391" height="144"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<fontDescription key="fontDescription" name="Menlo-Regular" family="Menlo" pointSize="8.5"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no"/>
|
||||
</textView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="Y9t-DD-6uH" secondAttribute="bottom" id="EAK-Wn-RP8"/>
|
||||
<constraint firstItem="Y9t-DD-6uH" firstAttribute="top" secondItem="pet-if-EHU" secondAttribute="topMargin" id="LW7-SZ-CP3"/>
|
||||
<constraint firstItem="Y9t-DD-6uH" firstAttribute="leading" secondItem="pet-if-EHU" secondAttribute="leadingMargin" constant="7" id="bw3-EI-8oh"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="Y9t-DD-6uH" secondAttribute="trailing" id="fCY-XN-Wtz"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</cells>
|
||||
</tableViewSection>
|
||||
<tableViewSection headerTitle="ASCII-ARMOR ENCRYPTED PRIVATE KEY" id="sxk-Yb-Y3x">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="pgpKeyURLTableViewCell" rowHeight="160" id="nmc-vy-Ab5">
|
||||
<rect key="frame" x="0.0" y="445" width="414" height="160"/>
|
||||
<rect key="frame" x="0.0" y="244" width="414" height="160"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="nmc-vy-Ab5" id="TQD-GC-YOY">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="159"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="160"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="23o-MP-wQY">
|
||||
|
|
@ -1586,6 +1522,14 @@ Cgo
|
|||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="jXO-n0-Mvx">
|
||||
<rect key="frame" x="0.0" y="404" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="jXO-n0-Mvx" id="AIL-mq-u7n">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</cells>
|
||||
</tableViewSection>
|
||||
</sections>
|
||||
|
|
@ -1603,7 +1547,8 @@ Cgo
|
|||
</navigationItem>
|
||||
<connections>
|
||||
<outlet property="armorPrivateKeyTextView" destination="23o-MP-wQY" id="ybK-Ba-vJt"/>
|
||||
<outlet property="armorPublicKeyTextView" destination="Y9t-DD-6uH" id="307-xN-QZ9"/>
|
||||
<outlet property="scanPrivateKeyCell" destination="jXO-n0-Mvx" id="Zdb-wm-7Ls"/>
|
||||
<segue destination="lLV-kB-JkG" kind="show" identifier="showSSHScannerSegue" id="orz-gu-cTp"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="qJO-AN-K9p" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
|
|
@ -1625,7 +1570,7 @@ Cgo
|
|||
<rect key="frame" x="0.0" y="35" width="414" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="4Bh-1D-w5T" id="mIL-ig-tbp">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Hlb-Zh-ega">
|
||||
|
|
@ -1658,7 +1603,7 @@ Cgo
|
|||
<rect key="frame" x="0.0" y="87" width="414" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="JRY-pY-XtS" id="KrQ-Ih-dk8">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Email" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="m25-Qy-XwU">
|
||||
|
|
@ -1735,7 +1680,7 @@ Cgo
|
|||
</objects>
|
||||
<point key="canvasLocation" x="4967" y="5333"/>
|
||||
</scene>
|
||||
<!--Scanner-->
|
||||
<!--Scan PGP Keys-->
|
||||
<scene sceneID="7j1-Qg-pUZ">
|
||||
<objects>
|
||||
<viewController id="LZE-gF-IcM" customClass="QRScannerController" customModule="pass" customModuleProvider="target" sceneMemberID="viewController">
|
||||
|
|
@ -1765,7 +1710,7 @@ Cgo
|
|||
<constraint firstItem="53A-gx-tky" firstAttribute="top" secondItem="U8O-Md-w8e" secondAttribute="bottom" constant="80" id="tzL-K0-lE7"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" title="Scanner" id="JIs-3z-Tmr">
|
||||
<navigationItem key="navigationItem" title="Scan PGP Keys" id="JIs-3z-Tmr">
|
||||
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="yma-o8-xRu">
|
||||
<connections>
|
||||
<segue destination="0F8-Zv-c2C" kind="unwind" unwindAction="cancelPGPScannerWithSegue:" id="q14-fu-3N4"/>
|
||||
|
|
@ -1781,6 +1726,52 @@ Cgo
|
|||
</objects>
|
||||
<point key="canvasLocation" x="6122" y="4302"/>
|
||||
</scene>
|
||||
<!--Scan SSH Keys-->
|
||||
<scene sceneID="kmR-CX-Yi7">
|
||||
<objects>
|
||||
<viewController id="lLV-kB-JkG" customClass="QRScannerController" customModule="pass" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="NSI-Fp-tX4"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="QZv-Im-xZk"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="GYE-sh-yvu">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="scanner output" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fsL-pq-A5q">
|
||||
<rect key="frame" x="50" y="567" width="314" height="45"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="0.5" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="45" id="IPT-kM-arz"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="QZv-Im-xZk" firstAttribute="top" secondItem="fsL-pq-A5q" secondAttribute="bottom" constant="80" id="76J-7g-eVO"/>
|
||||
<constraint firstItem="fsL-pq-A5q" firstAttribute="leading" secondItem="GYE-sh-yvu" secondAttribute="leadingMargin" constant="30" id="IOo-JD-FMG"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="fsL-pq-A5q" secondAttribute="trailing" constant="30" id="ymC-G4-bdA"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" title="Scan SSH Keys" id="bov-FI-Hkg">
|
||||
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="JhH-TO-YkO">
|
||||
<connections>
|
||||
<segue destination="J2S-Mr-s10" kind="unwind" unwindAction="cancelSSHScannerWithSegue:" id="Thj-zj-TEX"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</navigationItem>
|
||||
<connections>
|
||||
<outlet property="scannerOutput" destination="fsL-pq-A5q" id="lSv-2S-qVd"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="s1p-jn-4PV" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
<exit id="J2S-Mr-s10" userLabel="Exit" sceneMemberID="exit"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="7133" y="2895"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="Lock" width="25" height="25"/>
|
||||
|
|
|
|||
|
|
@ -51,8 +51,15 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
|
|||
|
||||
let numberOfPasswordsString = numberFormatter.string(from: NSNumber(value: self.passwordStore.numberOfPasswords))!
|
||||
let sizeOfRepositoryString = ByteCountFormatter.string(fromByteCount: Int64(self.passwordStore.sizeOfRepositoryByteCount), countStyle: ByteCountFormatter.CountStyle.file)
|
||||
var numberOfCommits: UInt = 0
|
||||
|
||||
let numberOfCommits = self.passwordStore.storeRepository?.numberOfCommits(inCurrentBranch: NSErrorPointer(nilLiteral: ())) ?? 0
|
||||
do {
|
||||
if let _ = try self.passwordStore.storeRepository?.currentBranch().oid {
|
||||
numberOfCommits = self.passwordStore.storeRepository?.numberOfCommits(inCurrentBranch: NSErrorPointer(nilLiteral: ())) ?? 0
|
||||
}
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
let numberOfCommitsString = numberFormatter.string(from: NSNumber(value: numberOfCommits))!
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class AboutTableViewController: BasicStaticTableViewController {
|
|||
// section 0
|
||||
[[.title: "Website", .action: "link", .link: "https://github.com/mssun/pass-ios.git"],
|
||||
[.title: "Help", .action: "link", .link: "https://github.com/mssun/passforios/wiki"],
|
||||
[.title: "Contact Developer", .action: "link", .link: "mailto:bob@mssun.me?subject=passforiOS"],],
|
||||
[.title: "Contact Developer", .action: "link", .link: "mailto:developer@passforios.mssun.me?subject=Pass%20for%20iOS"],],
|
||||
|
||||
// section 1,
|
||||
[[.title: "Open Source Components", .action: "segue", .link: "showOpenSourceComponentsSegue"],
|
||||
|
|
|
|||
|
|
@ -16,11 +16,14 @@ class AddPasswordTableViewController: PasswordEditorTableViewController {
|
|||
override func viewDidLoad() {
|
||||
tableData = [
|
||||
[[.type: PasswordEditorCellType.nameCell, .title: "name"]],
|
||||
[[.type: PasswordEditorCellType.fillPasswordCell, .title: "password"],
|
||||
[.type: PasswordEditorCellType.passwordLengthCell, .title: "passwordlength"]],
|
||||
[[.type: PasswordEditorCellType.fillPasswordCell, .title: "password"]],
|
||||
[[.type: PasswordEditorCellType.additionsCell, .title: "additions"]],
|
||||
[[.type: PasswordEditorCellType.scanQRCodeCell]]
|
||||
]
|
||||
if let lengthSetting = Globals.passwordDefaultLength[Defaults[.passwordGeneratorFlavor]],
|
||||
lengthSetting.max > lengthSetting.min {
|
||||
tableData[1].append([.type: PasswordEditorCellType.passwordLengthCell, .title: "passwordlength"])
|
||||
}
|
||||
super.viewDidLoad()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,17 +7,21 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import SwiftyUserDefaults
|
||||
|
||||
class EditPasswordTableViewController: PasswordEditorTableViewController {
|
||||
override func viewDidLoad() {
|
||||
tableData = [
|
||||
[[.type: PasswordEditorCellType.nameCell, .title: "name", .content: password!.namePath]],
|
||||
[[.type: PasswordEditorCellType.fillPasswordCell, .title: "password", .content: password!.password],
|
||||
[.type: PasswordEditorCellType.passwordLengthCell, .title: "passwordlength"]],
|
||||
[[.type: PasswordEditorCellType.fillPasswordCell, .title: "password", .content: password!.password]],
|
||||
[[.type: PasswordEditorCellType.additionsCell, .title: "additions", .content: password!.getAdditionsPlainText()]],
|
||||
[[.type: PasswordEditorCellType.scanQRCodeCell],
|
||||
[.type: PasswordEditorCellType.deletePasswordCell]]
|
||||
]
|
||||
if let lengthSetting = Globals.passwordDefaultLength[Defaults[.passwordGeneratorFlavor]],
|
||||
lengthSetting.max > lengthSetting.min {
|
||||
tableData[1].append([.type: PasswordEditorCellType.passwordLengthCell, .title: "passwordlength"])
|
||||
}
|
||||
super.viewDidLoad()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ struct GitCredential {
|
|||
|
||||
enum Credential {
|
||||
case http(userName: String, controller: UIViewController)
|
||||
case ssh(userName: String, publicKeyFile: URL, privateKeyFile: URL, controller: UIViewController)
|
||||
case ssh(userName: String, privateKeyFile: URL, controller: UIViewController)
|
||||
}
|
||||
|
||||
init(credential: Credential) {
|
||||
|
|
@ -44,7 +44,7 @@ struct GitCredential {
|
|||
attempts += 1
|
||||
lastPassword = newPassword
|
||||
credential = try? GTCredential(userName: userName, password: newPassword!)
|
||||
case let .ssh(userName, publicKeyFile, privateKeyFile, controller):
|
||||
case let .ssh(userName, privateKeyFile, controller):
|
||||
var newPassword = Utils.getPasswordFromKeychain(name: "gitSSHKeyPassphrase")
|
||||
if newPassword == nil || attempts != 0 {
|
||||
if let requestedPassword = self.requestGitPassword(controller, lastPassword) {
|
||||
|
|
@ -56,7 +56,8 @@ struct GitCredential {
|
|||
}
|
||||
attempts += 1
|
||||
lastPassword = newPassword
|
||||
credential = try? GTCredential(userName: userName, publicKeyURL: publicKeyFile, privateKeyURL: privateKeyFile, passphrase: newPassword!)
|
||||
credential = try? GTCredential(userName: userName, publicKeyURL: nil, privateKeyURL: privateKeyFile, passphrase: newPassword!)
|
||||
print(privateKeyFile)
|
||||
}
|
||||
return credential
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,27 +9,82 @@
|
|||
import UIKit
|
||||
import SwiftyUserDefaults
|
||||
|
||||
class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextViewDelegate {
|
||||
@IBOutlet weak var armorPublicKeyTextView: UITextView!
|
||||
class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextViewDelegate, QRScannerControllerDelegate {
|
||||
@IBOutlet weak var armorPrivateKeyTextView: UITextView!
|
||||
@IBOutlet weak var scanPrivateKeyCell: UITableViewCell!
|
||||
|
||||
var gitSSHPrivateKeyPassphrase: String?
|
||||
let passwordStore = PasswordStore.shared
|
||||
|
||||
private var recentPastedText = ""
|
||||
|
||||
class ScannedSSHKey {
|
||||
static let maxNumberOfGif = 100
|
||||
var numberOfSegments = 0
|
||||
var previousSegment = ""
|
||||
var key = ""
|
||||
var message = ""
|
||||
var hasStarted = false
|
||||
var isDone = false
|
||||
|
||||
func reset() {
|
||||
numberOfSegments = 0
|
||||
previousSegment = ""
|
||||
key = ""
|
||||
message = "Looking for the starting frame."
|
||||
hasStarted = false
|
||||
isDone = false
|
||||
}
|
||||
|
||||
func addSegment(segment: String) {
|
||||
// skip duplicated segments
|
||||
guard segment != previousSegment else {
|
||||
return
|
||||
}
|
||||
previousSegment = segment
|
||||
|
||||
// check whether we have found the first block
|
||||
if hasStarted == false {
|
||||
hasStarted = segment.contains("-----BEGIN")
|
||||
}
|
||||
guard hasStarted == true else {
|
||||
return
|
||||
}
|
||||
|
||||
// check the number of segments
|
||||
numberOfSegments = numberOfSegments + 1
|
||||
guard numberOfSegments <= ScannedSSHKey.maxNumberOfGif else {
|
||||
key = "Too many QR codes"
|
||||
return
|
||||
}
|
||||
|
||||
// update full text and check whether we are done
|
||||
key.append(segment)
|
||||
if let index1 = key.range(of: "-----END")?.lowerBound,
|
||||
let _ = key.substring(from: index1).range(of: "KEY-----")?.lowerBound {
|
||||
isDone = true
|
||||
}
|
||||
|
||||
// update message
|
||||
message = "\(numberOfSegments) scanned QR codes."
|
||||
}
|
||||
}
|
||||
var scanned = ScannedSSHKey()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
armorPublicKeyTextView.text = Defaults[.gitSSHPublicKeyArmor]
|
||||
armorPrivateKeyTextView.text = Defaults[.gitSSHPrivateKeyArmor]
|
||||
armorPublicKeyTextView.delegate = self
|
||||
armorPrivateKeyTextView.delegate = self
|
||||
|
||||
scanPrivateKeyCell?.textLabel?.text = "Scan Private Key QR Codes"
|
||||
scanPrivateKeyCell?.textLabel?.textColor = Globals.blue
|
||||
scanPrivateKeyCell?.selectionStyle = .default
|
||||
scanPrivateKeyCell?.accessoryType = .disclosureIndicator
|
||||
}
|
||||
|
||||
@IBAction func doneButtonTapped(_ sender: Any) {
|
||||
Defaults[.gitSSHPublicKeyArmor] = armorPublicKeyTextView.text
|
||||
Defaults[.gitSSHPrivateKeyArmor] = armorPrivateKeyTextView.text
|
||||
do {
|
||||
try passwordStore.initGitSSHKey(with: armorPublicKeyTextView.text, .public)
|
||||
try passwordStore.initGitSSHKey(with: armorPrivateKeyTextView.text, .secret)
|
||||
} catch {
|
||||
Utils.alert(title: "Cannot Save", message: "Cannot Save SSH Key", controller: self, completion: nil)
|
||||
|
|
@ -51,4 +106,46 @@ class GitSSHKeyArmorSettingTableViewController: UITableViewController, UITextVie
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let selectedCell = tableView.cellForRow(at: indexPath)
|
||||
if selectedCell == scanPrivateKeyCell {
|
||||
scanned.reset()
|
||||
self.performSegue(withIdentifier: "showSSHScannerSegue", sender: self)
|
||||
}
|
||||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - QRScannerControllerDelegate Methods
|
||||
func checkScannedOutput(line: String) -> (accept: Bool, message: String) {
|
||||
scanned.addSegment(segment: line)
|
||||
if scanned.isDone {
|
||||
return (accept: true, message: "Done")
|
||||
} else {
|
||||
return (accept: false, message: scanned.message)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - QRScannerControllerDelegate Methods
|
||||
func handleScannedOutput(line: String) {
|
||||
armorPrivateKeyTextView.text = scanned.key
|
||||
}
|
||||
|
||||
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
|
||||
if segue.identifier == "showSSHScannerSegue" {
|
||||
if let navController = segue.destination as? UINavigationController {
|
||||
if let viewController = navController.topViewController as? QRScannerController {
|
||||
viewController.delegate = self
|
||||
}
|
||||
} else if let viewController = segue.destination as? QRScannerController {
|
||||
viewController.delegate = self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction private func cancelSSHScanner(segue: UIStoryboardSegue) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,9 +40,9 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
// Grey out ssh option if ssh_key and ssh_key.pub are not present
|
||||
// Grey out ssh option if ssh_key is not present
|
||||
if let sshLabel = sshLabel {
|
||||
sshLabel.isEnabled = gitSSHKeyExists()
|
||||
sshLabel.isEnabled = passwordStore.gitSSHKeyExists()
|
||||
}
|
||||
}
|
||||
override func viewDidLoad() {
|
||||
|
|
@ -73,15 +73,56 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
view.endEditing(true)
|
||||
}
|
||||
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
if identifier == "saveGitServerSettingSegue" {
|
||||
guard let _ = URL(string: gitURLTextField.text!) else {
|
||||
Utils.alert(title: "Cannot Save", message: "Git Server is not set.", controller: self, completion: nil)
|
||||
return false
|
||||
}
|
||||
private func cloneAndSegueIfSuccess() {
|
||||
// try to clone
|
||||
let gitRepostiroyURL = gitURLTextField.text!
|
||||
let username = usernameTextField.text!
|
||||
let auth = authenticationMethod
|
||||
|
||||
SVProgressHUD.setDefaultMaskType(.black)
|
||||
SVProgressHUD.setDefaultStyle(.light)
|
||||
SVProgressHUD.show(withStatus: "Prepare Repository")
|
||||
var gitCredential: GitCredential
|
||||
if auth == "Password" {
|
||||
gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: username, controller: self))
|
||||
} else {
|
||||
gitCredential = GitCredential(
|
||||
credential: GitCredential.Credential.ssh(
|
||||
userName: username,
|
||||
privateKeyFile: Globals.gitSSHPrivateKeyURL,
|
||||
controller: self
|
||||
)
|
||||
)
|
||||
}
|
||||
return true
|
||||
}
|
||||
let dispatchQueue = DispatchQueue.global(qos: .userInitiated)
|
||||
dispatchQueue.async {
|
||||
do {
|
||||
try self.passwordStore.cloneRepository(remoteRepoURL: URL(string: gitRepostiroyURL)!,
|
||||
credential: gitCredential,
|
||||
transferProgressBlock: { (git_transfer_progress, stop) in
|
||||
DispatchQueue.main.async {
|
||||
SVProgressHUD.showProgress(Float(git_transfer_progress.pointee.received_objects)/Float(git_transfer_progress.pointee.total_objects), status: "Clone Remote Repository")
|
||||
}
|
||||
},
|
||||
checkoutProgressBlock: { (path, completedSteps, totalSteps) in
|
||||
DispatchQueue.main.async {
|
||||
SVProgressHUD.showProgress(Float(completedSteps)/Float(totalSteps), status: "Checkout Master Branch")
|
||||
}
|
||||
})
|
||||
DispatchQueue.main.async {
|
||||
Defaults[.gitURL] = URL(string: gitRepostiroyURL)
|
||||
Defaults[.gitUsername] = username
|
||||
Defaults[.gitAuthenticationMethod] = auth
|
||||
SVProgressHUD.showSuccess(withStatus: "Done")
|
||||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self)
|
||||
}
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
||||
}
|
||||
}
|
||||
} }
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let cell = tableView.cellForRow(at: indexPath)
|
||||
|
|
@ -89,7 +130,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
authenticationMethod = "Password"
|
||||
} else if cell == authSSHKeyCell {
|
||||
|
||||
if !gitSSHKeyExists() {
|
||||
if !passwordStore.gitSSHKeyExists() {
|
||||
Utils.alert(title: "Cannot Select SSH Key", message: "Please setup SSH key first.", controller: self, completion: nil)
|
||||
authenticationMethod = "Password"
|
||||
} else {
|
||||
|
|
@ -100,35 +141,31 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
||||
private func doClone() {
|
||||
if self.shouldPerformSegue(withIdentifier: "saveGitServerSettingSegue", sender: self) {
|
||||
self.performSegue(withIdentifier: "saveGitServerSettingSegue", sender: self)
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func save(_ sender: Any) {
|
||||
guard let _ = URL(string: gitURLTextField.text!) else {
|
||||
Utils.alert(title: "Cannot Save", message: "Git Server is not set.", controller: self, completion: nil)
|
||||
return
|
||||
}
|
||||
|
||||
if passwordStore.repositoryExisted() {
|
||||
let alert = UIAlertController(title: "Erase Current Password Store Data?", message: "A cloned password store exists. This operation will erase all local data. Data on your remote server will not be affected.", preferredStyle: UIAlertControllerStyle.alert)
|
||||
alert.addAction(UIAlertAction(title: "Erase", style: UIAlertActionStyle.destructive, handler: { _ in
|
||||
self.doClone()
|
||||
// perform segue only after a successful clone
|
||||
self.cloneAndSegueIfSuccess()
|
||||
}))
|
||||
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil))
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
} else {
|
||||
doClone()
|
||||
// perform segue only after a successful clone
|
||||
cloneAndSegueIfSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
private func gitSSHKeyExists() -> Bool {
|
||||
return FileManager.default.fileExists(atPath: Globals.gitSSHPublicKeyPath) &&
|
||||
FileManager.default.fileExists(atPath: Globals.gitSSHPrivateKeyPath)
|
||||
}
|
||||
|
||||
|
||||
func showSSHKeyActionSheet() {
|
||||
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||
var urlActionTitle = "Download from URL"
|
||||
var armorActionTitle = "ASCII-Armor Encrypted Key"
|
||||
var fileActionTitle = "Use Uploaded Keys"
|
||||
var fileActionTitle = "Use Imported Keys"
|
||||
|
||||
if Defaults[.gitSSHKeySource] == "url" {
|
||||
urlActionTitle = "✓ \(urlActionTitle)"
|
||||
|
|
@ -147,16 +184,24 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
optionMenu.addAction(urlAction)
|
||||
optionMenu.addAction(armorAction)
|
||||
|
||||
if (gitSSHKeyExists()) {
|
||||
if passwordStore.gitSSHKeyExists() {
|
||||
// might keys updated via iTunes, or downloaded/pasted inside the app
|
||||
let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
||||
Defaults[.gitSSHKeySource] = "file"
|
||||
}
|
||||
optionMenu.addAction(fileAction)
|
||||
} else {
|
||||
let fileAction = UIAlertAction(title: "iTunes File Sharing", style: .default) { _ in
|
||||
let title = "Import via iTunes File Sharing"
|
||||
let message = "Copy your private key from your computer to Pass for iOS with the name \"ssh_key\" (without quotes)."
|
||||
Utils.alert(title: title, message: message, controller: self)
|
||||
}
|
||||
optionMenu.addAction(fileAction)
|
||||
}
|
||||
|
||||
if Defaults[.gitSSHKeySource] != nil {
|
||||
let deleteAction = UIAlertAction(title: "Remove Git SSH Keys", style: .destructive) { _ in
|
||||
Utils.removeGitSSHKeys()
|
||||
self.passwordStore.removeGitSSHKeys()
|
||||
Defaults[.gitSSHKeySource] = nil
|
||||
if let sshLabel = self.sshLabel {
|
||||
sshLabel.isEnabled = false
|
||||
|
|
|
|||
|
|
@ -107,20 +107,6 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
|||
scanPrivateKeyCell?.accessoryType = .disclosureIndicator
|
||||
}
|
||||
|
||||
private func createSavePassphraseAndSegueAlert() -> UIAlertController {
|
||||
let savePassphraseAlert = UIAlertController(title: "Passphrase", message: "Do you want to save the passphrase for later decryption?", preferredStyle: UIAlertControllerStyle.alert)
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
||||
Defaults[.isRememberPassphraseOn] = false
|
||||
self.pgpPassphrase = nil
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
})
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "Save", style: UIAlertActionStyle.destructive) {_ in
|
||||
Defaults[.isRememberPassphraseOn] = true
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
})
|
||||
return savePassphraseAlert
|
||||
}
|
||||
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
if identifier == "savePGPKeySegue" {
|
||||
if armorPublicKeyTextView.text.isEmpty {
|
||||
|
|
@ -136,17 +122,29 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
|
|||
}
|
||||
|
||||
@IBAction func save(_ sender: Any) {
|
||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
||||
self.pgpPassphrase = alert.textFields?.first?.text
|
||||
let savePassphraseAndSegueAlert = self.createSavePassphraseAndSegueAlert()
|
||||
self.present(savePassphraseAndSegueAlert, animated: true, completion: nil)
|
||||
}))
|
||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = self.pgpPassphrase
|
||||
textField.isSecureTextEntry = true
|
||||
let savePassphraseAlert = UIAlertController(title: "Passphrase", message: "Do you want to save the passphrase for later decryption?", preferredStyle: UIAlertControllerStyle.alert)
|
||||
// no
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
||||
self.pgpPassphrase = nil
|
||||
Defaults[.isRememberPassphraseOn] = false
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
})
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
// yes
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.destructive) {_ in
|
||||
// ask for the passphrase
|
||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
||||
self.pgpPassphrase = alert.textFields?.first?.text
|
||||
Defaults[.isRememberPassphraseOn] = true
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
}))
|
||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = self.pgpPassphrase
|
||||
textField.isSecureTextEntry = true
|
||||
})
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
})
|
||||
self.present(savePassphraseAlert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
|
||||
|
|
|
|||
|
|
@ -24,19 +24,6 @@ class PGPKeySettingTableViewController: UITableViewController {
|
|||
pgpPassphrase = passwordStore.pgpKeyPassphrase
|
||||
}
|
||||
|
||||
private func createSavePassphraseAndSegueAlert() -> UIAlertController {
|
||||
let savePassphraseAlert = UIAlertController(title: "Passphrase", message: "Do you want to save the passphrase for later decryption?", preferredStyle: UIAlertControllerStyle.alert)
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
||||
Defaults[.isRememberPassphraseOn] = false
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
})
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "Save", style: UIAlertActionStyle.destructive) {_ in
|
||||
Defaults[.isRememberPassphraseOn] = true
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
})
|
||||
return savePassphraseAlert
|
||||
}
|
||||
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
if identifier == "savePGPKeySegue" {
|
||||
guard validatePGPKeyURL(input: pgpPublicKeyURLTextField.text) == true,
|
||||
|
|
@ -60,16 +47,28 @@ class PGPKeySettingTableViewController: UITableViewController {
|
|||
}
|
||||
|
||||
@IBAction func save(_ sender: Any) {
|
||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
||||
self.pgpPassphrase = alert.textFields?.first?.text
|
||||
let savePassphraseAndSegueAlert = self.createSavePassphraseAndSegueAlert()
|
||||
self.present(savePassphraseAndSegueAlert, animated: true, completion: nil)
|
||||
}))
|
||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = self.pgpPassphrase
|
||||
textField.isSecureTextEntry = true
|
||||
let savePassphraseAlert = UIAlertController(title: "Passphrase", message: "Do you want to save the passphrase for later decryption?", preferredStyle: UIAlertControllerStyle.alert)
|
||||
// no
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
||||
self.pgpPassphrase = nil
|
||||
Defaults[.isRememberPassphraseOn] = false
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
})
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
// yes
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.destructive) {_ in
|
||||
// ask for the passphrase
|
||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
||||
self.pgpPassphrase = alert.textFields?.first?.text
|
||||
Defaults[.isRememberPassphraseOn] = true
|
||||
self.performSegue(withIdentifier: "savePGPKeySegue", sender: self)
|
||||
}))
|
||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = self.pgpPassphrase
|
||||
textField.isSecureTextEntry = true
|
||||
})
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
})
|
||||
self.present(savePassphraseAlert, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,10 +101,10 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
NotificationCenter.default.addObserver(self, selector: #selector(setShouldPopCurrentView), name: .passwordStoreChangeDiscarded, object: nil)
|
||||
|
||||
// reset the data table if some password (maybe another one) has been updated
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(showPassword), name: .passwordStoreUpdated, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(decryptThenShowPassword), name: .passwordStoreUpdated, object: nil)
|
||||
|
||||
// reset the data table if the disaply settings have been changed
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(showPassword), name: .passwordDetailDisplaySettingChanged, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(decryptThenShowPassword), name: .passwordDetailDisplaySettingChanged, object: nil)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
|
|
@ -140,19 +140,29 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
return passphrase
|
||||
}
|
||||
|
||||
private func decryptThenShowPassword() {
|
||||
@objc private func decryptThenShowPassword() {
|
||||
guard let passwordEntity = passwordEntity, passwordEntity.path != nil else {
|
||||
Utils.alert(title: "Cannot Show Password", message: "The password does not exist.", controller: self, handler: {(UIAlertAction) -> Void in
|
||||
self.navigationController!.popViewController(animated: true)
|
||||
})
|
||||
return
|
||||
}
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
// decrypt password
|
||||
do {
|
||||
self.password = try self.passwordStore.decrypt(passwordEntity: self.passwordEntity!, requestPGPKeyPassphrase: self.requestPGPKeyPassphrase)
|
||||
self.password = try self.passwordStore.decrypt(passwordEntity: passwordEntity, requestPGPKeyPassphrase: self.requestPGPKeyPassphrase)
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
// remove the wrong passphrase so that users could enter it next time
|
||||
self.passwordStore.pgpKeyPassphrase = nil
|
||||
// alert: cancel or try again
|
||||
let alert = UIAlertController(title: "Cannot Show Password", message: error.localizedDescription, preferredStyle: UIAlertControllerStyle.alert)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {(UIAlertAction) -> Void in
|
||||
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.default) { _ in
|
||||
self.navigationController!.popViewController(animated: true)
|
||||
}))
|
||||
})
|
||||
alert.addAction(UIAlertAction(title: "Try again", style: UIAlertActionStyle.destructive) {_ in
|
||||
self.decryptThenShowPassword()
|
||||
})
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
return
|
||||
|
|
@ -162,7 +172,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
|
|||
}
|
||||
}
|
||||
|
||||
@objc private func showPassword() {
|
||||
private func showPassword() {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.indicator.stopAnimating()
|
||||
self?.setTableData()
|
||||
|
|
|
|||
|
|
@ -89,6 +89,9 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
|
|||
fillPasswordCell = tableView.dequeueReusableCell(withIdentifier: "fillPasswordCell", for: indexPath) as? FillPasswordTableViewCell
|
||||
fillPasswordCell?.delegate = self
|
||||
fillPasswordCell?.setContent(content: cellData[PasswordEditorCellKey.content] as? String)
|
||||
if tableData[passwordSection].count == 1 {
|
||||
fillPasswordCell?.settingButton.isHidden = true
|
||||
}
|
||||
return fillPasswordCell!
|
||||
case .passwordLengthCell:
|
||||
passwordLengthCell = tableView.dequeueReusableCell(withIdentifier: "passwordLengthCell", for: indexPath) as? SliderTableViewCell
|
||||
|
|
|
|||
|
|
@ -145,7 +145,6 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
gitCredential = GitCredential(
|
||||
credential: GitCredential.Credential.ssh(
|
||||
userName: Defaults[.gitUsername]!,
|
||||
publicKeyFile: Globals.gitSSHPublicKeyURL,
|
||||
privateKeyFile: Globals.gitSSHPrivateKeyURL,
|
||||
controller: self
|
||||
)
|
||||
|
|
@ -535,7 +534,9 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
self.tapTabBarTime = currentTime
|
||||
if duration < 0.35 {
|
||||
let topIndexPath = IndexPath(row: 0, section: 0)
|
||||
tableView.scrollToRow(at: topIndexPath, at: .bottom, animated: true)
|
||||
if let _ = tableView.cellForRow(at: topIndexPath) {
|
||||
tableView.scrollToRow(at: topIndexPath, at: .bottom, animated: true)
|
||||
}
|
||||
self.tapTabBarTime = 0
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,31 +13,23 @@ import SVProgressHUD
|
|||
class SSHKeySettingTableViewController: UITableViewController {
|
||||
|
||||
@IBOutlet weak var privateKeyURLTextField: UITextField!
|
||||
@IBOutlet weak var publicKeyURLTextField: UITextField!
|
||||
let passwordStore = PasswordStore.shared
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
privateKeyURLTextField.text = Defaults[.gitSSHPrivateKeyURL]?.absoluteString
|
||||
publicKeyURLTextField.text = Defaults[.gitSSHPublicKeyURL]?.absoluteString
|
||||
}
|
||||
|
||||
|
||||
@IBAction func doneButtonTapped(_ sender: UIButton) {
|
||||
guard let publicKeyURL = URL(string: publicKeyURLTextField.text!) else {
|
||||
Utils.alert(title: "Cannot Save", message: "Please set Public Key URL first.", controller: self, completion: nil)
|
||||
return
|
||||
}
|
||||
guard let privateKeyURL = URL(string: privateKeyURLTextField.text!) else {
|
||||
Utils.alert(title: "Cannot Save", message: "Please set Private Key URL first.", controller: self, completion: nil)
|
||||
return
|
||||
}
|
||||
|
||||
Defaults[.gitSSHPublicKeyURL] = publicKeyURL
|
||||
Defaults[.gitSSHPrivateKeyURL] = privateKeyURL
|
||||
|
||||
do {
|
||||
try Data(contentsOf: publicKeyURL).write(to: URL(fileURLWithPath: Globals.gitSSHPublicKeyPath), options: .atomic)
|
||||
try Data(contentsOf: privateKeyURL).write(to: URL(fileURLWithPath: Globals.gitSSHPrivateKeyPath), options: .atomic)
|
||||
} catch {
|
||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import SVProgressHUD
|
|||
import CoreData
|
||||
import SwiftyUserDefaults
|
||||
import PasscodeLock
|
||||
import LocalAuthentication
|
||||
|
||||
class SettingsTableViewController: UITableViewController {
|
||||
|
||||
|
|
@ -91,64 +92,49 @@ class SettingsTableViewController: UITableViewController {
|
|||
}
|
||||
}
|
||||
|
||||
@IBAction func cancelGitServerSetting(segue: UIStoryboardSegue) {
|
||||
}
|
||||
|
||||
@IBAction func saveGitServerSetting(segue: UIStoryboardSegue) {
|
||||
if let controller = segue.source as? GitServerSettingTableViewController {
|
||||
let gitRepostiroyURL = controller.gitURLTextField.text!
|
||||
let username = controller.usernameTextField.text!
|
||||
let auth = controller.authenticationMethod
|
||||
|
||||
SVProgressHUD.setDefaultMaskType(.black)
|
||||
SVProgressHUD.setDefaultStyle(.light)
|
||||
SVProgressHUD.show(withStatus: "Prepare Repository")
|
||||
var gitCredential: GitCredential
|
||||
if auth == "Password" {
|
||||
gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: username, controller: self))
|
||||
} else {
|
||||
gitCredential = GitCredential(
|
||||
credential: GitCredential.Credential.ssh(
|
||||
userName: username,
|
||||
publicKeyFile: Globals.gitSSHPublicKeyURL,
|
||||
privateKeyFile: Globals.gitSSHPrivateKeyURL,
|
||||
controller: self
|
||||
)
|
||||
)
|
||||
}
|
||||
let dispatchQueue = DispatchQueue.global(qos: .userInitiated)
|
||||
dispatchQueue.async {
|
||||
do {
|
||||
try self.passwordStore.cloneRepository(remoteRepoURL: URL(string: gitRepostiroyURL)!,
|
||||
credential: gitCredential,
|
||||
transferProgressBlock:{ (git_transfer_progress, stop) in
|
||||
DispatchQueue.main.async {
|
||||
SVProgressHUD.showProgress(Float(git_transfer_progress.pointee.received_objects)/Float(git_transfer_progress.pointee.total_objects), status: "Clone Remote Repository")
|
||||
}
|
||||
},
|
||||
checkoutProgressBlock: { (path, completedSteps, totalSteps) in
|
||||
DispatchQueue.main.async {
|
||||
SVProgressHUD.showProgress(Float(completedSteps)/Float(totalSteps), status: "Checkout Master Branch")
|
||||
}
|
||||
})
|
||||
DispatchQueue.main.async {
|
||||
Defaults[.gitURL] = URL(string: gitRepostiroyURL)
|
||||
Defaults[.gitUsername] = username
|
||||
Defaults[.gitAuthenticationMethod] = auth
|
||||
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitURL]?.host
|
||||
SVProgressHUD.showSuccess(withStatus: "Done")
|
||||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
}
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
||||
}
|
||||
private func saveImportedPGPKey() {
|
||||
// load keys
|
||||
Defaults[.pgpKeySource] = "file"
|
||||
|
||||
SVProgressHUD.setDefaultMaskType(.black)
|
||||
SVProgressHUD.setDefaultStyle(.light)
|
||||
SVProgressHUD.show(withStatus: "Fetching PGP Key")
|
||||
DispatchQueue.global(qos: .userInitiated).async { [unowned self] in
|
||||
do {
|
||||
try self.passwordStore.initPGPKeys()
|
||||
DispatchQueue.main.async {
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
|
||||
SVProgressHUD.showSuccess(withStatus: "Success")
|
||||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
}
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = "Not Set"
|
||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func cancelGitServerSetting(segue: UIStoryboardSegue) {
|
||||
}
|
||||
|
||||
@IBAction func saveGitServerSetting(segue: UIStoryboardSegue) {
|
||||
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitURL]?.host
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
// Security section, hide TouchID if the device doesn't support
|
||||
if section == 1 {
|
||||
if hasTouchID() {
|
||||
return 2
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return super.tableView(tableView, numberOfRowsInSection: section)
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.actOnPasswordStoreErasedNotification), name: .passwordStoreErased, object: nil)
|
||||
|
|
@ -159,6 +145,28 @@ class SettingsTableViewController: UITableViewController {
|
|||
setPasscodeLockTouchIDCells()
|
||||
}
|
||||
|
||||
private func hasTouchID() -> Bool {
|
||||
let context = LAContext()
|
||||
var error: NSError?
|
||||
if context.canEvaluatePolicy(LAPolicy.deviceOwnerAuthenticationWithBiometrics, error: &error) {
|
||||
return true
|
||||
} else {
|
||||
switch error!.code {
|
||||
case LAError.Code.touchIDNotEnrolled.rawValue:
|
||||
return true
|
||||
case LAError.Code.passcodeNotSet.rawValue:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func isTouchIDEnabled() -> Bool {
|
||||
let context = LAContext()
|
||||
return context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)
|
||||
}
|
||||
|
||||
private func setPasscodeLockTouchIDCells() {
|
||||
if PasscodeLockRepository().hasPasscode {
|
||||
self.passcodeTableViewCell.detailTextLabel?.text = "On"
|
||||
|
|
@ -210,32 +218,25 @@ class SettingsTableViewController: UITableViewController {
|
|||
tableView.deselectRow(at: indexPath, animated: true)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
}
|
||||
|
||||
func touchIDSwitchAction(uiSwitch: UISwitch) {
|
||||
if !Globals.passcodeConfiguration.isTouchIDAllowed {
|
||||
if !Globals.passcodeConfiguration.isTouchIDAllowed || !isTouchIDEnabled() {
|
||||
// switch off
|
||||
uiSwitch.isOn = Defaults[.isTouchIDOn] // false
|
||||
Utils.alert(title: "Notice", message: "Please set the passcode lock first.", controller: self, completion: nil)
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
|
||||
uiSwitch.isOn = Defaults[.isTouchIDOn] // false
|
||||
Utils.alert(title: "Notice", message: "Please enable Touch ID and set the passcode lock first.", controller: self, completion: nil)
|
||||
}
|
||||
} else {
|
||||
Defaults[.isTouchIDOn] = uiSwitch.isOn
|
||||
}
|
||||
let appDelegate = UIApplication.shared.delegate as! AppDelegate
|
||||
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window, configuration: Globals.passcodeConfiguration)
|
||||
}
|
||||
|
||||
func pgpKeyExists() -> Bool {
|
||||
return FileManager.default.fileExists(atPath: Globals.pgpPublicKeyPath) &&
|
||||
FileManager.default.fileExists(atPath: Globals.pgpPrivateKeyPath)
|
||||
}
|
||||
|
||||
func showPGPKeyActionSheet() {
|
||||
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
|
||||
var urlActionTitle = "Download from URL"
|
||||
var armorActionTitle = "ASCII-Armor Encrypted Key"
|
||||
var fileActionTitle = "Use Uploaded Keys"
|
||||
var fileActionTitle = "Use Imported Keys"
|
||||
|
||||
if Defaults[.pgpKeySource] == "url" {
|
||||
urlActionTitle = "✓ \(urlActionTitle)"
|
||||
|
|
@ -254,63 +255,47 @@ class SettingsTableViewController: UITableViewController {
|
|||
optionMenu.addAction(urlAction)
|
||||
optionMenu.addAction(armorAction)
|
||||
|
||||
if (pgpKeyExists()) {
|
||||
if passwordStore.pgpKeyExists() {
|
||||
let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
||||
|
||||
SVProgressHUD.setDefaultMaskType(.black)
|
||||
SVProgressHUD.setDefaultStyle(.light)
|
||||
SVProgressHUD.show(withStatus: "Reading PGP key")
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "PGP Passphrase",
|
||||
message: "Please fill in the passphrase for your PGP key.",
|
||||
preferredStyle: UIAlertControllerStyle.alert
|
||||
)
|
||||
|
||||
alert.addAction(
|
||||
UIAlertAction(
|
||||
title: "OK",
|
||||
style: UIAlertActionStyle.default,
|
||||
handler: {_ in
|
||||
Utils.addPasswordToKeychain(
|
||||
name: "pgpKeyPassphrase",
|
||||
password: alert.textFields!.first!.text!
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
alert.addTextField(
|
||||
configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = Utils.getPasswordFromKeychain(name: "pgpKeyPassphrase") ?? ""
|
||||
textField.isSecureTextEntry = true
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.passwordStore.initPGPKeys()
|
||||
|
||||
let key: PGPKey = self.passwordStore.getPgpPrivateKey()
|
||||
Defaults[.pgpKeySource] = "file"
|
||||
|
||||
if (key.isEncrypted) {
|
||||
SVProgressHUD.dismiss()
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
SVProgressHUD.dismiss()
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = self.passwordStore.pgpKeyID
|
||||
}
|
||||
|
||||
// passphrase related
|
||||
let savePassphraseAlert = UIAlertController(title: "Passphrase", message: "Do you want to save the passphrase for later decryption?", preferredStyle: UIAlertControllerStyle.alert)
|
||||
// no
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
||||
self.passwordStore.pgpKeyPassphrase = nil
|
||||
Defaults[.isRememberPassphraseOn] = false
|
||||
self.saveImportedPGPKey()
|
||||
})
|
||||
// yes
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.destructive) {_ in
|
||||
// ask for the passphrase
|
||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your PGP secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
||||
self.passwordStore.pgpKeyPassphrase = alert.textFields?.first?.text
|
||||
Defaults[.isRememberPassphraseOn] = true
|
||||
self.saveImportedPGPKey()
|
||||
}))
|
||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = ""
|
||||
textField.isSecureTextEntry = true
|
||||
})
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
})
|
||||
self.present(savePassphraseAlert, animated: true, completion: nil)
|
||||
}
|
||||
optionMenu.addAction(fileAction)
|
||||
} else {
|
||||
let fileAction = UIAlertAction(title: "iTunes File Sharing", style: .default) { _ in
|
||||
let title = "Import via iTunes File Sharing"
|
||||
let message = "Copy your public and private key from your computer to Pass for iOS with the name \"gpg_key.pub\" and \"gpg_key\" (without quotes)."
|
||||
Utils.alert(title: title, message: message, controller: self)
|
||||
}
|
||||
|
||||
optionMenu.addAction(fileAction)
|
||||
}
|
||||
|
||||
|
||||
if Defaults[.pgpKeySource] != nil {
|
||||
let deleteAction = UIAlertAction(title: "Remove PGP Keys", style: .destructive) { _ in
|
||||
Utils.removePGPKeys()
|
||||
self.passwordStore.removePGPKeys()
|
||||
self.pgpKeyTableViewCell.detailTextLabel?.text = "Not Set"
|
||||
}
|
||||
optionMenu.addAction(deleteAction)
|
||||
|
|
|
|||
|
|
@ -20,10 +20,8 @@ extension DefaultsKeys {
|
|||
static let gitURL = DefaultsKey<URL?>("gitURL")
|
||||
static let gitAuthenticationMethod = DefaultsKey<String?>("gitAuthenticationMethod")
|
||||
static let gitUsername = DefaultsKey<String?>("gitUsername")
|
||||
static let gitSSHPublicKeyURL = DefaultsKey<URL?>("gitSSHPublicKeyURL")
|
||||
static let gitSSHPrivateKeyURL = DefaultsKey<URL?>("gitSSHPrivateKeyURL")
|
||||
static let gitSSHKeySource = DefaultsKey<String?>("gitSSHKeySource")
|
||||
static let gitSSHPublicKeyArmor = DefaultsKey<String?>("gitSSHPublicKeyArmor")
|
||||
static let gitSSHPrivateKeyArmor = DefaultsKey<String?>("gitSSHPrivateKeyArmor")
|
||||
static let gitSignatureName = DefaultsKey<String?>("gitSignatureName")
|
||||
static let gitSignatureEmail = DefaultsKey<String?>("gitSignatureEmail")
|
||||
|
|
|
|||
|
|
@ -15,15 +15,13 @@ class Globals {
|
|||
static let pgpPublicKeyPath = "\(documentPath)/gpg_key.pub"
|
||||
static let pgpPrivateKeyPath = "\(documentPath)/gpg_key"
|
||||
|
||||
static let gitSSHPublicKeyPath = "\(documentPath)/ssh_key.pub"
|
||||
static let gitSSHPrivateKeyPath = "\(documentPath)/ssh_key"
|
||||
static let gitSSHPublicKeyURL = URL(fileURLWithPath: gitSSHPublicKeyPath)
|
||||
static let gitSSHPrivateKeyURL = URL(fileURLWithPath: gitSSHPrivateKeyPath)
|
||||
|
||||
static let repositoryPath = "\(libraryPath)/password-store"
|
||||
static var passcodeConfiguration = PasscodeLockConfiguration()
|
||||
|
||||
static let passwordDefaultLength = ["Random": (min: 6, max: 24, def: 16),
|
||||
static let passwordDefaultLength = ["Random": (min: 4, max: 64, def: 16),
|
||||
"Apple": (min: 15, max: 15, def: 15)]
|
||||
|
||||
static let gitSignatureDefaultName = "Pass for iOS"
|
||||
|
|
|
|||
|
|
@ -64,37 +64,15 @@ class Utils {
|
|||
return randomString
|
||||
}
|
||||
|
||||
static func alert(title: String, message: String, controller: UIViewController, completion: (() -> Void)?) {
|
||||
static func alert(title: String, message: String, controller: UIViewController, handler: ((UIAlertAction) -> Void)? = nil, completion: (() -> Void)? = nil) {
|
||||
SVProgressHUD.dismiss()
|
||||
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: handler))
|
||||
controller.present(alert, animated: true, completion: completion)
|
||||
|
||||
}
|
||||
|
||||
static func removePGPKeys() {
|
||||
removeFileIfExists(atPath: Globals.pgpPublicKeyPath)
|
||||
removeFileIfExists(atPath: Globals.pgpPrivateKeyPath)
|
||||
Defaults.remove(.pgpKeySource)
|
||||
Defaults.remove(.pgpPublicKeyArmor)
|
||||
Defaults.remove(.pgpPrivateKeyArmor)
|
||||
Defaults.remove(.pgpPrivateKeyURL)
|
||||
Defaults.remove(.pgpPublicKeyURL)
|
||||
Utils.removeKeychain(name: ".pgpKeyPassphrase")
|
||||
}
|
||||
|
||||
static func removeGitSSHKeys() {
|
||||
removeFileIfExists(atPath: Globals.gitSSHPublicKeyPath)
|
||||
removeFileIfExists(atPath: Globals.gitSSHPrivateKeyPath)
|
||||
Defaults.remove(.gitSSHPublicKeyArmor)
|
||||
Defaults.remove(.gitSSHPrivateKeyArmor)
|
||||
Defaults.remove(.gitSSHPublicKeyURL)
|
||||
Defaults.remove(.gitSSHPrivateKeyURL)
|
||||
Utils.removeKeychain(name: ".gitSSHPrivateKeyPassphrase")
|
||||
}
|
||||
|
||||
static func getPasswordFromKeychain(name: String) -> String? {
|
||||
let keychain = Keychain(service: "me.mssun.passforios")
|
||||
let keychain = Keychain(service: Bundle.main.bundleIdentifier!)
|
||||
do {
|
||||
return try keychain.getString(name)
|
||||
} catch {
|
||||
|
|
@ -104,11 +82,11 @@ class Utils {
|
|||
}
|
||||
|
||||
static func addPasswordToKeychain(name: String, password: String?) {
|
||||
let keychain = Keychain(service: "me.mssun.passforios")
|
||||
let keychain = Keychain(service: Bundle.main.bundleIdentifier!)
|
||||
keychain[name] = password
|
||||
}
|
||||
static func removeKeychain(name: String) {
|
||||
let keychain = Keychain(service: "me.mssun.passforios")
|
||||
let keychain = Keychain(service: Bundle.main.bundleIdentifier!)
|
||||
do {
|
||||
try keychain.remove(name)
|
||||
} catch {
|
||||
|
|
@ -116,7 +94,7 @@ class Utils {
|
|||
}
|
||||
}
|
||||
static func removeAllKeychain() {
|
||||
let keychain = Keychain(service: "me.mssun.passforios")
|
||||
let keychain = Keychain(service: Bundle.main.bundleIdentifier!)
|
||||
do {
|
||||
try keychain.removeAll()
|
||||
} catch {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.2.6</string>
|
||||
<string>0.2.7</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class PasswordStore {
|
|||
}
|
||||
}
|
||||
|
||||
let pgp: ObjectivePGP = ObjectivePGP()
|
||||
var pgp: ObjectivePGP = ObjectivePGP()
|
||||
|
||||
var pgpKeyPassphrase: String? {
|
||||
set {
|
||||
|
|
@ -93,10 +93,10 @@ class PasswordStore {
|
|||
if FileManager.default.fileExists(atPath: storeURL.path) {
|
||||
try storeRepository = GTRepository.init(url: storeURL)
|
||||
}
|
||||
try initPGPKeys()
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
initPGPKeys()
|
||||
}
|
||||
|
||||
enum SSHKeyType {
|
||||
|
|
@ -104,24 +104,16 @@ class PasswordStore {
|
|||
}
|
||||
|
||||
public func initGitSSHKey(with armorKey: String, _ keyType: SSHKeyType) throws {
|
||||
var keyPath = ""
|
||||
switch keyType {
|
||||
case .public:
|
||||
keyPath = Globals.gitSSHPublicKeyPath
|
||||
case .secret:
|
||||
keyPath = Globals.gitSSHPrivateKeyPath
|
||||
guard keyType == .secret else {
|
||||
return
|
||||
}
|
||||
|
||||
let keyPath = Globals.gitSSHPrivateKeyPath
|
||||
try armorKey.write(toFile: keyPath, atomically: true, encoding: .ascii)
|
||||
}
|
||||
|
||||
public func initPGPKeys() {
|
||||
do {
|
||||
try initPGPKey(.public)
|
||||
try initPGPKey(.secret)
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
public func initPGPKeys() throws {
|
||||
try initPGPKey(.public)
|
||||
try initPGPKey(.secret)
|
||||
}
|
||||
|
||||
public func initPGPKey(_ keyType: PGPKeyType) throws {
|
||||
|
|
@ -143,7 +135,7 @@ class PasswordStore {
|
|||
}
|
||||
}
|
||||
|
||||
public func initPGPKey(from url: URL, keyType: PGPKeyType) throws{
|
||||
public func initPGPKey(from url: URL, keyType: PGPKeyType) throws {
|
||||
var pgpKeyLocalPath = ""
|
||||
if keyType == .public {
|
||||
pgpKeyLocalPath = Globals.pgpPublicKeyPath
|
||||
|
|
@ -692,7 +684,6 @@ class PasswordStore {
|
|||
|
||||
Utils.removeFileIfExists(atPath: Globals.pgpPublicKeyPath)
|
||||
Utils.removeFileIfExists(atPath: Globals.pgpPrivateKeyPath)
|
||||
Utils.removeFileIfExists(atPath: Globals.gitSSHPublicKeyPath)
|
||||
Utils.removeFileIfExists(atPath: Globals.gitSSHPrivateKeyPath)
|
||||
|
||||
Utils.removeAllKeychain()
|
||||
|
|
@ -787,4 +778,37 @@ class PasswordStore {
|
|||
let encryptedData = try pgp.encryptData(plainData, usingPublicKey: publicKey, armored: Defaults[.encryptInArmored])
|
||||
return encryptedData
|
||||
}
|
||||
|
||||
|
||||
|
||||
func removePGPKeys() {
|
||||
Utils.removeFileIfExists(atPath: Globals.pgpPublicKeyPath)
|
||||
Utils.removeFileIfExists(atPath: Globals.pgpPrivateKeyPath)
|
||||
Defaults.remove(.pgpKeySource)
|
||||
Defaults.remove(.pgpPublicKeyArmor)
|
||||
Defaults.remove(.pgpPrivateKeyArmor)
|
||||
Defaults.remove(.pgpPrivateKeyURL)
|
||||
Defaults.remove(.pgpPublicKeyURL)
|
||||
Utils.removeKeychain(name: ".pgpKeyPassphrase")
|
||||
pgp = ObjectivePGP()
|
||||
publicKey = nil
|
||||
privateKey = nil
|
||||
}
|
||||
|
||||
func removeGitSSHKeys() {
|
||||
Utils.removeFileIfExists(atPath: Globals.gitSSHPrivateKeyPath)
|
||||
Defaults.remove(.gitSSHPrivateKeyArmor)
|
||||
Defaults.remove(.gitSSHPrivateKeyURL)
|
||||
Utils.removeKeychain(name: ".gitSSHPrivateKeyPassphrase")
|
||||
}
|
||||
|
||||
func gitSSHKeyExists() -> Bool {
|
||||
let fm = FileManager.default
|
||||
return fm.fileExists(atPath: Globals.gitSSHPrivateKeyPath)
|
||||
}
|
||||
|
||||
func pgpKeyExists() -> Bool {
|
||||
let fm = FileManager.default
|
||||
return fm.fileExists(atPath: Globals.pgpPublicKeyPath) && fm.fileExists(atPath: Globals.pgpPrivateKeyPath)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12118" systemVersion="16F43c" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12086"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
|
@ -16,55 +16,54 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="320" height="90"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="89.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="90"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="password" textAlignment="natural" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="k0U-2N-YaX" userLabel="Password">
|
||||
<rect key="frame" x="15" y="11" width="225" height="68"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="38" id="9gX-VT-F9P"/>
|
||||
</constraints>
|
||||
<nil key="textColor"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
|
||||
<connections>
|
||||
<action selector="textFieldDidChange:" destination="KGk-i7-Jjw" eventType="editingChanged" id="U0t-2B-JxY"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SZJ-aY-45Y" userLabel="Setting">
|
||||
<rect key="frame" x="275" y="11" width="30" height="68"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="30" id="D9D-FC-ANz"/>
|
||||
</constraints>
|
||||
<inset key="contentEdgeInsets" minX="5" minY="10" maxX="5" maxY="10"/>
|
||||
<state key="normal" image="HorizontalSettings"/>
|
||||
<connections>
|
||||
<action selector="showHidePasswordSettings" destination="KGk-i7-Jjw" eventType="touchUpInside" id="3I8-S0-qlo"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hTh-ek-Xam" userLabel="Generate">
|
||||
<rect key="frame" x="245" y="11" width="30" height="68"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="30" id="l0l-7B-Tws"/>
|
||||
</constraints>
|
||||
<inset key="contentEdgeInsets" minX="5" minY="10" maxX="5" maxY="10"/>
|
||||
<state key="normal" image="Refresh"/>
|
||||
<connections>
|
||||
<action selector="generatePassword:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="M61-hs-PCP"/>
|
||||
</connections>
|
||||
</button>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="19l-R0-gP1">
|
||||
<rect key="frame" x="15" y="11" width="290" height="68"/>
|
||||
<subviews>
|
||||
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="password" textAlignment="natural" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="k0U-2N-YaX" userLabel="Password">
|
||||
<rect key="frame" x="0.0" y="0.0" width="230" height="68"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="38" id="9gX-VT-F9P"/>
|
||||
</constraints>
|
||||
<nil key="textColor"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" keyboardType="alphabet"/>
|
||||
<connections>
|
||||
<action selector="textFieldDidChange:" destination="KGk-i7-Jjw" eventType="editingChanged" id="U0t-2B-JxY"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hTh-ek-Xam" userLabel="Generate">
|
||||
<rect key="frame" x="230" y="0.0" width="30" height="68"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="30" id="l0l-7B-Tws"/>
|
||||
</constraints>
|
||||
<inset key="contentEdgeInsets" minX="5" minY="10" maxX="5" maxY="10"/>
|
||||
<state key="normal" image="Refresh"/>
|
||||
<connections>
|
||||
<action selector="generatePassword:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="M61-hs-PCP"/>
|
||||
</connections>
|
||||
</button>
|
||||
<button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SZJ-aY-45Y" userLabel="Setting">
|
||||
<rect key="frame" x="260" y="0.0" width="30" height="68"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="30" id="D9D-FC-ANz"/>
|
||||
</constraints>
|
||||
<inset key="contentEdgeInsets" minX="5" minY="10" maxX="5" maxY="10"/>
|
||||
<state key="normal" image="HorizontalSettings"/>
|
||||
<connections>
|
||||
<action selector="showHidePasswordSettings" destination="KGk-i7-Jjw" eventType="touchUpInside" id="3I8-S0-qlo"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="SZJ-aY-45Y" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="5XP-xZ-YWY"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="SZJ-aY-45Y" secondAttribute="trailing" id="5bp-bm-9vv"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="SZJ-aY-45Y" secondAttribute="bottom" id="CMF-1f-MdG"/>
|
||||
<constraint firstItem="hTh-ek-Xam" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="OjQ-mD-CWV"/>
|
||||
<constraint firstItem="SZJ-aY-45Y" firstAttribute="leading" secondItem="hTh-ek-Xam" secondAttribute="trailing" id="UlR-NB-9So"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="hTh-ek-Xam" secondAttribute="bottom" id="bvu-Q0-QAG"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="k0U-2N-YaX" secondAttribute="trailing" constant="65" id="fz0-HW-sCe"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="k0U-2N-YaX" secondAttribute="bottom" id="lRv-MC-Cru"/>
|
||||
<constraint firstItem="k0U-2N-YaX" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="sUk-sk-JLT"/>
|
||||
<constraint firstItem="k0U-2N-YaX" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" id="zGn-an-SlK"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="19l-R0-gP1" secondAttribute="bottom" id="ZtI-tq-wfu"/>
|
||||
<constraint firstItem="19l-R0-gP1" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" id="cad-hD-m5H"/>
|
||||
<constraint firstItem="19l-R0-gP1" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="ig6-lH-djx"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="19l-R0-gP1" secondAttribute="trailing" id="k4R-Fi-Hue"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12118" systemVersion="16F43c" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12086"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
<rect key="frame" x="0.0" y="0.0" width="333" height="59"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
|
||||
<rect key="frame" x="0.0" y="0.0" width="333" height="58.5"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="333" height="59"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yyr-cF-QN0">
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12118" systemVersion="16F43c" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12120" systemVersion="16G8c" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12086"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12088"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
|
|
@ -20,37 +20,37 @@
|
|||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="MwT-Jl-hhE">
|
||||
<rect key="frame" x="60.5" y="22.5" width="198.5" height="31"/>
|
||||
<rect key="frame" x="53.5" y="22.5" width="212.5" height="31"/>
|
||||
<connections>
|
||||
<action selector="handleSliderValueChange:" destination="KGk-i7-Jjw" eventType="valueChanged" id="WwM-ZE-yIB"/>
|
||||
</connections>
|
||||
</slider>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="88" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GJP-Fj-VZt" userLabel="Value">
|
||||
<rect key="frame" x="274" y="11" width="24" height="52"/>
|
||||
<rect key="frame" x="278" y="11" width="20" height="52"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="24" id="tOG-yp-eFw"/>
|
||||
<constraint firstAttribute="width" constant="20" id="tOG-yp-eFw"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="t7T-HC-hUd" userLabel="Title">
|
||||
<rect key="frame" x="15" y="11" width="30" height="52"/>
|
||||
<rect key="frame" x="15" y="11" width="26.5" height="52"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="38" id="8Tz-Qo-Mkg"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="13"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="MwT-Jl-hhE" firstAttribute="leading" secondItem="t7T-HC-hUd" secondAttribute="trailing" constant="17" id="Cc9-kV-nZf"/>
|
||||
<constraint firstItem="MwT-Jl-hhE" firstAttribute="leading" secondItem="t7T-HC-hUd" secondAttribute="trailing" constant="14" id="Cc9-kV-nZf"/>
|
||||
<constraint firstItem="t7T-HC-hUd" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" id="Kje-Zj-RaX"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="GJP-Fj-VZt" secondAttribute="trailing" constant="7" id="LjD-JH-dRT"/>
|
||||
<constraint firstItem="MwT-Jl-hhE" firstAttribute="centerY" secondItem="t7T-HC-hUd" secondAttribute="centerY" id="MHN-Vl-1le"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="GJP-Fj-VZt" secondAttribute="bottom" id="NmC-sS-9Yt"/>
|
||||
<constraint firstItem="GJP-Fj-VZt" firstAttribute="leading" secondItem="MwT-Jl-hhE" secondAttribute="trailing" constant="17" id="VAG-Y2-0Lu"/>
|
||||
<constraint firstItem="GJP-Fj-VZt" firstAttribute="leading" secondItem="MwT-Jl-hhE" secondAttribute="trailing" constant="14" id="VAG-Y2-0Lu"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="t7T-HC-hUd" secondAttribute="bottom" id="mng-Ic-Ciy"/>
|
||||
<constraint firstItem="GJP-Fj-VZt" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="oYC-wl-Lyg"/>
|
||||
<constraint firstItem="t7T-HC-hUd" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="vhu-L7-r5I"/>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue