Merge branch 'release/0.2.6'

This commit is contained in:
Bob Sun 2017-05-22 23:05:23 -07:00
commit c19d6469ea
No known key found for this signature in database
GPG key ID: 1F86BA2052FED3B4
15 changed files with 597 additions and 331 deletions

View file

@ -59,6 +59,8 @@
DCC408C71E307DBB00F29B0E /* SVProgressHUD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC408C61E307DBB00F29B0E /* SVProgressHUD.framework */; };
DCC441521E8F6C06008A90C4 /* RawPasswordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC441511E8F6C06008A90C4 /* RawPasswordViewController.swift */; };
DCC441541E916382008A90C4 /* GitSSHKeyArmorSettingTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC441531E916382008A90C4 /* GitSSHKeyArmorSettingTableViewController.swift */; };
DCD9AD131EB678500093499A /* GitCredential.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCD9AD121EB678500093499A /* GitCredential.swift */; };
DCD9AD151EB6829A0093499A /* AppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCD9AD141EB6829A0093499A /* AppError.swift */; };
DCDDEAB01E4639F300F68193 /* LabelTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DCDDEAAF1E4639F300F68193 /* LabelTableViewCell.xib */; };
DCDDEAB31E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCDDEAB11E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift */; };
DCFB779A1E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCFB77981E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift */; };
@ -142,6 +144,8 @@
DCC408C91E30BA1300F29B0E /* pass.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = pass.xcdatamodel; sourceTree = "<group>"; };
DCC441511E8F6C06008A90C4 /* RawPasswordViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RawPasswordViewController.swift; sourceTree = "<group>"; };
DCC441531E916382008A90C4 /* GitSSHKeyArmorSettingTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GitSSHKeyArmorSettingTableViewController.swift; sourceTree = "<group>"; };
DCD9AD121EB678500093499A /* GitCredential.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GitCredential.swift; path = pass/Controllers/GitCredential.swift; sourceTree = SOURCE_ROOT; };
DCD9AD141EB6829A0093499A /* AppError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppError.swift; sourceTree = "<group>"; };
DCDDEAAF1E4639F300F68193 /* LabelTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LabelTableViewCell.xib; sourceTree = "<group>"; };
DCDDEAB11E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordDetailTitleTableViewCell.swift; sourceTree = "<group>"; };
DCFB77981E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TitleTextFieldTableViewCell.swift; sourceTree = "<group>"; };
@ -238,6 +242,7 @@
DCC408A31E2FCC9E00F29B0E /* PasswordStore.swift */,
DC193FFF1E49E1A60077E0A3 /* PasscodeLockConfiguration.swift */,
DC193FFD1E49E0760077E0A3 /* PasscodeLockRepository.swift */,
DCD9AD121EB678500093499A /* GitCredential.swift */,
);
path = Models;
sourceTree = "<group>";
@ -302,6 +307,7 @@
children = (
DC917BE21E2E8231000FDF54 /* Info.plist */,
DC917BD61E2E8231000FDF54 /* AppDelegate.swift */,
DCD9AD141EB6829A0093499A /* AppError.swift */,
DC19400D1E4B3A340077E0A3 /* Models */,
DC19400C1E4B39400077E0A3 /* Controllers */,
DC19400F1E4B3A9E0077E0A3 /* Views */,
@ -526,6 +532,7 @@
files = (
DCC408A41E2FCC9E00F29B0E /* PasswordStore.swift in Sources */,
DC037CBF1E4ED4E100609409 /* TextViewTableViewCell.swift in Sources */,
DCD9AD151EB6829A0093499A /* AppError.swift in Sources */,
DCC441541E916382008A90C4 /* GitSSHKeyArmorSettingTableViewController.swift in Sources */,
DC8963C01E38EEB900828B09 /* SSHKeySettingTableViewController.swift in Sources */,
DC193FFA1E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift in Sources */,
@ -545,6 +552,7 @@
DC4914991E434600007FF592 /* PasswordDetailTableViewController.swift in Sources */,
DC962CDF1E4B62C10033B5D8 /* AboutTableViewController.swift in Sources */,
DC5734AE1E439AD400D09270 /* PasswordsViewController.swift in Sources */,
DCD9AD131EB678500093499A /* GitCredential.swift in Sources */,
DC3E64E61E656F11009A83DE /* CommitLogsTableViewController.swift in Sources */,
DC037CAA1E4B8EAE00609409 /* SpecialThanksTableViewController.swift in Sources */,
DC037CA61E4B883900609409 /* OpenSourceComponentsTableViewController.swift in Sources */,

40
pass/AppError.swift Normal file
View file

@ -0,0 +1,40 @@
//
// AppError.swift
// pass
//
// Created by Mingshen Sun on 30/4/2017.
// Copyright © 2017 Bob Sun. All rights reserved.
//
import Foundation
enum AppError: Error {
case RepositoryNotSetError
case RepositoryRemoteMasterNotFoundError
case KeyImportError
case PasswordDuplicatedError
case GitResetError
case PGPPublicKeyNotExistError
case UnknownError
}
extension AppError: LocalizedError {
public var errorDescription: String? {
switch self {
case .RepositoryNotSetError:
return "Git repository is not set."
case .RepositoryRemoteMasterNotFoundError:
return "Cannot find remote branch origin/master."
case .KeyImportError:
return "Cannot import the key."
case .PasswordDuplicatedError:
return "Cannot add the password: password duplicated."
case .GitResetError:
return "Cannot identify the latest synced commit."
case .PGPPublicKeyNotExistError:
return "PGP public key doesn't exist."
case .UnknownError:
return "Unknown error."
}
}
}

View file

@ -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="16F60a" 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="16E195" 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.666666666666664"/>
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
<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.999999999999998" width="33.333333333333336" height="20.333333333333332"/>
<rect key="frame" x="15" y="11" width="34" height="21"/>
<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.999999999999998" width="44" height="20.333333333333332"/>
<rect key="frame" x="335" y="11" width="44" height="21"/>
<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="376" height="43.666666666666664"/>
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
<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="20" y="0.0" width="356" height="43.666666666666664"/>
<rect key="frame" x="15" y="0.0" width="364" height="43"/>
<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="376" height="43.666666666666664"/>
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
<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="20" y="11.999999999999998" width="160.33333333333334" height="20.333333333333332"/>
<rect key="frame" x="15" y="11" width="161" height="21"/>
<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="318.33333333333331" y="11.999999999999998" width="57.666666666666664" height="20.333333333333332"/>
<rect key="frame" x="321" y="11" width="58" height="21"/>
<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="376" height="43.666666666666664"/>
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
<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="20" y="11.999999999999998" width="66" height="20.333333333333332"/>
<rect key="frame" x="15" y="11" width="66" height="21"/>
<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="318.33333333333331" y="11.999999999999998" width="57.666666666666664" height="20.333333333333332"/>
<rect key="frame" x="321" y="11" width="58" height="21"/>
<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="223" width="414" height="44"/>
<rect key="frame" x="0.0" y="224" 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="376" height="43.666666666666664"/>
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
<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="20" y="11.999999999999998" width="115" height="20.333333333333332"/>
<rect key="frame" x="15" y="11" width="115" height="21"/>
<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="351.66666666666669" y="11.999999999999998" width="24.333333333333332" height="20.333333333333332"/>
<rect key="frame" x="354" y="11" width="25" height="21"/>
<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="267" width="414" height="44"/>
<rect key="frame" x="0.0" y="268" 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.666666666666664"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="43"/>
<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="20" y="0.0" width="379" height="43.666666666666664"/>
<rect key="frame" x="15" y="0.0" width="384" height="43"/>
<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="347" width="414" height="44"/>
<rect key="frame" x="0.0" y="348" 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="376" height="43.666666666666664"/>
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
<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="20" y="0.0" width="356" height="43.666666666666664"/>
<rect key="frame" x="15" y="0.0" width="364" height="43"/>
<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="427" width="414" height="44"/>
<rect key="frame" x="0.0" y="428" 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="376" height="43.666666666666664"/>
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
<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="20" y="0.0" width="356" height="43.666666666666664"/>
<rect key="frame" x="15" y="0.0" width="364" height="43"/>
<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,23 +288,23 @@
<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.5"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="53"/>
<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">
<rect key="frame" x="87.333333333333343" y="10.999999999999998" width="311.66666666666663" height="14.33333333333333"/>
<rect key="frame" x="88" y="11" width="311" height="15"/>
<fontDescription key="fontDescription" name=".AppleSystemUIFont" family=".AppleSystemUIFont" pointSize="12"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" tag="202" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" preservesSuperviewLayoutMargins="YES" text="Edit password for baidu.com using Pass for iOS." textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="L1p-Dm-Mnh">
<rect key="frame" x="15" y="28.666666666666671" width="384" height="14.333333333333329"/>
<rect key="frame" x="15" y="29" width="384" height="14"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" tag="200" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" preservesSuperviewLayoutMargins="YES" text="Bob Sun" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8Dc-U9-AVf">
<rect key="frame" x="15" y="11.000000000000002" width="62.333333333333329" height="14.66666666666667"/>
<rect key="frame" x="15" y="11" width="63" height="15"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@ -348,10 +348,10 @@
<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="55.5" width="414" height="52"/>
<rect key="frame" x="0.0" y="56" 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="52"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Git Repository URL" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="EVT-VU-sCi">
@ -378,10 +378,10 @@
<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="163.5" width="414" height="52"/>
<rect key="frame" x="0.0" y="165" 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="52"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="51"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Username" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="TMg-Gk-7nG">
@ -407,10 +407,10 @@
<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="271.5" width="414" height="44"/>
<rect key="frame" x="0.0" y="274" 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="44"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Password" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LfQ-Af-j2O">
@ -420,7 +420,7 @@
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" tag="1001" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="✓" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Scc-5J-bu1">
<rect key="frame" x="23" y="11.666666666666668" width="15.666666666666664" height="21.333333333333332"/>
<rect key="frame" x="23" y="11" width="16" height="22"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="18"/>
<color key="textColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -438,10 +438,10 @@
<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="315.5" width="414" height="44"/>
<rect key="frame" x="0.0" y="318" 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="44"/>
<rect key="frame" x="0.0" y="0.0" width="367" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SSH Key" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ezz-76-a53">
@ -451,7 +451,7 @@
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" tag="1001" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="✓" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wbx-rk-i8H">
<rect key="frame" x="23" y="10.666666666666664" width="16.666666666666664" height="22"/>
<rect key="frame" x="23" y="11" width="16" height="22"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="18"/>
<color key="textColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@ -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.5"/>
<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="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.5"/>
<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="Private Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qht-RC-Yeg">
@ -916,7 +916,7 @@ Phone Support PIN #: 84719</string>
<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.5"/>
<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">
@ -950,7 +950,7 @@ Phone Support PIN #: 84719</string>
<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.5"/>
<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="Private Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="C2w-dd-roS">
@ -1056,14 +1056,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="55.5" width="414" height="44"/>
<rect key="frame" x="0.0" y="56" 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.666666666666664"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="43"/>
<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="20" y="0.0" width="379" height="43.666666666666664"/>
<rect key="frame" x="15" y="0.0" width="384" height="43"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
@ -1077,21 +1077,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="155.5" width="414" height="44"/>
<rect key="frame" x="0.0" y="157" 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="376" height="43.666666666666664"/>
<rect key="frame" x="0.0" y="0.0" width="381" height="43"/>
<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="20.000000000000007" y="11.999999999999998" width="99.666666666666671" height="20.333333333333332"/>
<rect key="frame" x="15" y="11" width="100" height="21"/>
<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="318.33333333333331" y="11.999999999999998" width="57.666666666666664" height="20.333333333333332"/>
<rect key="frame" x="321" y="11" width="58" height="21"/>
<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 +1108,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="255.5" width="414" height="44"/>
<rect key="frame" x="0.0" y="258" 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.666666666666664"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="43"/>
<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="20" y="0.0" width="379" height="43.666666666666664"/>
<rect key="frame" x="15" y="0.0" width="384" height="43"/>
<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 +1125,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="299.5" width="414" height="44"/>
<rect key="frame" x="0.0" y="302" 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.666666666666664"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="43"/>
<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="20" y="0.0" width="379" height="43.666666666666664"/>
<rect key="frame" x="15" y="0.0" width="384" height="43"/>
<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"/>
@ -1265,7 +1265,7 @@ Phone Support PIN #: 84719</string>
<scene sceneID="Jmv-A6-Wr1">
<objects>
<tableViewController id="1gA-jh-frD" customClass="PGPKeyArmorSettingTableViewController" 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="1" sectionFooterHeight="1" id="WYj-Sf-Cyc">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="1" sectionFooterHeight="1" id="WYj-Sf-Cyc">
<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"/>
@ -1276,18 +1276,18 @@ 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.66666666666666"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="169"/>
<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="20.000000000000007" y="17" width="121.66666666666667" height="17"/>
<rect key="frame" x="15" y="17" width="122" 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="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="sMx-qd-MTJ">
<rect key="frame" x="20" y="34" width="363.66666666666669" height="119"/>
<rect key="frame" x="15" y="34" width="384" height="119"/>
<autoresizingMask key="autoresizingMask"/>
<attributedString key="attributedText">
<fragment>
@ -1337,14 +1337,14 @@ 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="244" width="414" height="160"/>
<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="Lom-iT-l16" id="eya-Tv-r0q">
<rect key="frame" x="0.0" y="0.0" width="414" height="159.5"/>
<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="oyB-oI-1fS">
<rect key="frame" x="15" y="8" width="391" height="143.66666666666666"/>
<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"/>
@ -1362,19 +1362,27 @@ Cgo
</constraints>
</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"/>
<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"/>
<autoresizingMask key="autoresizingMask"/>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
<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="443" width="414" height="160"/>
<rect key="frame" x="0.0" y="489" 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.5"/>
<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="lrQ-Ln-ZOv">
<rect key="frame" x="15" y="8" width="391" height="143.66666666666666"/>
<rect key="frame" x="15" y="8" width="391" height="143"/>
<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"/>
@ -1392,6 +1400,14 @@ Cgo
</constraints>
</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"/>
<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"/>
<autoresizingMask key="autoresizingMask"/>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
@ -1415,7 +1431,10 @@ Cgo
<connections>
<outlet property="armorPrivateKeyTextView" destination="lrQ-Ln-ZOv" id="13E-xA-FHB"/>
<outlet property="armorPublicKeyTextView" destination="oyB-oI-1fS" id="pX6-9c-Z78"/>
<outlet property="scanPrivateKeyCell" destination="b0Z-rW-sAE" id="cKx-fK-Ik1"/>
<outlet property="scanPublicKeyCell" destination="F0i-XE-PGt" id="kLX-N9-E4U"/>
<segue destination="Ul9-vk-jhw" kind="unwind" identifier="savePGPKeySegue" unwindAction="savePGPKeyWithSegue:" id="Eof-7g-AlY"/>
<segue destination="LZE-gF-IcM" kind="show" identifier="showPGPScannerSegue" id="5iZ-y9-FCH"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="2Wn-7D-LLj" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -1474,18 +1493,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.66666666666666"/>
<rect key="frame" x="0.0" y="0.0" width="414" height="169"/>
<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="20.000000000000007" y="37" width="121.66666666666667" height="17"/>
<rect key="frame" x="15" y="36" width="122" 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="20" y="53.999999999999993" width="344" height="79.333333333333329"/>
<rect key="frame" x="15" y="53" width="344" height="80"/>
<autoresizingMask key="autoresizingMask"/>
<attributedString key="attributedText">
<fragment>
@ -1518,14 +1537,14 @@ Cgo
<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="244" width="414" height="160"/>
<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.5"/>
<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="143.66666666666666"/>
<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"/>
@ -1545,14 +1564,14 @@ Cgo
<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="443" width="414" height="160"/>
<rect key="frame" x="0.0" y="445" 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.5"/>
<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="23o-MP-wQY">
<rect key="frame" x="15" y="8" width="391" height="144"/>
<rect key="frame" x="15" y="8" width="391" height="143"/>
<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"/>
@ -1606,7 +1625,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.5"/>
<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="Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Hlb-Zh-ega">
@ -1639,7 +1658,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.5"/>
<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="Email" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="m25-Qy-XwU">
@ -1716,12 +1735,58 @@ Cgo
</objects>
<point key="canvasLocation" x="4967" y="5333"/>
</scene>
<!--Scanner-->
<scene sceneID="7j1-Qg-pUZ">
<objects>
<viewController id="LZE-gF-IcM" customClass="QRScannerController" customModule="pass" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="6mM-FW-piL"/>
<viewControllerLayoutGuide type="bottom" id="53A-gx-tky"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="CA8-A9-019">
<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="U8O-Md-w8e">
<rect key="frame" x="50" y="562" 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="q3X-BT-aK8"/>
</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 firstAttribute="trailingMargin" secondItem="U8O-Md-w8e" secondAttribute="trailing" constant="30" id="Sok-Wi-SXQ"/>
<constraint firstItem="U8O-Md-w8e" firstAttribute="leading" secondItem="CA8-A9-019" secondAttribute="leadingMargin" constant="30" id="opY-C9-XIS"/>
<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">
<barButtonItem key="leftBarButtonItem" systemItem="cancel" id="yma-o8-xRu">
<connections>
<segue destination="0F8-Zv-c2C" kind="unwind" unwindAction="cancelPGPScannerWithSegue:" id="q14-fu-3N4"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="scannerOutput" destination="U8O-Md-w8e" id="JTW-9y-mr6"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="I2W-rx-CxX" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="0F8-Zv-c2C" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="6122" y="4302"/>
</scene>
</scenes>
<resources>
<image name="Lock" width="25" height="25"/>
<image name="Settings" width="25" height="25"/>
</resources>
<inferredMetricsTieBreakers>
<segue reference="UfP-k3-XeR"/>
<segue reference="yyD-4H-pLE"/>
</inferredMetricsTieBreakers>
</document>

View file

@ -98,6 +98,12 @@ class BasicStaticTableViewController: UITableViewController, MFMailComposeViewCo
let subject = urlComponents.queryItems![0].value ?? ""
if MFMailComposeViewController.canSendMail() {
sendEmail(toRecipients: [urlComponents.path], subject: subject)
} else {
let email = urlComponents.path
let alertTitle = "Cannot open Mail App"
let alertMessage = "Email copied: \(email)"
Utils.copyToPasteboard(textToCopy: email)
Utils.alert(title: alertTitle, message: alertMessage, controller: self, completion: nil)
}
case "http", "https":
let svc = SFSafariViewController(url: URL(string: link)!, entersReaderIfAvailable: false)

View file

@ -16,7 +16,7 @@ class CommitLogsTableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(updateCommitLogs), name: .passwordStoreUpdated, object: nil)
commits = passwordStore.getRecentCommits(count: 20)
commits = getCommitLogs()
self.tableView.estimatedRowHeight = 50
self.tableView.rowHeight = UITableViewAutomaticDimension
}
@ -41,8 +41,17 @@ class CommitLogsTableViewController: UITableViewController {
return cell
}
func updateCommitLogs () {
commits = passwordStore.getRecentCommits(count: 20)
func updateCommitLogs() {
commits = getCommitLogs()
tableView.reloadData()
}
private func getCommitLogs() -> [GTCommit] {
do {
return try passwordStore.getRecentCommits(count: 20)
} catch {
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
return []
}
}
}

View file

@ -0,0 +1,107 @@
//
// GitCredential.swift
// pass
//
// Created by Mingshen Sun on 30/4/2017.
// Copyright © 2017 Bob Sun. All rights reserved.
//
import Foundation
import UIKit
import SwiftyUserDefaults
import ObjectiveGit
import SVProgressHUD
struct GitCredential {
var credential: Credential
enum Credential {
case http(userName: String, controller: UIViewController)
case ssh(userName: String, publicKeyFile: URL, privateKeyFile: URL, controller: UIViewController)
}
init(credential: Credential) {
self.credential = credential
}
func credentialProvider() throws -> GTCredentialProvider {
var attempts = 0
var lastPassword: String? = nil
return GTCredentialProvider { (_, _, _) -> (GTCredential?) in
var credential: GTCredential? = nil
switch self.credential {
case let .http(userName, controller):
var newPassword = Utils.getPasswordFromKeychain(name: "gitPassword")
if newPassword == nil || attempts != 0 {
if let requestedPassword = self.requestGitPassword(controller, lastPassword) {
newPassword = requestedPassword
Utils.addPasswordToKeychain(name: "gitPassword", password: newPassword)
} else {
return nil
}
}
attempts += 1
lastPassword = newPassword
credential = try? GTCredential(userName: userName, password: newPassword!)
case let .ssh(userName, publicKeyFile, privateKeyFile, controller):
var newPassword = Utils.getPasswordFromKeychain(name: "gitSSHKeyPassphrase")
if newPassword == nil || attempts != 0 {
if let requestedPassword = self.requestGitPassword(controller, lastPassword) {
newPassword = requestedPassword
Utils.addPasswordToKeychain(name: "gitSSHKeyPassphrase", password: newPassword)
} else {
return nil
}
}
attempts += 1
lastPassword = newPassword
credential = try? GTCredential(userName: userName, publicKeyURL: publicKeyFile, privateKeyURL: privateKeyFile, passphrase: newPassword!)
}
return credential
}
}
func delete() {
switch credential {
case .http:
Utils.removeKeychain(name: "gitPassword")
case .ssh:
Utils.removeKeychain(name: "gitSSHKeyPassphrase")
}
}
private func requestGitPassword(_ controller: UIViewController, _ lastPassword: String?) -> String? {
let sem = DispatchSemaphore(value: 0)
var password: String?
var message = ""
switch credential {
case .http:
message = "Please fill in the password of your Git account."
case .ssh:
message = "Please fill in the password of your SSH key."
}
DispatchQueue.main.async {
SVProgressHUD.dismiss()
let alert = UIAlertController(title: "Password", message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.addTextField(configurationHandler: {(textField: UITextField!) in
textField.text = lastPassword ?? ""
textField.isSecureTextEntry = true
})
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
password = alert.textFields!.first!.text
sem.signal()
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
password = nil
sem.signal()
})
controller.present(alert, animated: true, completion: nil)
}
let _ = sem.wait(timeout: .distantFuture)
return password
}
}

View file

@ -19,7 +19,7 @@ class GitServerSettingTableViewController: UITableViewController {
let passwordStore = PasswordStore.shared
var sshLabel: UILabel? = nil
var authenticationMethod = Defaults[.gitAuthenticationMethod]
var authenticationMethod = Defaults[.gitAuthenticationMethod] ?? "Password"
private func checkAuthenticationMethod(method: String) {
let passwordCheckView = authPasswordCell.viewWithTag(1001)!
@ -41,9 +41,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
sshLabel = authSSHKeyCell.subviews[0].subviews[0] as? UILabel
sshLabel!.isEnabled = gitSSHKeyExists()
if let sshLabel = sshLabel {
sshLabel.isEnabled = gitSSHKeyExists()
}
}
override func viewDidLoad() {
super.viewDidLoad()
@ -51,9 +51,8 @@ class GitServerSettingTableViewController: UITableViewController {
gitURLTextField.text = url.absoluteString
}
usernameTextField.text = Defaults[.gitUsername]
authenticationMethod = Defaults[.gitAuthenticationMethod]
checkAuthenticationMethod(method: authenticationMethod!)
sshLabel = authSSHKeyCell.subviews[0].subviews[0] as? UILabel
checkAuthenticationMethod(method: authenticationMethod)
authSSHKeyCell.accessoryType = .detailButton
}
@ -80,10 +79,6 @@ class GitServerSettingTableViewController: UITableViewController {
Utils.alert(title: "Cannot Save", message: "Git Server is not set.", controller: self, completion: nil)
return false
}
guard authenticationMethod != nil else {
Utils.alert(title: "Cannot Save", message: "Authentication method is not set.", controller: self, completion: nil)
return false
}
}
return true
}
@ -101,7 +96,7 @@ class GitServerSettingTableViewController: UITableViewController {
authenticationMethod = "SSH Key"
}
}
checkAuthenticationMethod(method: authenticationMethod!)
checkAuthenticationMethod(method: authenticationMethod)
tableView.deselectRow(at: indexPath, animated: true)
}
@ -163,7 +158,10 @@ class GitServerSettingTableViewController: UITableViewController {
let deleteAction = UIAlertAction(title: "Remove Git SSH Keys", style: .destructive) { _ in
Utils.removeGitSSHKeys()
Defaults[.gitSSHKeySource] = nil
self.sshLabel!.isEnabled = false
if let sshLabel = self.sshLabel {
sshLabel.isEnabled = false
self.checkAuthenticationMethod(method: "Password")
}
}
optionMenu.addAction(deleteAction)
}

View file

@ -9,19 +9,102 @@
import UIKit
import SwiftyUserDefaults
class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDelegate {
class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDelegate, QRScannerControllerDelegate {
@IBOutlet weak var armorPublicKeyTextView: UITextView!
@IBOutlet weak var armorPrivateKeyTextView: UITextView!
@IBOutlet weak var scanPublicKeyCell: UITableViewCell!
@IBOutlet weak var scanPrivateKeyCell: UITableViewCell!
var pgpPassphrase: String?
let passwordStore = PasswordStore.shared
private var recentPastedText = ""
class ScannedPGPKey {
static let maxNumberOfGif = 100
enum KeyType {
case publicKey, privateKey
}
var keyType = KeyType.publicKey
var numberOfSegments = 0
var previousSegment = ""
var key = ""
var message = ""
var hasStarted = false
var isDone = false
func reset(keytype: KeyType) {
self.keyType = keytype
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 {
let findPublic = segment.contains("-----BEGIN PGP PUBLIC KEY BLOCK-----")
let findPrivate = segment.contains("-----BEGIN PGP PRIVATE KEY BLOCK-----")
switch keyType {
case .publicKey:
if findPrivate {
message = "Please scan public key."
}
hasStarted = findPublic
case .privateKey:
if findPublic {
message = "Please scan private key."
}
hasStarted = findPrivate
}
}
guard hasStarted == true else {
return
}
// check the number of segments
numberOfSegments = numberOfSegments + 1
guard numberOfSegments <= ScannedPGPKey.maxNumberOfGif else {
key = "Too many QR codes"
return
}
// update full text and check whether we are done
key.append(segment)
if key.contains("-----END PGP PUBLIC KEY BLOCK-----") || key.contains("-----END PGP PRIVATE KEY BLOCK-----") {
isDone = true
}
// update message
message = "\(numberOfSegments) scanned QR codes."
}
}
var scanned = ScannedPGPKey()
override func viewDidLoad() {
super.viewDidLoad()
armorPublicKeyTextView.text = Defaults[.pgpPublicKeyArmor]
armorPrivateKeyTextView.text = Defaults[.pgpPrivateKeyArmor]
pgpPassphrase = passwordStore.pgpKeyPassphrase
scanPublicKeyCell?.textLabel?.text = "Scan Public Key QR Codes"
scanPublicKeyCell?.textLabel?.textColor = Globals.blue
scanPublicKeyCell?.selectionStyle = .default
scanPublicKeyCell?.accessoryType = .disclosureIndicator
scanPrivateKeyCell?.textLabel?.text = "Scan Private Key QR Codes"
scanPrivateKeyCell?.textLabel?.textColor = Globals.blue
scanPrivateKeyCell?.selectionStyle = .default
scanPrivateKeyCell?.accessoryType = .disclosureIndicator
}
private func createSavePassphraseAndSegueAlert() -> UIAlertController {
@ -79,4 +162,53 @@ class PGPKeyArmorSettingTableViewController: UITableViewController, UITextViewDe
}
return true
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedCell = tableView.cellForRow(at: indexPath)
if selectedCell == scanPublicKeyCell {
scanned.reset(keytype: ScannedPGPKey.KeyType.publicKey)
self.performSegue(withIdentifier: "showPGPScannerSegue", sender: self)
} else if selectedCell == scanPrivateKeyCell {
scanned.reset(keytype: ScannedPGPKey.KeyType.privateKey)
self.performSegue(withIdentifier: "showPGPScannerSegue", 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) {
switch scanned.keyType {
case .publicKey:
armorPublicKeyTextView.text = scanned.key
case .privateKey:
armorPrivateKeyTextView.text = scanned.key
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showPGPScannerSegue" {
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 cancelPGPScanner(segue: UIStoryboardSegue) {
}
}

View file

@ -39,22 +39,26 @@ class PGPKeySettingTableViewController: UITableViewController {
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if identifier == "savePGPKeySegue" {
guard let pgpPublicKeyURL = URL(string: pgpPublicKeyURLTextField.text!) else {
Utils.alert(title: "Cannot Save", message: "Please set Public Key URL first.", controller: self, completion: nil)
return false
}
guard let pgpPrivateKeyURL = URL(string: pgpPrivateKeyURLTextField.text!) else {
Utils.alert(title: "Cannot Save", message: "Please set Private Key URL first.", controller: self, completion: nil)
return false
}
guard pgpPublicKeyURL.scheme! == "https", pgpPrivateKeyURL.scheme! == "https" else {
Utils.alert(title: "Cannot Save Settings", message: "HTTP connection is not supported.", controller: self, completion: nil)
guard validatePGPKeyURL(input: pgpPublicKeyURLTextField.text) == true,
validatePGPKeyURL(input: pgpPrivateKeyURLTextField.text) == true else {
return false
}
}
return true
}
private func validatePGPKeyURL(input: String?) -> Bool {
guard let path = input, let url = URL(string: path) else {
Utils.alert(title: "Cannot Save PGP Key", message: "Please set PGP Key URL first.", controller: self, completion: nil)
return false
}
guard let scheme = url.scheme, scheme == "https", scheme == "https" else {
Utils.alert(title: "Cannot Save PGP Key", message: "HTTP connection is not supported.", controller: self, completion: nil)
return false
}
return true
}
@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

View file

@ -147,6 +147,8 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
self.password = try self.passwordStore.decrypt(passwordEntity: self.passwordEntity!, requestPGPKeyPassphrase: self.requestPGPKeyPassphrase)
} catch {
DispatchQueue.main.async {
// remove the wrong passphrase so that users could enter it next time
self.passwordStore.pgpKeyPassphrase = nil
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
self.navigationController!.popViewController(animated: true)

View file

@ -355,9 +355,15 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
textField.text = ""
textField.isSecureTextEntry = true
})
// hide it so that alert is on the top of the view
SVProgressHUD.dismiss()
self.present(alert, animated: true, completion: nil)
}
let _ = sem.wait(timeout: DispatchTime.distantFuture)
DispatchQueue.main.async {
// bring back
SVProgressHUD.show(withStatus: "Decrypting")
}
if Defaults[.isRememberPassphraseOn] {
self.passwordStore.pgpKeyPassphrase = passphrase
}
@ -380,7 +386,9 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
} catch {
print(error)
DispatchQueue.main.async {
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
// remove the wrong passphrase so that users could enter it next time
self.passwordStore.pgpKeyPassphrase = nil
Utils.alert(title: "Cannot Copy Password", message: error.localizedDescription, controller: self, completion: nil)
}
}
}

View file

@ -156,17 +156,19 @@ class SettingsTableViewController: UITableViewController {
touchIDTableViewCell.accessoryView = touchIDSwitch
setPGPKeyTableViewCellDetailText()
setPasswordRepositoryTableViewCellDetailText()
setTouchIDSwitch()
setPasscodeLockRepositoryTableViewCellDetailText()
setPasscodeLockTouchIDCells()
}
private func setPasscodeLockRepositoryTableViewCellDetailText() {
private func setPasscodeLockTouchIDCells() {
if PasscodeLockRepository().hasPasscode {
self.passcodeTableViewCell.detailTextLabel?.text = "On"
Globals.passcodeConfiguration.isTouchIDAllowed = true
touchIDSwitch.isOn = Defaults[.isTouchIDOn]
} else {
self.passcodeTableViewCell.detailTextLabel?.text = "Off"
touchIDSwitch.isEnabled = false
Globals.passcodeConfiguration.isTouchIDAllowed = false
Defaults[.isTouchIDOn] = false
touchIDSwitch.isOn = Defaults[.isTouchIDOn]
}
}
@ -186,19 +188,10 @@ class SettingsTableViewController: UITableViewController {
}
}
private func setTouchIDSwitch() {
if Defaults[.isTouchIDOn] {
touchIDSwitch.isOn = true
} else {
touchIDSwitch.isOn = false
}
}
func actOnPasswordStoreErasedNotification() {
setPGPKeyTableViewCellDetailText()
setPasswordRepositoryTableViewCellDetailText()
setTouchIDSwitch()
setPasscodeLockRepositoryTableViewCellDetailText()
setPasscodeLockTouchIDCells()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window, configuration: Globals.passcodeConfiguration)
@ -222,12 +215,12 @@ class SettingsTableViewController: UITableViewController {
}
func touchIDSwitchAction(uiSwitch: UISwitch) {
if uiSwitch.isOn {
Defaults[.isTouchIDOn] = true
Globals.passcodeConfiguration.isTouchIDAllowed = true
if !Globals.passcodeConfiguration.isTouchIDAllowed {
// switch off
uiSwitch.isOn = Defaults[.isTouchIDOn] // false
Utils.alert(title: "Notice", message: "Please set the passcode lock first.", controller: self, completion: nil)
} else {
Defaults[.isTouchIDOn] = false
Globals.passcodeConfiguration.isTouchIDAllowed = false
Defaults[.isTouchIDOn] = uiSwitch.isOn
}
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window, configuration: Globals.passcodeConfiguration)
@ -335,8 +328,7 @@ class SettingsTableViewController: UITableViewController {
let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let removePasscodeAction = UIAlertAction(title: "Remove Passcode", style: .destructive) { [weak self] _ in
passcodeRemoveViewController.successCallback = { _ in
self?.passcodeTableViewCell.detailTextLabel?.text = "Off"
self?.touchIDSwitch.isEnabled = false
self?.setPasscodeLockTouchIDCells()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.passcodeLockPresenter = PasscodeLockPresenter(mainWindow: appDelegate.window, configuration: Globals.passcodeConfiguration)
}
@ -359,8 +351,7 @@ class SettingsTableViewController: UITableViewController {
func setPasscodeLock() {
let passcodeSetViewController = PasscodeLockViewController(state: .set, configuration: Globals.passcodeConfiguration)
passcodeSetViewController.successCallback = { _ in
self.passcodeTableViewCell.detailTextLabel?.text = "On"
self.touchIDSwitch.isEnabled = true
self.setPasscodeLockTouchIDCells()
}
present(passcodeSetViewController, animated: true, completion: nil)
}

View file

@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.2.5</string>
<string>0.2.6</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>ITSAppUsesNonExemptEncryption</key>

View file

@ -13,99 +13,6 @@ import SwiftyUserDefaults
import ObjectiveGit
import SVProgressHUD
struct GitCredential {
var credential: Credential
enum Credential {
case http(userName: String, controller: UIViewController)
case ssh(userName: String, publicKeyFile: URL, privateKeyFile: URL, controller: UIViewController)
}
init(credential: Credential) {
self.credential = credential
}
func credentialProvider() throws -> GTCredentialProvider {
var attempts = 0
var lastPassword: String? = nil
return GTCredentialProvider { (_, _, _) -> (GTCredential?) in
var credential: GTCredential? = nil
switch self.credential {
case let .http(userName, controller):
var newPassword = Utils.getPasswordFromKeychain(name: "gitPassword")
if newPassword == nil || attempts != 0 {
if let requestedPassword = self.requestGitPassword(controller, lastPassword) {
newPassword = requestedPassword
Utils.addPasswordToKeychain(name: "gitPassword", password: newPassword)
} else {
return nil
}
}
attempts += 1
lastPassword = newPassword
credential = try? GTCredential(userName: userName, password: newPassword!)
case let .ssh(userName, publicKeyFile, privateKeyFile, controller):
var newPassword = Utils.getPasswordFromKeychain(name: "gitSSHKeyPassphrase")
if newPassword == nil || attempts != 0 {
if let requestedPassword = self.requestGitPassword(controller, lastPassword) {
newPassword = requestedPassword
Utils.addPasswordToKeychain(name: "gitSSHKeyPassphrase", password: newPassword)
} else {
return nil
}
}
attempts += 1
lastPassword = newPassword
credential = try? GTCredential(userName: userName, publicKeyURL: publicKeyFile, privateKeyURL: privateKeyFile, passphrase: newPassword!)
}
return credential
}
}
func delete() {
switch credential {
case .http:
Utils.removeKeychain(name: "gitPassword")
case .ssh:
Utils.removeKeychain(name: "gitSSHKeyPassphrase")
}
}
private func requestGitPassword(_ controller: UIViewController, _ lastPassword: String?) -> String? {
let sem = DispatchSemaphore(value: 0)
var password: String?
var message = ""
switch credential {
case .http:
message = "Please fill in the password of your Git account."
case .ssh:
message = "Please fill in the password of your SSH key."
}
DispatchQueue.main.async {
SVProgressHUD.dismiss()
let alert = UIAlertController(title: "Password", message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.addTextField(configurationHandler: {(textField: UITextField!) in
textField.text = lastPassword ?? ""
textField.isSecureTextEntry = true
})
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
password = alert.textFields!.first!.text
sem.signal()
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
password = nil
sem.signal()
})
controller.present(alert, animated: true, completion: nil)
}
let _ = sem.wait(timeout: .distantFuture)
return password
}
}
class PasswordStore {
static let shared = PasswordStore()
let storeURL = URL(fileURLWithPath: "\(Globals.repositoryPath)")
@ -223,16 +130,16 @@ class PasswordStore {
let keyPath = Globals.pgpPublicKeyPath
self.publicKey = importKey(from: keyPath)
if self.publicKey == nil {
throw NSError(domain: "me.mssun.pass.error", code: 2, userInfo: [NSLocalizedDescriptionKey: "Cannot import the public PGP key."])
throw AppError.KeyImportError
}
case .secret:
let keyPath = Globals.pgpPrivateKeyPath
self.privateKey = importKey(from: keyPath)
if self.privateKey == nil {
throw NSError(domain: "me.mssun.pass.error", code: 2, userInfo: [NSLocalizedDescriptionKey: "Cannot import the private PGP key."])
throw AppError.KeyImportError
}
default:
throw NSError(domain: "me.mssun.pass.error", code: 2, userInfo: [NSLocalizedDescriptionKey: "Cannot import key: unknown PGP key type."])
throw AppError.UnknownError
}
}
@ -329,9 +236,7 @@ class PasswordStore {
Utils.removeFileIfExists(at: tempStoreURL)
do {
let credentialProvider = try credential.credentialProvider()
let options: [String: Any] = [
GTRepositoryCloneOptionsCredentialProvider: credentialProvider,
]
let options = [GTRepositoryCloneOptionsCredentialProvider: credentialProvider]
storeRepository = try GTRepository.clone(from: remoteRepoURL, toWorkingDirectory: tempStoreURL, options: options, transferProgressBlock:transferProgressBlock)
let fm = FileManager.default
if fm.fileExists(atPath: storeURL.path) {
@ -352,16 +257,14 @@ class PasswordStore {
}
func pullRepository(credential: GitCredential, transferProgressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void) throws {
if storeRepository == nil {
throw NSError(domain: "me.mssun.pass.error", code: 1, userInfo: [NSLocalizedDescriptionKey: "Git Repository is not set."])
guard let storeRepository = storeRepository else {
throw AppError.RepositoryNotSetError
}
do {
let credentialProvider = try credential.credentialProvider()
let options: [String: Any] = [
GTRepositoryRemoteOptionsCredentialProvider: credentialProvider
]
let remote = try GTRemote(name: "origin", in: storeRepository!)
try storeRepository!.pull((storeRepository?.currentBranch())!, from: remote, withOptions: options, progress: transferProgressBlock)
let options = [GTRepositoryRemoteOptionsCredentialProvider: credentialProvider]
let remote = try GTRemote(name: "origin", in: storeRepository)
try storeRepository.pull(storeRepository.currentBranch(), from: remote, withOptions: options, progress: transferProgressBlock)
} catch {
credential.delete()
throw(error)
@ -429,21 +332,18 @@ class PasswordStore {
}
}
func getRecentCommits(count: Int) -> [GTCommit] {
guard storeRepository != nil else {
func getRecentCommits(count: Int) throws -> [GTCommit] {
guard let storeRepository = storeRepository else {
return []
}
var commits = [GTCommit]()
do {
let enumerator = try GTEnumerator(repository: storeRepository!)
try enumerator.pushSHA(storeRepository!.headReference().targetOID.sha!)
for _ in 0 ..< count {
let commit = try enumerator.nextObject(withSuccess: nil)
commits.append(commit)
}
} catch {
print(error)
return commits
let enumerator = try GTEnumerator(repository: storeRepository)
if let sha = try storeRepository.headReference().targetOID.sha {
try enumerator.pushSHA(sha)
}
for _ in 0 ..< count {
let commit = try enumerator.nextObject(withSuccess: nil)
commits.append(commit)
}
return commits
}
@ -464,7 +364,6 @@ class PasswordStore {
do {
if !withDir {
passwordEntityFetch.predicate = NSPredicate(format: "isDir = false")
}
let fetchedPasswordEntities = try context.fetch(passwordEntityFetch) as! [PasswordEntity]
return fetchedPasswordEntities.sorted { $0.name!.caseInsensitiveCompare($1.name!) == .orderedAscending }
@ -511,11 +410,14 @@ class PasswordStore {
func getLatestUpdateInfo(filename: String) -> String {
guard let blameHunks = try? storeRepository?.blame(withFile: filename, options: nil).hunks,
let latestCommitTime = blameHunks?.map({
guard let storeRepository = storeRepository else {
return "Unknown"
}
guard let blameHunks = try? storeRepository.blame(withFile: filename, options: nil).hunks,
let latestCommitTime = blameHunks.map({
$0.finalSignature?.time?.timeIntervalSince1970 ?? 0
}).max() else {
return "unknown"
return "Unknown"
}
let lastCommitDate = Date(timeIntervalSince1970: latestCommitTime)
let currentDate = Date()
@ -528,7 +430,7 @@ class PasswordStore {
dateComponentsFormatter.unitsStyle = .full
dateComponentsFormatter.maximumUnitCount = 2
dateComponentsFormatter.includesApproximationPhrase = true
autoFormattedDifference = (dateComponentsFormatter.string(from: diffDate)?.appending(" ago"))!
autoFormattedDifference = dateComponentsFormatter.string(from: diffDate)!.appending(" ago")
}
return autoFormattedDifference
}
@ -537,21 +439,23 @@ class PasswordStore {
}
private func gitAdd(path: String) throws {
if let repo = storeRepository {
try repo.index().addFile(path)
try repo.index().write()
guard let storeRepository = storeRepository else {
throw AppError.RepositoryNotSetError
}
try storeRepository.index().addFile(path)
try storeRepository.index().write()
}
private func gitRm(path: String) throws {
if let repo = storeRepository {
if FileManager.default.fileExists(atPath: storeURL.appendingPathComponent(path).path) {
try FileManager.default.removeItem(at: storeURL.appendingPathComponent(path))
}
try repo.index().removeFile(path)
try repo.index().write()
guard let storeRepository = storeRepository else {
throw AppError.RepositoryNotSetError
}
let url = storeURL.appendingPathComponent(path)
if FileManager.default.fileExists(atPath: url.path) {
try FileManager.default.removeItem(at: url)
}
try storeRepository.index().removeFile(path)
try storeRepository.index().write()
}
private func deleteDirectoryTree(at url: URL) throws {
@ -571,54 +475,52 @@ class PasswordStore {
}
private func gitMv(from: String, to: String) throws {
let fromURL = storeURL.appendingPathComponent(from)
let toURL = storeURL.appendingPathComponent(to)
let fm = FileManager.default
do {
guard fm.fileExists(atPath: storeURL.appendingPathComponent(from).path) else {
print("\(from) not exist")
return
}
try fm.moveItem(at: storeURL.appendingPathComponent(from), to: storeURL.appendingPathComponent(to))
} catch {
print(error)
guard fm.fileExists(atPath: fromURL.path) else {
print("\(from) not exist")
return
}
try fm.moveItem(at: fromURL, to: toURL)
try gitAdd(path: to)
try gitRm(path: from)
}
private func gitCommit(message: String) throws -> GTCommit? {
if let repo = storeRepository {
let newTree = try repo.index().writeTree()
let headReference = try repo.headReference()
let commitEnum = try GTEnumerator(repository: repo)
try commitEnum.pushSHA(headReference.targetOID.sha!)
let parent = commitEnum.nextObject() as! GTCommit
let signature = gitSignatureForNow
let commit = try repo.createCommit(with: newTree, message: message, author: signature, committer: signature, parents: [parent], updatingReferenceNamed: headReference.name)
return commit
guard let storeRepository = storeRepository else {
throw AppError.RepositoryNotSetError
}
return nil
let newTree = try storeRepository.index().writeTree()
let headReference = try storeRepository.headReference()
let commitEnum = try GTEnumerator(repository: storeRepository)
try commitEnum.pushSHA(headReference.targetOID.sha!)
let parent = commitEnum.nextObject() as! GTCommit
let signature = gitSignatureForNow
let commit = try storeRepository.createCommit(with: newTree, message: message, author: signature, committer: signature, parents: [parent], updatingReferenceNamed: headReference.name)
return commit
}
private func getLocalBranch(withName branchName: String) -> GTBranch? {
do {
let reference = GTBranch.localNamePrefix().appending(branchName)
let branches = try storeRepository!.branches(withPrefix: reference)
return branches[0]
} catch {
print(error)
private func getLocalBranch(withName branchName: String) throws -> GTBranch? {
guard let storeRepository = storeRepository else {
throw AppError.RepositoryNotSetError
}
return nil
let reference = GTBranch.localNamePrefix().appending(branchName)
let branches = try storeRepository.branches(withPrefix: reference)
return branches.first
}
func pushRepository(credential: GitCredential, transferProgressBlock: @escaping (UInt32, UInt32, Int, UnsafeMutablePointer<ObjCBool>) -> Void) throws {
guard let storeRepository = storeRepository else {
throw AppError.RepositoryNotSetError
}
do {
let credentialProvider = try credential.credentialProvider()
let options: [String: Any] = [
GTRepositoryRemoteOptionsCredentialProvider: credentialProvider,
]
let masterBranch = getLocalBranch(withName: "master")!
let remote = try GTRemote(name: "origin", in: storeRepository!)
try storeRepository?.push(masterBranch, to: remote, withOptions: options, progress: transferProgressBlock)
let options = [GTRepositoryRemoteOptionsCredentialProvider: credentialProvider]
if let masterBranch = try getLocalBranch(withName: "master") {
let remote = try GTRemote(name: "origin", in: storeRepository)
try storeRepository.push(masterBranch, to: remote, withOptions: options, progress: transferProgressBlock)
}
} catch {
credential.delete()
throw(error)
@ -627,7 +529,7 @@ class PasswordStore {
private func addPasswordEntities(password: Password) throws -> PasswordEntity? {
guard !passwordExisted(password: password) else {
throw NSError(domain: "me.mssun.pass.error", code: 2, userInfo: [NSLocalizedDescriptionKey: "Cannot add password: password duplicated."])
throw AppError.PasswordDuplicatedError
}
var passwordURL = password.url!
@ -726,7 +628,6 @@ class PasswordStore {
private func deletePasswordEntities(passwordEntity: PasswordEntity) throws {
var current: PasswordEntity? = passwordEntity
print(passwordEntity.path!)
while current != nil && (current!.children!.count == 0 || !current!.isDir) {
let parent = current!.parent
self.context.delete(current!)
@ -761,13 +662,13 @@ class PasswordStore {
}
func updateImage(passwordEntity: PasswordEntity, image: Data?) {
if image == nil {
guard let image = image else {
return
}
let privateMOC = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
privateMOC.parent = context
privateMOC.perform {
passwordEntity.image = NSData(data: image!)
passwordEntity.image = NSData(data: image)
do {
try privateMOC.save()
self.context.performAndWait {
@ -796,7 +697,6 @@ class PasswordStore {
Utils.removeAllKeychain()
deleteCoreData(entityName: "PasswordEntity")
Defaults.removeAll()
@ -808,6 +708,9 @@ class PasswordStore {
// return the number of discarded commits
func reset() throws -> Int {
guard let storeRepository = storeRepository else {
throw AppError.RepositoryNotSetError
}
// get a list of local commits
if let localCommits = try getLocalCommits(),
localCommits.count > 0 {
@ -815,9 +718,9 @@ class PasswordStore {
guard let firstLocalCommit = localCommits.last,
firstLocalCommit.parents.count == 1,
let newHead = firstLocalCommit.parents.first else {
throw NSError(domain: "me.mssun.pass.error", code: 1, userInfo: [NSLocalizedDescriptionKey: "Cannot decide how to reset."])
throw AppError.GitResetError
}
try self.storeRepository?.reset(to: newHead, resetType: GTRepositoryResetType.hard)
try storeRepository.reset(to: newHead, resetType: .hard)
self.setAllSynced()
self.updatePasswordEntityCoreData()
@ -843,24 +746,28 @@ class PasswordStore {
}
private func getLocalCommits() throws -> [GTCommit]? {
// get the remote origin/master branch
guard let remoteBranches = try storeRepository?.remoteBranches(),
let index = remoteBranches.index(where: { $0.shortName == "master" })
else {
throw NSError(domain: "me.mssun.pass.error", code: 1, userInfo: [NSLocalizedDescriptionKey: "Cannot find remote branch origin/master."])
guard let storeRepository = storeRepository else {
throw AppError.RepositoryNotSetError
}
// get the remote origin/master branch
guard let index = try storeRepository.remoteBranches().index(where: { $0.shortName == "master" }) else {
throw AppError.RepositoryRemoteMasterNotFoundError
}
let remoteMasterBranch = try storeRepository.remoteBranches()[index]
// check oid before calling localCommitsRelative
guard remoteMasterBranch.oid != nil else {
throw AppError.RepositoryRemoteMasterNotFoundError
}
let remoteMasterBranch = remoteBranches[index]
//print("remoteMasterBranch \(remoteMasterBranch)")
// get a list of local commits
return try storeRepository?.localCommitsRelative(toRemoteBranch: remoteMasterBranch)
return try storeRepository.localCommitsRelative(toRemoteBranch: remoteMasterBranch)
}
func decrypt(passwordEntity: PasswordEntity, requestPGPKeyPassphrase: () -> String) throws -> Password? {
var password: Password?
let encryptedDataPath = URL(fileURLWithPath: "\(Globals.repositoryPath)/\(passwordEntity.path!)")
let encryptedDataPath = storeURL.appendingPathComponent(passwordEntity.path!)
let encryptedData = try Data(contentsOf: encryptedDataPath)
var passphrase = self.pgpKeyPassphrase
if passphrase == nil {
@ -869,14 +776,15 @@ class PasswordStore {
let decryptedData = try PasswordStore.shared.pgp.decryptData(encryptedData, passphrase: passphrase)
let plainText = String(data: decryptedData, encoding: .utf8) ?? ""
let escapedPath = passwordEntity.path!.stringByAddingPercentEncodingForRFC3986() ?? ""
password = Password(name: passwordEntity.name!, url: URL(string: escapedPath), plainText: plainText)
return password
return Password(name: passwordEntity.name!, url: URL(string: escapedPath), plainText: plainText)
}
func encrypt(password: Password) throws -> Data {
guard let publicKey = pgp.getKeysOf(.public).first else {
throw AppError.PGPPublicKeyNotExistError
}
let plainData = password.getPlainData()
let pgp = PasswordStore.shared.pgp
let encryptedData = try pgp.encryptData(plainData, usingPublicKey: pgp.getKeysOf(.public)[0], armored: Defaults[.encryptInArmored])
let encryptedData = try pgp.encryptData(plainData, usingPublicKey: publicKey, armored: Defaults[.encryptInArmored])
return encryptedData
}
}

View file

@ -62,9 +62,11 @@ class LabelTableViewCell: UITableViewCell {
case "url":
type = .URL
contentLabel.text = content
contentLabel.font = UIFont.systemFont(ofSize: contentLabel.font.pointSize)
default:
type = .other
contentLabel.text = content
contentLabel.font = UIFont.systemFont(ofSize: contentLabel.font.pointSize)
}
updateButtons()
}
@ -75,21 +77,6 @@ class LabelTableViewCell: UITableViewCell {
return true
}
}
override func awakeFromNib() {
super.awakeFromNib()
}
override func layoutSubviews() {
super.layoutSubviews()
if buttons != nil {
self.accessoryView = buttons
}
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
switch type {
@ -208,5 +195,6 @@ class LabelTableViewCell: UITableViewCell {
passwordDisplayButton = nil
buttons = nil
}
self.accessoryView = buttons
}
}