Support ASCII-armored and iTunes uploaded SSH key
This commit is contained in:
parent
894a6cc54c
commit
97d66a8acc
11 changed files with 487 additions and 113 deletions
|
|
@ -54,6 +54,7 @@
|
|||
DCC408A41E2FCC9E00F29B0E /* PasswordStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC408A31E2FCC9E00F29B0E /* PasswordStore.swift */; };
|
||||
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 */; };
|
||||
DCDDEAB01E4639F300F68193 /* LabelTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DCDDEAAF1E4639F300F68193 /* LabelTableViewCell.xib */; };
|
||||
DCDDEAB31E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCDDEAB11E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift */; };
|
||||
DCE6C2671E71261C003038C6 /* PasswordWithFolderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCE6C2651E71261C003038C6 /* PasswordWithFolderTableViewCell.swift */; };
|
||||
|
|
@ -134,6 +135,7 @@
|
|||
DCC408C61E307DBB00F29B0E /* SVProgressHUD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SVProgressHUD.framework; path = Carthage/Build/iOS/SVProgressHUD.framework; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
DCE6C2651E71261C003038C6 /* PasswordWithFolderTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordWithFolderTableViewCell.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -216,6 +218,7 @@
|
|||
DCAAF7441E2FA66800AB94BC /* SettingsTableViewController.swift */,
|
||||
DC037CA91E4B8EAE00609409 /* SpecialThanksTableViewController.swift */,
|
||||
DC8963BF1E38EEB900828B09 /* SSHKeySettingTableViewController.swift */,
|
||||
DCC441531E916382008A90C4 /* GitSSHKeyArmorSettingTableViewController.swift */,
|
||||
);
|
||||
path = Controllers;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -518,6 +521,7 @@
|
|||
files = (
|
||||
DCC408A41E2FCC9E00F29B0E /* PasswordStore.swift in Sources */,
|
||||
DC037CBF1E4ED4E100609409 /* TextViewTableViewCell.swift in Sources */,
|
||||
DCC441541E916382008A90C4 /* GitSSHKeyArmorSettingTableViewController.swift in Sources */,
|
||||
DC8963C01E38EEB900828B09 /* SSHKeySettingTableViewController.swift in Sources */,
|
||||
DC193FFA1E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift in Sources */,
|
||||
DCFB77AB1E503729008DE471 /* ContentTableViewCell.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -477,10 +477,11 @@
|
|||
<connections>
|
||||
<outlet property="authPasswordCell" destination="KrP-nb-haa" id="zjH-sg-dfJ"/>
|
||||
<outlet property="authSSHKeyCell" destination="Qmt-bo-CuJ" id="11L-Tt-MgM"/>
|
||||
<outlet property="gitRepositoryURLTextField" destination="EVT-VU-sCi" id="2EH-Uq-tbU"/>
|
||||
<outlet property="gitURLTextField" destination="EVT-VU-sCi" id="XdU-3l-Nsv"/>
|
||||
<outlet property="usernameTextField" destination="TMg-Gk-7nG" id="htL-4C-WJF"/>
|
||||
<segue destination="7K9-cE-9qq" kind="unwind" identifier="saveGitServerSettingSegue" unwindAction="saveGitServerSettingWithSegue:" id="5UN-sC-xCA"/>
|
||||
<segue destination="hqC-Ic-NMi" kind="show" identifier="showSSHKeySettingSegue" id="AP7-FV-2Ow"/>
|
||||
<segue destination="hqC-Ic-NMi" kind="show" identifier="setGitSSHKeyByURLSegue" id="AP7-FV-2Ow"/>
|
||||
<segue destination="WgM-cY-mig" kind="show" identifier="setGitSSHKeyByArmorSegue" id="HLm-0q-hUg"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="7c1-c7-Qyp" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
|
|
@ -752,7 +753,7 @@
|
|||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3dt-Ph-4As">
|
||||
<rect key="frame" x="20" y="4" width="374" height="732"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<mutableString key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.</mutableString>
|
||||
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.</string>
|
||||
<fontDescription key="fontDescription" name="Courier" family="Courier" pointSize="14"/>
|
||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||
</textView>
|
||||
|
|
@ -892,36 +893,6 @@
|
|||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="passphrase" rowHeight="52" id="yER-vT-YTO">
|
||||
<rect key="frame" x="0.0" y="139" width="414" height="52"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="yER-vT-YTO" id="Mip-zw-xLu">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="51.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Passphrase" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Rnj-2x-ksO">
|
||||
<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="Passphrase" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="4oZ-lc-EFS">
|
||||
<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" secureTextEntry="YES"/>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="Rnj-2x-ksO" firstAttribute="leading" secondItem="Mip-zw-xLu" secondAttribute="leadingMargin" constant="7" id="B0m-eX-UKn"/>
|
||||
<constraint firstItem="4oZ-lc-EFS" firstAttribute="top" secondItem="Rnj-2x-ksO" secondAttribute="bottom" id="V7l-fu-KnP"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="Rnj-2x-ksO" secondAttribute="trailing" id="nEm-LM-Uwg"/>
|
||||
<constraint firstAttribute="topMargin" secondItem="Rnj-2x-ksO" secondAttribute="top" id="nPH-l3-bRA"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="4oZ-lc-EFS" secondAttribute="trailing" id="uIe-w7-hcX"/>
|
||||
<constraint firstItem="4oZ-lc-EFS" firstAttribute="leading" secondItem="Rnj-2x-ksO" secondAttribute="leading" id="vEc-EI-F0z"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</cells>
|
||||
</tableViewSection>
|
||||
</sections>
|
||||
|
|
@ -931,14 +902,13 @@
|
|||
</connections>
|
||||
</tableView>
|
||||
<connections>
|
||||
<outlet property="passphraseTextField" destination="4oZ-lc-EFS" id="dtf-H3-gBh"/>
|
||||
<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"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="5132" y="2893"/>
|
||||
<point key="canvasLocation" x="7433" y="2204"/>
|
||||
</scene>
|
||||
<!--General Settings Table View Controller-->
|
||||
<scene sceneID="fho-xr-1Ah">
|
||||
|
|
@ -1371,7 +1341,7 @@ pfZ36xQbOAQYKKf6ZTT5R/Y=
|
|||
<placeholder placeholderIdentifier="IBFirstResponder" id="2Wn-7D-LLj" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
<exit id="Ul9-vk-jhw" userLabel="Exit" sceneMemberID="exit"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="6039.130434782609" y="4307.608695652174"/>
|
||||
<point key="canvasLocation" x="7094" y="4030"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="m18-ch-m92">
|
||||
|
|
@ -1409,6 +1379,200 @@ pfZ36xQbOAQYKKf6ZTT5R/Y=
|
|||
</objects>
|
||||
<point key="canvasLocation" x="6720" y="-24"/>
|
||||
</scene>
|
||||
<!--GitSSH Key Armor Setting Table View Controller-->
|
||||
<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="18" 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"/>
|
||||
<sections>
|
||||
<tableViewSection id="HgL-ju-8xi">
|
||||
<cells>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="pgpKeyURLTableViewCell" rowHeight="170" id="EMz-nP-2Om">
|
||||
<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.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<textView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" bounces="NO" scrollEnabled="NO" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" delaysContentTouches="NO" canCancelContentTouches="NO" bouncesZoom="NO" editable="NO" usesAttributedText="YES" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vkU-ka-wAm">
|
||||
<rect key="frame" x="15" y="22" width="391" height="146.66666666666666"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<attributedString key="attributedText">
|
||||
<fragment>
|
||||
<string key="content">ASCII-armored key format similar to uuencoded documents rather than binary format.
|
||||
|
||||
</string>
|
||||
<attributes>
|
||||
<color key="NSColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<font key="NSFont" size="14" name=".AppleSystemUIFont"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
<fragment>
|
||||
<string key="content"> $ cat ~/.ssh/id_rsa.pub
|
||||
$ cat ~/.ssh/id_rsa</string>
|
||||
<attributes>
|
||||
<color key="NSColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<font key="NSFont" size="13" name="Menlo-Regular"/>
|
||||
<paragraphStyle key="NSParagraphStyle" alignment="left" lineBreakMode="wordWrapping" baseWritingDirection="natural" tighteningFactorForTruncation="0.0"/>
|
||||
</attributes>
|
||||
</fragment>
|
||||
</attributedString>
|
||||
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no"/>
|
||||
</textView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ASCII-Armor Keys" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HIF-Zn-aBt">
|
||||
<rect key="frame" x="15" y="8" width="391" height="21"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="21" id="Sh8-Aj-s7i"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="HIF-Zn-aBt" firstAttribute="leading" secondItem="XW5-mL-PRC" secondAttribute="leadingMargin" constant="7" id="2fZ-Tu-6jx"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="vkU-ka-wAm" secondAttribute="trailing" id="I1w-xW-439"/>
|
||||
<constraint firstItem="vkU-ka-wAm" firstAttribute="top" secondItem="HIF-Zn-aBt" secondAttribute="bottom" constant="-7" id="QEU-iz-4AS"/>
|
||||
<constraint firstItem="vkU-ka-wAm" firstAttribute="leading" secondItem="XW5-mL-PRC" secondAttribute="leadingMargin" constant="7" id="UEQ-vW-A0q"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="HIF-Zn-aBt" secondAttribute="trailing" id="h7g-Ft-YVp"/>
|
||||
<constraint firstAttribute="bottomMargin" secondItem="vkU-ka-wAm" secondAttribute="bottom" constant="-7" id="lHv-ws-fct"/>
|
||||
<constraint firstAttribute="topMargin" secondItem="HIF-Zn-aBt" secondAttribute="top" id="uqY-0s-I2H"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
</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="261" 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"/>
|
||||
<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"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<string key="text">-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQENBFiiqFoBCACzvPOW+J1RlQOI9oB7Iwuk92rzpkKGC8tiwo4otHMc3rxmzYlG
|
||||
gEdHmSi6Ix0+hYZ2vSWJamPQl9WUiYSBQmkVwoqiwXNWcqRePOylcqsj58owIxZt
|
||||
23nXUIG78t+5BatoWyl9/qXsMUMSink7RAlOnjCyvoSJw9yzUVeWn723rvAr7ypV
|
||||
yqjce4gOGIfGT8PpGXThDQjvg4gM+wxUD3+oNhW50Qb+crMsefxwEoGXbCA4+6ZO
|
||||
nJGy2MhRr4FkXwNAAcvTvTmYXQfH8Q8xCtgl4PyxQA4OAeoEfxl5FOuOGIbNKgMs
|
||||
133n2oue5dy3YERN2t9/Di8Iov4Bsc+nj6+vABEBAAG0E1Bhc3MgZm9yIGlPUyAo
|
||||
RGVtbymJATcEEwEKACEFAliiqFoCGwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AA
|
||||
CgkQl/oT92AAdt0TqAgAlTsGLTe9+qY9pfyBVpDk+z1SC9kaOYsvoj7hSWVOXxwP
|
||||
yn4jxjHUr1C9fyaZqP9K4yIdl9jsGBkpaR6lhnUm9x5RO5gEAAAaLhx3ZgE7/XQg
|
||||
y7WHibxsnLaTEMVnNh8BJzQveYSqO8frBkQofj0K9LNiqWHhcllKKNkVHqyeMRII
|
||||
KYPOXvDnsnKqywapu5VyyErMnPqq6h7i3Z7+xDfVk8iUew9i0LR/QEmJO7iTH98C
|
||||
DczQo+4VnflBIHiNcMaXQqC2Li5rS+O3a9hq5V/gJwBtIx1iXvDaRATH4aUANxTZ
|
||||
POHVLwxBuTwilhnEaAPGkGu+oG1XF+RWOyrGYluWc7kBDQRYoqhaAQgAoh9B+sY1
|
||||
jZZgnqP11a9wkjom2DcBJLreYNzgBFYhUcmxtq+ZWyorPFzMJpbIjzMGRiGWFIus
|
||||
DE5D5LZdAvkINWKsbVN6Y3OI6Tj+/O45SuJ7EusG8Z1bwmjJqHy/Y//Fk0rF6ZFs
|
||||
g0+p12Xzr5k8sMKUU4I5T4DNrsS+mwnOPItC7NGawkArPD7Mew0ma+Luv7b3g0gA
|
||||
DuofvxKiN0jq6W9QPUNRY4BKm+Y03CdZNXyMDs/NTguDdfarawTIAIlJOSg5rV7S
|
||||
74v73dtZkB5LySX1rBomRb5zkCg6/Ygap4RO1aO9gbXyPmc2lUQSBAJCS9d8h0qD
|
||||
sNGembqhGDwHpQARAQABiQEfBBgBCgAJBQJYoqhaAhsMAAoJEJf6E/dgAHbdKl4H
|
||||
/A/Q+hOh40M2B6Sh/Rsus+k1VL51+UXVJRyiNiqvofamufF5ULfeq3Pt5HfqpCsF
|
||||
/A7iRP0MuanKcZbLDjDv6wWDuRvW9Kwn5qjbb6iBPh+wfyReqNMWGksJTyap0SNR
|
||||
+Mn+sjbxGkUPjzVdRdqtw64R3DLW6SpMNIUVC6paazCViEtHsSauWwP/0+DRA/6j
|
||||
xBHSAr0UaLsRTHleOSWV6ABrh9skJRWLBcOoi5pxotBs/3BmjqERQf9bwmmyxj2K
|
||||
cE60Muv6qY4/KCQqPKhyFjJwXhS/e7BwxHEt1SbUb1aC4lH5UrbW9KYLu5lHJRdY
|
||||
pfZ36xQbOAQYKKf6ZTT5R/Y=
|
||||
=2pJ8
|
||||
-----END PGP PUBLIC KEY BLOCK-----</string>
|
||||
<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="477" 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"/>
|
||||
<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"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<string key="text">-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQENBFiiqFoBCACzvPOW+J1RlQOI9oB7Iwuk92rzpkKGC8tiwo4otHMc3rxmzYlG
|
||||
gEdHmSi6Ix0+hYZ2vSWJamPQl9WUiYSBQmkVwoqiwXNWcqRePOylcqsj58owIxZt
|
||||
23nXUIG78t+5BatoWyl9/qXsMUMSink7RAlOnjCyvoSJw9yzUVeWn723rvAr7ypV
|
||||
yqjce4gOGIfGT8PpGXThDQjvg4gM+wxUD3+oNhW50Qb+crMsefxwEoGXbCA4+6ZO
|
||||
nJGy2MhRr4FkXwNAAcvTvTmYXQfH8Q8xCtgl4PyxQA4OAeoEfxl5FOuOGIbNKgMs
|
||||
133n2oue5dy3YERN2t9/Di8Iov4Bsc+nj6+vABEBAAG0E1Bhc3MgZm9yIGlPUyAo
|
||||
RGVtbymJATcEEwEKACEFAliiqFoCGwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AA
|
||||
CgkQl/oT92AAdt0TqAgAlTsGLTe9+qY9pfyBVpDk+z1SC9kaOYsvoj7hSWVOXxwP
|
||||
yn4jxjHUr1C9fyaZqP9K4yIdl9jsGBkpaR6lhnUm9x5RO5gEAAAaLhx3ZgE7/XQg
|
||||
y7WHibxsnLaTEMVnNh8BJzQveYSqO8frBkQofj0K9LNiqWHhcllKKNkVHqyeMRII
|
||||
KYPOXvDnsnKqywapu5VyyErMnPqq6h7i3Z7+xDfVk8iUew9i0LR/QEmJO7iTH98C
|
||||
DczQo+4VnflBIHiNcMaXQqC2Li5rS+O3a9hq5V/gJwBtIx1iXvDaRATH4aUANxTZ
|
||||
POHVLwxBuTwilhnEaAPGkGu+oG1XF+RWOyrGYluWc7kBDQRYoqhaAQgAoh9B+sY1
|
||||
jZZgnqP11a9wkjom2DcBJLreYNzgBFYhUcmxtq+ZWyorPFzMJpbIjzMGRiGWFIus
|
||||
DE5D5LZdAvkINWKsbVN6Y3OI6Tj+/O45SuJ7EusG8Z1bwmjJqHy/Y//Fk0rF6ZFs
|
||||
g0+p12Xzr5k8sMKUU4I5T4DNrsS+mwnOPItC7NGawkArPD7Mew0ma+Luv7b3g0gA
|
||||
DuofvxKiN0jq6W9QPUNRY4BKm+Y03CdZNXyMDs/NTguDdfarawTIAIlJOSg5rV7S
|
||||
74v73dtZkB5LySX1rBomRb5zkCg6/Ygap4RO1aO9gbXyPmc2lUQSBAJCS9d8h0qD
|
||||
sNGembqhGDwHpQARAQABiQEfBBgBCgAJBQJYoqhaAhsMAAoJEJf6E/dgAHbdKl4H
|
||||
/A/Q+hOh40M2B6Sh/Rsus+k1VL51+UXVJRyiNiqvofamufF5ULfeq3Pt5HfqpCsF
|
||||
/A7iRP0MuanKcZbLDjDv6wWDuRvW9Kwn5qjbb6iBPh+wfyReqNMWGksJTyap0SNR
|
||||
+Mn+sjbxGkUPjzVdRdqtw64R3DLW6SpMNIUVC6paazCViEtHsSauWwP/0+DRA/6j
|
||||
xBHSAr0UaLsRTHleOSWV6ABrh9skJRWLBcOoi5pxotBs/3BmjqERQf9bwmmyxj2K
|
||||
cE60Muv6qY4/KCQqPKhyFjJwXhS/e7BwxHEt1SbUb1aC4lH5UrbW9KYLu5lHJRdY
|
||||
pfZ36xQbOAQYKKf6ZTT5R/Y=
|
||||
=2pJ8
|
||||
-----END PGP PUBLIC KEY BLOCK-----</string>
|
||||
<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="23o-MP-wQY" secondAttribute="bottom" id="45J-dA-N4r"/>
|
||||
<constraint firstItem="23o-MP-wQY" firstAttribute="top" secondItem="TQD-GC-YOY" secondAttribute="topMargin" id="Tth-YH-Ni9"/>
|
||||
<constraint firstAttribute="trailingMargin" secondItem="23o-MP-wQY" secondAttribute="trailing" id="lqq-rV-fZK"/>
|
||||
<constraint firstItem="23o-MP-wQY" firstAttribute="leading" secondItem="TQD-GC-YOY" secondAttribute="leadingMargin" constant="7" id="oYc-y1-XS9"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</cells>
|
||||
</tableViewSection>
|
||||
</sections>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="WgM-cY-mig" id="7bV-Gr-WNu"/>
|
||||
<outlet property="delegate" destination="WgM-cY-mig" id="lsz-m8-HZb"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<connections>
|
||||
<outlet property="armorPrivateKeyTextView" destination="23o-MP-wQY" id="ybK-Ba-vJt"/>
|
||||
<outlet property="armorPublicKeyTextView" destination="Y9t-DD-6uH" id="307-xN-QZ9"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="qJO-AN-K9p" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="6870" y="3117"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="Lock" width="25" height="25"/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// GitSSHKeyArmorSettingTableViewController.swift
|
||||
// pass
|
||||
//
|
||||
// Created by Mingshen Sun on 2/4/2017.
|
||||
// Copyright © 2017 Bob Sun. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SwiftyUserDefaults
|
||||
|
||||
class GitSSHKeyArmorSettingTableViewController: UITableViewController {
|
||||
@IBOutlet weak var armorPublicKeyTextView: UITextView!
|
||||
@IBOutlet weak var armorPrivateKeyTextView: UITextView!
|
||||
var gitSSHPrivateKeyPassphrase: String?
|
||||
let passwordStore = PasswordStore.shared
|
||||
var doneBarButtonItem: UIBarButtonItem?
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
armorPublicKeyTextView.text = Defaults[.gitSSHPublicKeyArmor]
|
||||
armorPrivateKeyTextView.text = Defaults[.gitSSHPrivateKeyArmor]
|
||||
gitSSHPrivateKeyPassphrase = passwordStore.gitSSHPrivateKeyPassphrase
|
||||
|
||||
doneBarButtonItem = UIBarButtonItem(title: "Done",
|
||||
style: UIBarButtonItemStyle.done,
|
||||
target: self,
|
||||
action: #selector(doneButtonTapped(_:)))
|
||||
navigationItem.rightBarButtonItem = doneBarButtonItem
|
||||
navigationItem.title = "SSH Key"
|
||||
}
|
||||
|
||||
private func createSavePassphraseAlert() -> UIAlertController {
|
||||
let savePassphraseAlert = UIAlertController(title: "Passphrase", message: "Do you want to save the passphrase for later sync?", preferredStyle: UIAlertControllerStyle.alert)
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.default) { _ in
|
||||
Defaults[.isRememberPassphraseOn] = false
|
||||
Defaults[.gitSSHKeySource] = "armor"
|
||||
self.navigationController!.popViewController(animated: true)
|
||||
})
|
||||
savePassphraseAlert.addAction(UIAlertAction(title: "Save", style: UIAlertActionStyle.destructive) {_ in
|
||||
Defaults[.isRememberPassphraseOn] = true
|
||||
self.passwordStore.gitSSHPrivateKeyPassphrase = self.gitSSHPrivateKeyPassphrase
|
||||
Defaults[.gitSSHKeySource] = "armor"
|
||||
self.navigationController!.popViewController(animated: true)
|
||||
})
|
||||
return savePassphraseAlert
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
let alert = UIAlertController(title: "Passphrase", message: "Please fill in the passphrase of your SSH secret key.", preferredStyle: UIAlertControllerStyle.alert)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
||||
self.gitSSHPrivateKeyPassphrase = alert.textFields?.first?.text
|
||||
let savePassphraseAlert = self.createSavePassphraseAlert()
|
||||
self.present(savePassphraseAlert, animated: true, completion: nil)
|
||||
}))
|
||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = self.gitSSHPrivateKeyPassphrase
|
||||
textField.isSecureTextEntry = true
|
||||
})
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -8,17 +8,18 @@
|
|||
|
||||
import UIKit
|
||||
import SwiftyUserDefaults
|
||||
import SVProgressHUD
|
||||
|
||||
class GitServerSettingTableViewController: UITableViewController {
|
||||
|
||||
@IBOutlet weak var gitRepositoryURLTextField: UITextField!
|
||||
@IBOutlet weak var gitURLTextField: UITextField!
|
||||
@IBOutlet weak var usernameTextField: UITextField!
|
||||
@IBOutlet weak var authSSHKeyCell: UITableViewCell!
|
||||
@IBOutlet weak var authPasswordCell: UITableViewCell!
|
||||
let passwordStore = PasswordStore.shared
|
||||
var password: String?
|
||||
|
||||
var authenticationMethod = Defaults[.gitRepositoryAuthenticationMethod]
|
||||
var authenticationMethod = Defaults[.gitAuthenticationMethod]
|
||||
|
||||
private func checkAuthenticationMethod(method: String) {
|
||||
let passwordCheckView = authPasswordCell.viewWithTag(1001)!
|
||||
|
|
@ -38,17 +39,17 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
}
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
if let url = Defaults[.gitRepositoryURL] {
|
||||
gitRepositoryURLTextField.text = url.absoluteString
|
||||
if let url = Defaults[.gitURL] {
|
||||
gitURLTextField.text = url.absoluteString
|
||||
}
|
||||
usernameTextField.text = Defaults[.gitRepositoryUsername]
|
||||
password = passwordStore.gitRepositoryPassword
|
||||
authenticationMethod = Defaults[.gitRepositoryAuthenticationMethod]
|
||||
usernameTextField.text = Defaults[.gitUsername]
|
||||
password = passwordStore.gitPassword
|
||||
authenticationMethod = Defaults[.gitAuthenticationMethod]
|
||||
|
||||
// Grey out ssh option if ssh_key and ssh_key.pub are not present
|
||||
let sshLabel = authSSHKeyCell.subviews[0].subviews[0] as! UILabel
|
||||
|
||||
sshLabel.isEnabled = sshKeyExists()
|
||||
sshLabel.isEnabled = gitSSHKeyExists()
|
||||
|
||||
if authenticationMethod == nil || !sshLabel.isEnabled {
|
||||
authenticationMethod = "Password"
|
||||
|
|
@ -61,7 +62,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
|
||||
let cell = tableView.cellForRow(at: indexPath)
|
||||
if cell == authSSHKeyCell {
|
||||
performSegue(withIdentifier: "showSSHKeySettingSegue", sender: self)
|
||||
showSSHKeyActionSheet()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +78,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
|
||||
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||
if identifier == "saveGitServerSettingSegue" {
|
||||
guard let _ = URL(string: gitRepositoryURLTextField.text!) else {
|
||||
guard let _ = URL(string: gitURLTextField.text!) else {
|
||||
Utils.alert(title: "Cannot Save", message: "Git Server is not set.", controller: self, completion: nil)
|
||||
return false
|
||||
}
|
||||
|
|
@ -89,18 +90,13 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
return true
|
||||
}
|
||||
|
||||
func sshKeyExists() -> Bool {
|
||||
return FileManager.default.fileExists(atPath: Globals.sshPublicKeyURL.path) &&
|
||||
FileManager.default.fileExists(atPath: Globals.sshPrivateKeyURL.path)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let cell = tableView.cellForRow(at: indexPath)
|
||||
if cell == authPasswordCell {
|
||||
authenticationMethod = "Password"
|
||||
} else if cell == authSSHKeyCell {
|
||||
|
||||
if !sshKeyExists() {
|
||||
if !gitSSHKeyExists() {
|
||||
Utils.alert(title: "Cannot Select SSH Key", message: "Please setup SSH key first.", controller: self, completion: nil)
|
||||
authenticationMethod = "Password"
|
||||
} else {
|
||||
|
|
@ -131,4 +127,74 @@ class GitServerSettingTableViewController: UITableViewController {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
if Defaults[.gitSSHKeySource] == "url" {
|
||||
urlActionTitle = "✓ \(urlActionTitle)"
|
||||
} else if Defaults[.gitSSHKeySource] == "armor" {
|
||||
armorActionTitle = "✓ \(armorActionTitle)"
|
||||
} else if Defaults[.gitSSHKeySource] == "file" {
|
||||
fileActionTitle = "✓ \(fileActionTitle)"
|
||||
}
|
||||
let urlAction = UIAlertAction(title: urlActionTitle, style: .default) { _ in
|
||||
self.performSegue(withIdentifier: "setGitSSHKeyByURLSegue", sender: self)
|
||||
}
|
||||
let armorAction = UIAlertAction(title: armorActionTitle, style: .default) { _ in
|
||||
self.performSegue(withIdentifier: "setGitSSHKeyByArmorSegue", sender: self)
|
||||
}
|
||||
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
|
||||
optionMenu.addAction(urlAction)
|
||||
optionMenu.addAction(armorAction)
|
||||
|
||||
if (gitSSHKeyExists()) {
|
||||
let fileAction = UIAlertAction(title: fileActionTitle, style: .default) { _ in
|
||||
let alert = UIAlertController(
|
||||
title: "SSH Key Passphrase",
|
||||
message: "Please fill in the passphrase for your Git Repository SSH key.",
|
||||
preferredStyle: UIAlertControllerStyle.alert
|
||||
)
|
||||
|
||||
alert.addAction(
|
||||
UIAlertAction(
|
||||
title: "OK",
|
||||
style: UIAlertActionStyle.default,
|
||||
handler: {_ in
|
||||
self.passwordStore.gitSSHPrivateKeyPassphrase = alert.textFields!.first!.text!
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
alert.addTextField(
|
||||
configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = self.passwordStore.gitSSHPrivateKeyPassphrase
|
||||
textField.isSecureTextEntry = true
|
||||
}
|
||||
)
|
||||
}
|
||||
Defaults[.gitSSHKeySource] = "file"
|
||||
optionMenu.addAction(fileAction)
|
||||
}
|
||||
|
||||
if Defaults[.gitSSHKeySource] != nil {
|
||||
let deleteAction = UIAlertAction(title: "Remove Git SSH Keys", style: .destructive) { _ in
|
||||
Utils.removeGitSSHKeys()
|
||||
Defaults[.gitSSHKeySource] = nil
|
||||
}
|
||||
optionMenu.addAction(deleteAction)
|
||||
}
|
||||
optionMenu.addAction(cancelAction)
|
||||
optionMenu.popoverPresentationController?.sourceView = authSSHKeyCell
|
||||
optionMenu.popoverPresentationController?.sourceRect = authSSHKeyCell.bounds
|
||||
self.present(optionMenu, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
|
|||
}
|
||||
DispatchQueue.main.async {
|
||||
self.reloadTableView(parent: nil)
|
||||
Defaults[.gitRepositoryPasswordAttempts] = 0
|
||||
Defaults[.gitPasswordAttempts] = 0
|
||||
SVProgressHUD.showSuccess(withStatus: "Done")
|
||||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,15 +12,14 @@ import SVProgressHUD
|
|||
|
||||
class SSHKeySettingTableViewController: UITableViewController {
|
||||
|
||||
@IBOutlet weak var passphraseTextField: UITextField!
|
||||
@IBOutlet weak var privateKeyURLTextField: UITextField!
|
||||
@IBOutlet weak var publicKeyURLTextField: UITextField!
|
||||
let passwordStore = PasswordStore.shared
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
passphraseTextField.text = Utils.getPasswordFromKeychain(name: "gitRepositorySSHPrivateKeyPassphrase") ?? ""
|
||||
privateKeyURLTextField.text = Defaults[.gitRepositorySSHPrivateKeyURL]?.absoluteString
|
||||
publicKeyURLTextField.text = Defaults[.gitRepositorySSHPublicKeyURL]?.absoluteString
|
||||
privateKeyURLTextField.text = Defaults[.gitSSHPrivateKeyURL]?.absoluteString
|
||||
publicKeyURLTextField.text = Defaults[.gitSSHPublicKeyURL]?.absoluteString
|
||||
var doneBarButtonItem: UIBarButtonItem?
|
||||
|
||||
doneBarButtonItem = UIBarButtonItem(title: "Done",
|
||||
|
|
@ -41,18 +40,42 @@ class SSHKeySettingTableViewController: UITableViewController {
|
|||
return
|
||||
}
|
||||
|
||||
Defaults[.gitRepositorySSHPublicKeyURL] = publicKeyURL
|
||||
Defaults[.gitRepositorySSHPrivateKeyURL] = privateKeyURL
|
||||
Utils.addPasswordToKeychain(name: "gitRepositorySSHPrivateKeyPassphrase", password: passphraseTextField.text!)
|
||||
Defaults[.gitSSHPublicKeyURL] = publicKeyURL
|
||||
Defaults[.gitSSHPrivateKeyURL] = privateKeyURL
|
||||
|
||||
do {
|
||||
try Data(contentsOf: publicKeyURL).write(to: Globals.sshPublicKeyURL, options: .atomic)
|
||||
try Data(contentsOf: privateKeyURL).write(to: Globals.sshPrivateKeyURL, options: .atomic)
|
||||
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)
|
||||
}
|
||||
|
||||
navigationController!.popViewController(animated: true)
|
||||
Defaults[.gitSSHKeySource] = "url"
|
||||
let alert = UIAlertController(
|
||||
title: "PGP Passphrase",
|
||||
message: "Please fill in the passphrase for your Git Repository SSH key.",
|
||||
preferredStyle: UIAlertControllerStyle.alert
|
||||
)
|
||||
|
||||
alert.addAction(
|
||||
UIAlertAction(
|
||||
title: "OK",
|
||||
style: UIAlertActionStyle.default,
|
||||
handler: {_ in
|
||||
Utils.addPasswordToKeychain(
|
||||
name: "gitSSHPrivateKeyPassphrase",
|
||||
password: alert.textFields!.first!.text!
|
||||
)
|
||||
self.navigationController!.popViewController(animated: true)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
alert.addTextField(
|
||||
configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = self.passwordStore.gitSSHPrivateKeyPassphrase
|
||||
textField.isSecureTextEntry = true
|
||||
})
|
||||
self.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,16 +95,16 @@ class SettingsTableViewController: UITableViewController {
|
|||
|
||||
@IBAction func saveGitServerSetting(segue: UIStoryboardSegue) {
|
||||
if let controller = segue.source as? GitServerSettingTableViewController {
|
||||
let gitRepostiroyURL = controller.gitRepositoryURLTextField.text!
|
||||
let gitRepostiroyURL = controller.gitURLTextField.text!
|
||||
let username = controller.usernameTextField.text!
|
||||
let password = controller.password
|
||||
let auth = controller.authenticationMethod
|
||||
|
||||
if Defaults[.gitRepositoryURL] == nil ||
|
||||
Defaults[.gitRepositoryURL]!.absoluteString != gitRepostiroyURL ||
|
||||
auth != Defaults[.gitRepositoryAuthenticationMethod] ||
|
||||
username != Defaults[.gitRepositoryUsername] ||
|
||||
password != self.passwordStore.gitRepositoryPassword ||
|
||||
if Defaults[.gitURL] == nil ||
|
||||
Defaults[.gitURL]!.absoluteString != gitRepostiroyURL ||
|
||||
auth != Defaults[.gitAuthenticationMethod] ||
|
||||
username != Defaults[.gitUsername] ||
|
||||
password != self.passwordStore.gitPassword ||
|
||||
self.passwordStore.repositoryExisted() == false {
|
||||
|
||||
SVProgressHUD.setDefaultMaskType(.black)
|
||||
|
|
@ -117,9 +117,9 @@ class SettingsTableViewController: UITableViewController {
|
|||
gitCredential = GitCredential(
|
||||
credential: GitCredential.Credential.ssh(
|
||||
userName: username,
|
||||
password: Utils.getPasswordFromKeychain(name: "gitRepositorySSHPrivateKeyPassphrase") ?? "",
|
||||
publicKeyFile: Globals.sshPublicKeyURL,
|
||||
privateKeyFile: Globals.sshPrivateKeyURL,
|
||||
password: Utils.getPasswordFromKeychain(name: "gitSSHPrivateKeyPassphrase") ?? "",
|
||||
publicKeyFile: Globals.gitSSHPublicKeyURL,
|
||||
privateKeyFile: Globals.gitSSHPrivateKeyURL,
|
||||
passwordNotSetCallback: self.requestSshKeyPassword
|
||||
)
|
||||
)
|
||||
|
|
@ -140,11 +140,11 @@ class SettingsTableViewController: UITableViewController {
|
|||
}
|
||||
})
|
||||
DispatchQueue.main.async {
|
||||
Defaults[.gitRepositoryURL] = URL(string: gitRepostiroyURL)
|
||||
Defaults[.gitRepositoryUsername] = username
|
||||
Defaults[.gitRepositoryAuthenticationMethod] = auth
|
||||
Defaults[.gitRepositoryPasswordAttempts] = 0
|
||||
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitRepositoryURL]?.host
|
||||
Defaults[.gitURL] = URL(string: gitRepostiroyURL)
|
||||
Defaults[.gitUsername] = username
|
||||
Defaults[.gitAuthenticationMethod] = auth
|
||||
Defaults[.gitPasswordAttempts] = 0
|
||||
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitURL]?.host
|
||||
SVProgressHUD.showSuccess(withStatus: "Done")
|
||||
SVProgressHUD.dismiss(withDelay: 1)
|
||||
}
|
||||
|
|
@ -162,7 +162,7 @@ class SettingsTableViewController: UITableViewController {
|
|||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.actOnPasswordStoreErasedNotification), name: .passwordStoreErased, object: nil)
|
||||
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitRepositoryURL]?.host
|
||||
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitURL]?.host
|
||||
touchIDTableViewCell.accessoryView = touchIDSwitch
|
||||
setPGPKeyTableViewCellDetailText()
|
||||
setPasswordRepositoryTableViewCellDetailText()
|
||||
|
|
@ -189,10 +189,10 @@ class SettingsTableViewController: UITableViewController {
|
|||
}
|
||||
|
||||
private func setPasswordRepositoryTableViewCellDetailText() {
|
||||
if Defaults[.gitRepositoryURL] == nil {
|
||||
if Defaults[.gitURL] == nil {
|
||||
passwordRepositoryTableViewCell.detailTextLabel?.text = "Not Set"
|
||||
} else {
|
||||
passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitRepositoryURL]!.host
|
||||
passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitURL]!.host
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -218,7 +218,7 @@ class SettingsTableViewController: UITableViewController {
|
|||
}))
|
||||
|
||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = self.passwordStore.gitRepositoryPassword
|
||||
textField.text = self.passwordStore.gitPassword
|
||||
textField.isSecureTextEntry = true
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -17,12 +17,17 @@ extension DefaultsKeys {
|
|||
static let pgpPublicKeyArmor = DefaultsKey<String?>("pgpPublicKeyArmor")
|
||||
static let pgpPrivateKeyArmor = DefaultsKey<String?>("pgpPrivateKeyArmor")
|
||||
|
||||
static let gitRepositoryURL = DefaultsKey<URL?>("gitRepositoryURL")
|
||||
static let gitRepositoryAuthenticationMethod = DefaultsKey<String?>("gitRepositoryAuthenticationMethod")
|
||||
static let gitRepositoryUsername = DefaultsKey<String?>("gitRepositoryUsername")
|
||||
static let gitRepositoryPasswordAttempts = DefaultsKey<Int>("gitRepositoryPasswordAttempts")
|
||||
static let gitRepositorySSHPublicKeyURL = DefaultsKey<URL?>("gitRepositorySSHPublicKeyURL")
|
||||
static let gitRepositorySSHPrivateKeyURL = DefaultsKey<URL?>("gitRepositorySSHPrivateKeyURL")
|
||||
static let gitURL = DefaultsKey<URL?>("gitURL")
|
||||
static let gitAuthenticationMethod = DefaultsKey<String?>("gitAuthenticationMethod")
|
||||
static let gitUsername = DefaultsKey<String?>("gitUsername")
|
||||
static let gitPasswordAttempts = DefaultsKey<Int>("gitPasswordAttempts")
|
||||
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 lastSyncedTime = DefaultsKey<Date?>("lastSyncedTime")
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,10 @@ class Globals {
|
|||
static let pgpPublicKeyPath = "\(documentPath)/gpg_key.pub"
|
||||
static let pgpPrivateKeyPath = "\(documentPath)/gpg_key"
|
||||
|
||||
static let sshPublicKeyURL = URL(fileURLWithPath: "\(documentPath)/ssh_key.pub")
|
||||
static let sshPrivateKeyURL = URL(fileURLWithPath: "\(documentPath)/ssh_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()
|
||||
|
|
|
|||
|
|
@ -83,6 +83,16 @@ class Utils {
|
|||
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")
|
||||
do {
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ struct GitCredential {
|
|||
var credential: GTCredential? = nil
|
||||
switch self.credential {
|
||||
case let .http(userName, password):
|
||||
print(Defaults[.gitRepositoryPasswordAttempts])
|
||||
print(Defaults[.gitPasswordAttempts])
|
||||
var newPassword: String = password
|
||||
if Defaults[.gitRepositoryPasswordAttempts] != 0 {
|
||||
if Defaults[.gitPasswordAttempts] != 0 {
|
||||
let sem = DispatchSemaphore(value: 0)
|
||||
DispatchQueue.main.async {
|
||||
SVProgressHUD.dismiss()
|
||||
|
|
@ -40,15 +40,15 @@ struct GitCredential {
|
|||
let alert = UIAlertController(title: "Password", message: "Please fill in the password of your Git account.", preferredStyle: UIAlertControllerStyle.alert)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
||||
newPassword = alert.textFields!.first!.text!
|
||||
PasswordStore.shared.gitRepositoryPassword = newPassword
|
||||
PasswordStore.shared.gitPassword = newPassword
|
||||
sem.signal()
|
||||
}))
|
||||
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
|
||||
Defaults[.gitRepositoryPasswordAttempts] = -1
|
||||
Defaults[.gitPasswordAttempts] = -1
|
||||
sem.signal()
|
||||
})
|
||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||
textField.text = PasswordStore.shared.gitRepositoryPassword
|
||||
textField.text = PasswordStore.shared.gitPassword
|
||||
textField.isSecureTextEntry = true
|
||||
})
|
||||
topController.present(alert, animated: true, completion: nil)
|
||||
|
|
@ -56,12 +56,12 @@ struct GitCredential {
|
|||
}
|
||||
let _ = sem.wait(timeout: DispatchTime.distantFuture)
|
||||
}
|
||||
if Defaults[.gitRepositoryPasswordAttempts] == -1 {
|
||||
Defaults[.gitRepositoryPasswordAttempts] = 0
|
||||
if Defaults[.gitPasswordAttempts] == -1 {
|
||||
Defaults[.gitPasswordAttempts] = 0
|
||||
return nil
|
||||
}
|
||||
Defaults[.gitRepositoryPasswordAttempts] += 1
|
||||
PasswordStore.shared.gitRepositoryPassword = newPassword
|
||||
Defaults[.gitPasswordAttempts] += 1
|
||||
PasswordStore.shared.gitPassword = newPassword
|
||||
credential = try? GTCredential(userName: userName, password: newPassword)
|
||||
case let .ssh(userName, password, publicKeyFile, privateKeyFile, passwordNotSetCallback):
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ struct GitCredential {
|
|||
}
|
||||
|
||||
// Save password for the future
|
||||
Utils.addPasswordToKeychain(name: "gitRepositorySSHPrivateKeyPassphrase", password: newPassword!)
|
||||
Utils.addPasswordToKeychain(name: "gitSSHPrivateKeyPassphrase", password: newPassword!)
|
||||
|
||||
// nil is expected in case of empty password
|
||||
if newPassword == "" {
|
||||
|
|
@ -112,7 +112,7 @@ class PasswordStore {
|
|||
|
||||
var gitSignatureForNow: GTSignature {
|
||||
get {
|
||||
return GTSignature(name: Defaults[.gitRepositoryUsername]!, email: Defaults[.gitRepositoryUsername]!+"@passforios", time: Date())!
|
||||
return GTSignature(name: Defaults[.gitUsername]!, email: Defaults[.gitUsername]!+"@passforios", time: Date())!
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -126,12 +126,21 @@ class PasswordStore {
|
|||
return Utils.getPasswordFromKeychain(name: "pgpKeyPassphrase")
|
||||
}
|
||||
}
|
||||
var gitRepositoryPassword: String? {
|
||||
var gitPassword: String? {
|
||||
set {
|
||||
Utils.addPasswordToKeychain(name: "gitRepositoryPassword", password: newValue)
|
||||
Utils.addPasswordToKeychain(name: "gitPassword", password: newValue)
|
||||
}
|
||||
get {
|
||||
return Utils.getPasswordFromKeychain(name: "gitRepositoryPassword")
|
||||
return Utils.getPasswordFromKeychain(name: "gitPassword")
|
||||
}
|
||||
}
|
||||
|
||||
var gitSSHPrivateKeyPassphrase: String? {
|
||||
set {
|
||||
Utils.addPasswordToKeychain(name: "gitSSHPrivateKeyPassphrase", password: newValue)
|
||||
}
|
||||
get {
|
||||
return Utils.getPasswordFromKeychain(name: "gitSSHPrivateKeyPassphrase") ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -164,22 +173,41 @@ class PasswordStore {
|
|||
print(error)
|
||||
}
|
||||
initPGPKeys()
|
||||
if Defaults[.gitRepositoryAuthenticationMethod] == "Password" {
|
||||
gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: Defaults[.gitRepositoryUsername]!, password: Utils.getPasswordFromKeychain(name: "gitRepositoryPassword") ?? ""))
|
||||
} else if Defaults[.gitRepositoryAuthenticationMethod] == "SSH Key"{
|
||||
initGitCredential()
|
||||
}
|
||||
|
||||
enum SSHKeyType {
|
||||
case `public`, secret
|
||||
}
|
||||
|
||||
public func initGitCredential() {
|
||||
if Defaults[.gitAuthenticationMethod] == "Password" {
|
||||
gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: Defaults[.gitUsername]!, password: Utils.getPasswordFromKeychain(name: "gitPassword") ?? ""))
|
||||
} else if Defaults[.gitAuthenticationMethod] == "SSH Key"{
|
||||
gitCredential = GitCredential(
|
||||
credential: GitCredential.Credential.ssh(
|
||||
userName: Defaults[.gitRepositoryUsername]!,
|
||||
password: Utils.getPasswordFromKeychain(name: "gitRepositorySSHPrivateKeyPassphrase") ?? "",
|
||||
publicKeyFile: Globals.sshPublicKeyURL,
|
||||
privateKeyFile: Globals.sshPrivateKeyURL,
|
||||
userName: Defaults[.gitUsername]!,
|
||||
password: gitSSHPrivateKeyPassphrase ?? "",
|
||||
publicKeyFile: Globals.gitSSHPublicKeyURL,
|
||||
privateKeyFile: Globals.gitSSHPrivateKeyURL,
|
||||
passwordNotSetCallback: nil
|
||||
)
|
||||
)
|
||||
} else {
|
||||
gitCredential = nil
|
||||
}
|
||||
}
|
||||
|
||||
public func initGitSSHKey(with armorKey: String, _ keyType: SSHKeyType) throws {
|
||||
var keyPath = ""
|
||||
switch keyType {
|
||||
case .public:
|
||||
keyPath = Globals.gitSSHPublicKeyPath
|
||||
case .secret:
|
||||
keyPath = Globals.gitSSHPrivateKeyPath
|
||||
}
|
||||
|
||||
try armorKey.write(toFile: keyPath, atomically: true, encoding: .ascii)
|
||||
}
|
||||
|
||||
public func initPGPKeys() {
|
||||
|
|
@ -654,8 +682,8 @@ class PasswordStore {
|
|||
|
||||
Utils.removeFileIfExists(atPath: Globals.pgpPublicKeyPath)
|
||||
Utils.removeFileIfExists(atPath: Globals.pgpPrivateKeyPath)
|
||||
Utils.removeFileIfExists(at: Globals.sshPrivateKeyURL)
|
||||
Utils.removeFileIfExists(at: Globals.sshPublicKeyURL)
|
||||
Utils.removeFileIfExists(atPath: Globals.gitSSHPublicKeyPath)
|
||||
Utils.removeFileIfExists(atPath: Globals.gitSSHPrivateKeyPath)
|
||||
|
||||
Utils.removeAllKeychain()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue