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 */; };
|
DCC408A41E2FCC9E00F29B0E /* PasswordStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC408A31E2FCC9E00F29B0E /* PasswordStore.swift */; };
|
||||||
DCC408C71E307DBB00F29B0E /* SVProgressHUD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC408C61E307DBB00F29B0E /* SVProgressHUD.framework */; };
|
DCC408C71E307DBB00F29B0E /* SVProgressHUD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC408C61E307DBB00F29B0E /* SVProgressHUD.framework */; };
|
||||||
DCC441521E8F6C06008A90C4 /* RawPasswordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC441511E8F6C06008A90C4 /* RawPasswordViewController.swift */; };
|
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 */; };
|
DCDDEAB01E4639F300F68193 /* LabelTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DCDDEAAF1E4639F300F68193 /* LabelTableViewCell.xib */; };
|
||||||
DCDDEAB31E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCDDEAB11E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift */; };
|
DCDDEAB31E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCDDEAB11E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift */; };
|
||||||
DCE6C2671E71261C003038C6 /* PasswordWithFolderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCE6C2651E71261C003038C6 /* PasswordWithFolderTableViewCell.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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
DCE6C2651E71261C003038C6 /* PasswordWithFolderTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordWithFolderTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
|
|
@ -216,6 +218,7 @@
|
||||||
DCAAF7441E2FA66800AB94BC /* SettingsTableViewController.swift */,
|
DCAAF7441E2FA66800AB94BC /* SettingsTableViewController.swift */,
|
||||||
DC037CA91E4B8EAE00609409 /* SpecialThanksTableViewController.swift */,
|
DC037CA91E4B8EAE00609409 /* SpecialThanksTableViewController.swift */,
|
||||||
DC8963BF1E38EEB900828B09 /* SSHKeySettingTableViewController.swift */,
|
DC8963BF1E38EEB900828B09 /* SSHKeySettingTableViewController.swift */,
|
||||||
|
DCC441531E916382008A90C4 /* GitSSHKeyArmorSettingTableViewController.swift */,
|
||||||
);
|
);
|
||||||
path = Controllers;
|
path = Controllers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|
@ -518,6 +521,7 @@
|
||||||
files = (
|
files = (
|
||||||
DCC408A41E2FCC9E00F29B0E /* PasswordStore.swift in Sources */,
|
DCC408A41E2FCC9E00F29B0E /* PasswordStore.swift in Sources */,
|
||||||
DC037CBF1E4ED4E100609409 /* TextViewTableViewCell.swift in Sources */,
|
DC037CBF1E4ED4E100609409 /* TextViewTableViewCell.swift in Sources */,
|
||||||
|
DCC441541E916382008A90C4 /* GitSSHKeyArmorSettingTableViewController.swift in Sources */,
|
||||||
DC8963C01E38EEB900828B09 /* SSHKeySettingTableViewController.swift in Sources */,
|
DC8963C01E38EEB900828B09 /* SSHKeySettingTableViewController.swift in Sources */,
|
||||||
DC193FFA1E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift in Sources */,
|
DC193FFA1E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift in Sources */,
|
||||||
DCFB77AB1E503729008DE471 /* ContentTableViewCell.swift in Sources */,
|
DCFB77AB1E503729008DE471 /* ContentTableViewCell.swift in Sources */,
|
||||||
|
|
|
||||||
|
|
@ -477,10 +477,11 @@
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="authPasswordCell" destination="KrP-nb-haa" id="zjH-sg-dfJ"/>
|
<outlet property="authPasswordCell" destination="KrP-nb-haa" id="zjH-sg-dfJ"/>
|
||||||
<outlet property="authSSHKeyCell" destination="Qmt-bo-CuJ" id="11L-Tt-MgM"/>
|
<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"/>
|
<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="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>
|
</connections>
|
||||||
</tableViewController>
|
</tableViewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="7c1-c7-Qyp" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
<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">
|
<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"/>
|
<rect key="frame" x="20" y="4" width="374" height="732"/>
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<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"/>
|
<fontDescription key="fontDescription" name="Courier" family="Courier" pointSize="14"/>
|
||||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||||
</textView>
|
</textView>
|
||||||
|
|
@ -892,36 +893,6 @@
|
||||||
</constraints>
|
</constraints>
|
||||||
</tableViewCellContentView>
|
</tableViewCellContentView>
|
||||||
</tableViewCell>
|
</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>
|
</cells>
|
||||||
</tableViewSection>
|
</tableViewSection>
|
||||||
</sections>
|
</sections>
|
||||||
|
|
@ -931,14 +902,13 @@
|
||||||
</connections>
|
</connections>
|
||||||
</tableView>
|
</tableView>
|
||||||
<connections>
|
<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="privateKeyURLTextField" destination="4iJ-oB-R1f" id="scx-lz-dUW"/>
|
||||||
<outlet property="publicKeyURLTextField" destination="Q1j-Z4-Ae8" id="nfA-W3-kJ2"/>
|
<outlet property="publicKeyURLTextField" destination="Q1j-Z4-Ae8" id="nfA-W3-kJ2"/>
|
||||||
</connections>
|
</connections>
|
||||||
</tableViewController>
|
</tableViewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="eY3-aM-BJB" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="eY3-aM-BJB" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="5132" y="2893"/>
|
<point key="canvasLocation" x="7433" y="2204"/>
|
||||||
</scene>
|
</scene>
|
||||||
<!--General Settings Table View Controller-->
|
<!--General Settings Table View Controller-->
|
||||||
<scene sceneID="fho-xr-1Ah">
|
<scene sceneID="fho-xr-1Ah">
|
||||||
|
|
@ -1371,7 +1341,7 @@ pfZ36xQbOAQYKKf6ZTT5R/Y=
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="2Wn-7D-LLj" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="2Wn-7D-LLj" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
<exit id="Ul9-vk-jhw" userLabel="Exit" sceneMemberID="exit"/>
|
<exit id="Ul9-vk-jhw" userLabel="Exit" sceneMemberID="exit"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="6039.130434782609" y="4307.608695652174"/>
|
<point key="canvasLocation" x="7094" y="4030"/>
|
||||||
</scene>
|
</scene>
|
||||||
<!--Navigation Controller-->
|
<!--Navigation Controller-->
|
||||||
<scene sceneID="m18-ch-m92">
|
<scene sceneID="m18-ch-m92">
|
||||||
|
|
@ -1409,6 +1379,200 @@ pfZ36xQbOAQYKKf6ZTT5R/Y=
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="6720" y="-24"/>
|
<point key="canvasLocation" x="6720" y="-24"/>
|
||||||
</scene>
|
</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>
|
</scenes>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="Lock" width="25" height="25"/>
|
<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 UIKit
|
||||||
import SwiftyUserDefaults
|
import SwiftyUserDefaults
|
||||||
|
import SVProgressHUD
|
||||||
|
|
||||||
class GitServerSettingTableViewController: UITableViewController {
|
class GitServerSettingTableViewController: UITableViewController {
|
||||||
|
|
||||||
@IBOutlet weak var gitRepositoryURLTextField: UITextField!
|
@IBOutlet weak var gitURLTextField: UITextField!
|
||||||
@IBOutlet weak var usernameTextField: UITextField!
|
@IBOutlet weak var usernameTextField: UITextField!
|
||||||
@IBOutlet weak var authSSHKeyCell: UITableViewCell!
|
@IBOutlet weak var authSSHKeyCell: UITableViewCell!
|
||||||
@IBOutlet weak var authPasswordCell: UITableViewCell!
|
@IBOutlet weak var authPasswordCell: UITableViewCell!
|
||||||
let passwordStore = PasswordStore.shared
|
let passwordStore = PasswordStore.shared
|
||||||
var password: String?
|
var password: String?
|
||||||
|
|
||||||
var authenticationMethod = Defaults[.gitRepositoryAuthenticationMethod]
|
var authenticationMethod = Defaults[.gitAuthenticationMethod]
|
||||||
|
|
||||||
private func checkAuthenticationMethod(method: String) {
|
private func checkAuthenticationMethod(method: String) {
|
||||||
let passwordCheckView = authPasswordCell.viewWithTag(1001)!
|
let passwordCheckView = authPasswordCell.viewWithTag(1001)!
|
||||||
|
|
@ -38,17 +39,17 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
if let url = Defaults[.gitRepositoryURL] {
|
if let url = Defaults[.gitURL] {
|
||||||
gitRepositoryURLTextField.text = url.absoluteString
|
gitURLTextField.text = url.absoluteString
|
||||||
}
|
}
|
||||||
usernameTextField.text = Defaults[.gitRepositoryUsername]
|
usernameTextField.text = Defaults[.gitUsername]
|
||||||
password = passwordStore.gitRepositoryPassword
|
password = passwordStore.gitPassword
|
||||||
authenticationMethod = Defaults[.gitRepositoryAuthenticationMethod]
|
authenticationMethod = Defaults[.gitAuthenticationMethod]
|
||||||
|
|
||||||
// Grey out ssh option if ssh_key and ssh_key.pub are not present
|
// Grey out ssh option if ssh_key and ssh_key.pub are not present
|
||||||
let sshLabel = authSSHKeyCell.subviews[0].subviews[0] as! UILabel
|
let sshLabel = authSSHKeyCell.subviews[0].subviews[0] as! UILabel
|
||||||
|
|
||||||
sshLabel.isEnabled = sshKeyExists()
|
sshLabel.isEnabled = gitSSHKeyExists()
|
||||||
|
|
||||||
if authenticationMethod == nil || !sshLabel.isEnabled {
|
if authenticationMethod == nil || !sshLabel.isEnabled {
|
||||||
authenticationMethod = "Password"
|
authenticationMethod = "Password"
|
||||||
|
|
@ -61,7 +62,7 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
|
override func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
|
||||||
let cell = tableView.cellForRow(at: indexPath)
|
let cell = tableView.cellForRow(at: indexPath)
|
||||||
if cell == authSSHKeyCell {
|
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 {
|
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
|
||||||
if identifier == "saveGitServerSettingSegue" {
|
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)
|
Utils.alert(title: "Cannot Save", message: "Git Server is not set.", controller: self, completion: nil)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -89,18 +90,13 @@ class GitServerSettingTableViewController: UITableViewController {
|
||||||
return true
|
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) {
|
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
let cell = tableView.cellForRow(at: indexPath)
|
let cell = tableView.cellForRow(at: indexPath)
|
||||||
if cell == authPasswordCell {
|
if cell == authPasswordCell {
|
||||||
authenticationMethod = "Password"
|
authenticationMethod = "Password"
|
||||||
} else if cell == authSSHKeyCell {
|
} 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)
|
Utils.alert(title: "Cannot Select SSH Key", message: "Please setup SSH key first.", controller: self, completion: nil)
|
||||||
authenticationMethod = "Password"
|
authenticationMethod = "Password"
|
||||||
} else {
|
} 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 {
|
DispatchQueue.main.async {
|
||||||
self.reloadTableView(parent: nil)
|
self.reloadTableView(parent: nil)
|
||||||
Defaults[.gitRepositoryPasswordAttempts] = 0
|
Defaults[.gitPasswordAttempts] = 0
|
||||||
SVProgressHUD.showSuccess(withStatus: "Done")
|
SVProgressHUD.showSuccess(withStatus: "Done")
|
||||||
SVProgressHUD.dismiss(withDelay: 1)
|
SVProgressHUD.dismiss(withDelay: 1)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,15 +12,14 @@ import SVProgressHUD
|
||||||
|
|
||||||
class SSHKeySettingTableViewController: UITableViewController {
|
class SSHKeySettingTableViewController: UITableViewController {
|
||||||
|
|
||||||
@IBOutlet weak var passphraseTextField: UITextField!
|
|
||||||
@IBOutlet weak var privateKeyURLTextField: UITextField!
|
@IBOutlet weak var privateKeyURLTextField: UITextField!
|
||||||
@IBOutlet weak var publicKeyURLTextField: UITextField!
|
@IBOutlet weak var publicKeyURLTextField: UITextField!
|
||||||
|
let passwordStore = PasswordStore.shared
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
passphraseTextField.text = Utils.getPasswordFromKeychain(name: "gitRepositorySSHPrivateKeyPassphrase") ?? ""
|
privateKeyURLTextField.text = Defaults[.gitSSHPrivateKeyURL]?.absoluteString
|
||||||
privateKeyURLTextField.text = Defaults[.gitRepositorySSHPrivateKeyURL]?.absoluteString
|
publicKeyURLTextField.text = Defaults[.gitSSHPublicKeyURL]?.absoluteString
|
||||||
publicKeyURLTextField.text = Defaults[.gitRepositorySSHPublicKeyURL]?.absoluteString
|
|
||||||
var doneBarButtonItem: UIBarButtonItem?
|
var doneBarButtonItem: UIBarButtonItem?
|
||||||
|
|
||||||
doneBarButtonItem = UIBarButtonItem(title: "Done",
|
doneBarButtonItem = UIBarButtonItem(title: "Done",
|
||||||
|
|
@ -41,18 +40,42 @@ class SSHKeySettingTableViewController: UITableViewController {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Defaults[.gitRepositorySSHPublicKeyURL] = publicKeyURL
|
Defaults[.gitSSHPublicKeyURL] = publicKeyURL
|
||||||
Defaults[.gitRepositorySSHPrivateKeyURL] = privateKeyURL
|
Defaults[.gitSSHPrivateKeyURL] = privateKeyURL
|
||||||
Utils.addPasswordToKeychain(name: "gitRepositorySSHPrivateKeyPassphrase", password: passphraseTextField.text!)
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try Data(contentsOf: publicKeyURL).write(to: Globals.sshPublicKeyURL, options: .atomic)
|
try Data(contentsOf: publicKeyURL).write(to: URL(fileURLWithPath: Globals.gitSSHPublicKeyPath), options: .atomic)
|
||||||
try Data(contentsOf: privateKeyURL).write(to: Globals.sshPrivateKeyURL, options: .atomic)
|
try Data(contentsOf: privateKeyURL).write(to: URL(fileURLWithPath: Globals.gitSSHPrivateKeyPath), options: .atomic)
|
||||||
} catch {
|
} catch {
|
||||||
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
Utils.alert(title: "Error", message: error.localizedDescription, controller: self, completion: nil)
|
||||||
}
|
}
|
||||||
|
Defaults[.gitSSHKeySource] = "url"
|
||||||
navigationController!.popViewController(animated: true)
|
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) {
|
@IBAction func saveGitServerSetting(segue: UIStoryboardSegue) {
|
||||||
if let controller = segue.source as? GitServerSettingTableViewController {
|
if let controller = segue.source as? GitServerSettingTableViewController {
|
||||||
let gitRepostiroyURL = controller.gitRepositoryURLTextField.text!
|
let gitRepostiroyURL = controller.gitURLTextField.text!
|
||||||
let username = controller.usernameTextField.text!
|
let username = controller.usernameTextField.text!
|
||||||
let password = controller.password
|
let password = controller.password
|
||||||
let auth = controller.authenticationMethod
|
let auth = controller.authenticationMethod
|
||||||
|
|
||||||
if Defaults[.gitRepositoryURL] == nil ||
|
if Defaults[.gitURL] == nil ||
|
||||||
Defaults[.gitRepositoryURL]!.absoluteString != gitRepostiroyURL ||
|
Defaults[.gitURL]!.absoluteString != gitRepostiroyURL ||
|
||||||
auth != Defaults[.gitRepositoryAuthenticationMethod] ||
|
auth != Defaults[.gitAuthenticationMethod] ||
|
||||||
username != Defaults[.gitRepositoryUsername] ||
|
username != Defaults[.gitUsername] ||
|
||||||
password != self.passwordStore.gitRepositoryPassword ||
|
password != self.passwordStore.gitPassword ||
|
||||||
self.passwordStore.repositoryExisted() == false {
|
self.passwordStore.repositoryExisted() == false {
|
||||||
|
|
||||||
SVProgressHUD.setDefaultMaskType(.black)
|
SVProgressHUD.setDefaultMaskType(.black)
|
||||||
|
|
@ -117,9 +117,9 @@ class SettingsTableViewController: UITableViewController {
|
||||||
gitCredential = GitCredential(
|
gitCredential = GitCredential(
|
||||||
credential: GitCredential.Credential.ssh(
|
credential: GitCredential.Credential.ssh(
|
||||||
userName: username,
|
userName: username,
|
||||||
password: Utils.getPasswordFromKeychain(name: "gitRepositorySSHPrivateKeyPassphrase") ?? "",
|
password: Utils.getPasswordFromKeychain(name: "gitSSHPrivateKeyPassphrase") ?? "",
|
||||||
publicKeyFile: Globals.sshPublicKeyURL,
|
publicKeyFile: Globals.gitSSHPublicKeyURL,
|
||||||
privateKeyFile: Globals.sshPrivateKeyURL,
|
privateKeyFile: Globals.gitSSHPrivateKeyURL,
|
||||||
passwordNotSetCallback: self.requestSshKeyPassword
|
passwordNotSetCallback: self.requestSshKeyPassword
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -140,11 +140,11 @@ class SettingsTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
Defaults[.gitRepositoryURL] = URL(string: gitRepostiroyURL)
|
Defaults[.gitURL] = URL(string: gitRepostiroyURL)
|
||||||
Defaults[.gitRepositoryUsername] = username
|
Defaults[.gitUsername] = username
|
||||||
Defaults[.gitRepositoryAuthenticationMethod] = auth
|
Defaults[.gitAuthenticationMethod] = auth
|
||||||
Defaults[.gitRepositoryPasswordAttempts] = 0
|
Defaults[.gitPasswordAttempts] = 0
|
||||||
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitRepositoryURL]?.host
|
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitURL]?.host
|
||||||
SVProgressHUD.showSuccess(withStatus: "Done")
|
SVProgressHUD.showSuccess(withStatus: "Done")
|
||||||
SVProgressHUD.dismiss(withDelay: 1)
|
SVProgressHUD.dismiss(withDelay: 1)
|
||||||
}
|
}
|
||||||
|
|
@ -162,7 +162,7 @@ class SettingsTableViewController: UITableViewController {
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(SettingsTableViewController.actOnPasswordStoreErasedNotification), name: .passwordStoreErased, object: nil)
|
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
|
touchIDTableViewCell.accessoryView = touchIDSwitch
|
||||||
setPGPKeyTableViewCellDetailText()
|
setPGPKeyTableViewCellDetailText()
|
||||||
setPasswordRepositoryTableViewCellDetailText()
|
setPasswordRepositoryTableViewCellDetailText()
|
||||||
|
|
@ -189,10 +189,10 @@ class SettingsTableViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func setPasswordRepositoryTableViewCellDetailText() {
|
private func setPasswordRepositoryTableViewCellDetailText() {
|
||||||
if Defaults[.gitRepositoryURL] == nil {
|
if Defaults[.gitURL] == nil {
|
||||||
passwordRepositoryTableViewCell.detailTextLabel?.text = "Not Set"
|
passwordRepositoryTableViewCell.detailTextLabel?.text = "Not Set"
|
||||||
} else {
|
} 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
|
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||||
textField.text = self.passwordStore.gitRepositoryPassword
|
textField.text = self.passwordStore.gitPassword
|
||||||
textField.isSecureTextEntry = true
|
textField.isSecureTextEntry = true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,17 @@ extension DefaultsKeys {
|
||||||
static let pgpPublicKeyArmor = DefaultsKey<String?>("pgpPublicKeyArmor")
|
static let pgpPublicKeyArmor = DefaultsKey<String?>("pgpPublicKeyArmor")
|
||||||
static let pgpPrivateKeyArmor = DefaultsKey<String?>("pgpPrivateKeyArmor")
|
static let pgpPrivateKeyArmor = DefaultsKey<String?>("pgpPrivateKeyArmor")
|
||||||
|
|
||||||
static let gitRepositoryURL = DefaultsKey<URL?>("gitRepositoryURL")
|
static let gitURL = DefaultsKey<URL?>("gitURL")
|
||||||
static let gitRepositoryAuthenticationMethod = DefaultsKey<String?>("gitRepositoryAuthenticationMethod")
|
static let gitAuthenticationMethod = DefaultsKey<String?>("gitAuthenticationMethod")
|
||||||
static let gitRepositoryUsername = DefaultsKey<String?>("gitRepositoryUsername")
|
static let gitUsername = DefaultsKey<String?>("gitUsername")
|
||||||
static let gitRepositoryPasswordAttempts = DefaultsKey<Int>("gitRepositoryPasswordAttempts")
|
static let gitPasswordAttempts = DefaultsKey<Int>("gitPasswordAttempts")
|
||||||
static let gitRepositorySSHPublicKeyURL = DefaultsKey<URL?>("gitRepositorySSHPublicKeyURL")
|
static let gitSSHPublicKeyURL = DefaultsKey<URL?>("gitSSHPublicKeyURL")
|
||||||
static let gitRepositorySSHPrivateKeyURL = DefaultsKey<URL?>("gitRepositorySSHPrivateKeyURL")
|
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")
|
static let lastSyncedTime = DefaultsKey<Date?>("lastSyncedTime")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,10 @@ class Globals {
|
||||||
static let pgpPublicKeyPath = "\(documentPath)/gpg_key.pub"
|
static let pgpPublicKeyPath = "\(documentPath)/gpg_key.pub"
|
||||||
static let pgpPrivateKeyPath = "\(documentPath)/gpg_key"
|
static let pgpPrivateKeyPath = "\(documentPath)/gpg_key"
|
||||||
|
|
||||||
static let sshPublicKeyURL = URL(fileURLWithPath: "\(documentPath)/ssh_key.pub")
|
static let gitSSHPublicKeyPath = "\(documentPath)/ssh_key.pub"
|
||||||
static let sshPrivateKeyURL = URL(fileURLWithPath: "\(documentPath)/ssh_key")
|
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 let repositoryPath = "\(libraryPath)/password-store"
|
||||||
static var passcodeConfiguration = PasscodeLockConfiguration()
|
static var passcodeConfiguration = PasscodeLockConfiguration()
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,16 @@ class Utils {
|
||||||
Utils.removeKeychain(name: ".pgpKeyPassphrase")
|
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? {
|
static func getPasswordFromKeychain(name: String) -> String? {
|
||||||
let keychain = Keychain(service: "me.mssun.passforios")
|
let keychain = Keychain(service: "me.mssun.passforios")
|
||||||
do {
|
do {
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,9 @@ struct GitCredential {
|
||||||
var credential: GTCredential? = nil
|
var credential: GTCredential? = nil
|
||||||
switch self.credential {
|
switch self.credential {
|
||||||
case let .http(userName, password):
|
case let .http(userName, password):
|
||||||
print(Defaults[.gitRepositoryPasswordAttempts])
|
print(Defaults[.gitPasswordAttempts])
|
||||||
var newPassword: String = password
|
var newPassword: String = password
|
||||||
if Defaults[.gitRepositoryPasswordAttempts] != 0 {
|
if Defaults[.gitPasswordAttempts] != 0 {
|
||||||
let sem = DispatchSemaphore(value: 0)
|
let sem = DispatchSemaphore(value: 0)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
SVProgressHUD.dismiss()
|
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)
|
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
|
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: {_ in
|
||||||
newPassword = alert.textFields!.first!.text!
|
newPassword = alert.textFields!.first!.text!
|
||||||
PasswordStore.shared.gitRepositoryPassword = newPassword
|
PasswordStore.shared.gitPassword = newPassword
|
||||||
sem.signal()
|
sem.signal()
|
||||||
}))
|
}))
|
||||||
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
|
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in
|
||||||
Defaults[.gitRepositoryPasswordAttempts] = -1
|
Defaults[.gitPasswordAttempts] = -1
|
||||||
sem.signal()
|
sem.signal()
|
||||||
})
|
})
|
||||||
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
alert.addTextField(configurationHandler: {(textField: UITextField!) in
|
||||||
textField.text = PasswordStore.shared.gitRepositoryPassword
|
textField.text = PasswordStore.shared.gitPassword
|
||||||
textField.isSecureTextEntry = true
|
textField.isSecureTextEntry = true
|
||||||
})
|
})
|
||||||
topController.present(alert, animated: true, completion: nil)
|
topController.present(alert, animated: true, completion: nil)
|
||||||
|
|
@ -56,12 +56,12 @@ struct GitCredential {
|
||||||
}
|
}
|
||||||
let _ = sem.wait(timeout: DispatchTime.distantFuture)
|
let _ = sem.wait(timeout: DispatchTime.distantFuture)
|
||||||
}
|
}
|
||||||
if Defaults[.gitRepositoryPasswordAttempts] == -1 {
|
if Defaults[.gitPasswordAttempts] == -1 {
|
||||||
Defaults[.gitRepositoryPasswordAttempts] = 0
|
Defaults[.gitPasswordAttempts] = 0
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
Defaults[.gitRepositoryPasswordAttempts] += 1
|
Defaults[.gitPasswordAttempts] += 1
|
||||||
PasswordStore.shared.gitRepositoryPassword = newPassword
|
PasswordStore.shared.gitPassword = newPassword
|
||||||
credential = try? GTCredential(userName: userName, password: newPassword)
|
credential = try? GTCredential(userName: userName, password: newPassword)
|
||||||
case let .ssh(userName, password, publicKeyFile, privateKeyFile, passwordNotSetCallback):
|
case let .ssh(userName, password, publicKeyFile, privateKeyFile, passwordNotSetCallback):
|
||||||
|
|
||||||
|
|
@ -76,7 +76,7 @@ struct GitCredential {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save password for the future
|
// 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
|
// nil is expected in case of empty password
|
||||||
if newPassword == "" {
|
if newPassword == "" {
|
||||||
|
|
@ -112,7 +112,7 @@ class PasswordStore {
|
||||||
|
|
||||||
var gitSignatureForNow: GTSignature {
|
var gitSignatureForNow: GTSignature {
|
||||||
get {
|
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")
|
return Utils.getPasswordFromKeychain(name: "pgpKeyPassphrase")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var gitRepositoryPassword: String? {
|
var gitPassword: String? {
|
||||||
set {
|
set {
|
||||||
Utils.addPasswordToKeychain(name: "gitRepositoryPassword", password: newValue)
|
Utils.addPasswordToKeychain(name: "gitPassword", password: newValue)
|
||||||
}
|
}
|
||||||
get {
|
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)
|
print(error)
|
||||||
}
|
}
|
||||||
initPGPKeys()
|
initPGPKeys()
|
||||||
if Defaults[.gitRepositoryAuthenticationMethod] == "Password" {
|
initGitCredential()
|
||||||
gitCredential = GitCredential(credential: GitCredential.Credential.http(userName: Defaults[.gitRepositoryUsername]!, password: Utils.getPasswordFromKeychain(name: "gitRepositoryPassword") ?? ""))
|
}
|
||||||
} else if Defaults[.gitRepositoryAuthenticationMethod] == "SSH Key"{
|
|
||||||
|
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(
|
gitCredential = GitCredential(
|
||||||
credential: GitCredential.Credential.ssh(
|
credential: GitCredential.Credential.ssh(
|
||||||
userName: Defaults[.gitRepositoryUsername]!,
|
userName: Defaults[.gitUsername]!,
|
||||||
password: Utils.getPasswordFromKeychain(name: "gitRepositorySSHPrivateKeyPassphrase") ?? "",
|
password: gitSSHPrivateKeyPassphrase ?? "",
|
||||||
publicKeyFile: Globals.sshPublicKeyURL,
|
publicKeyFile: Globals.gitSSHPublicKeyURL,
|
||||||
privateKeyFile: Globals.sshPrivateKeyURL,
|
privateKeyFile: Globals.gitSSHPrivateKeyURL,
|
||||||
passwordNotSetCallback: nil
|
passwordNotSetCallback: nil
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
gitCredential = nil
|
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() {
|
public func initPGPKeys() {
|
||||||
|
|
@ -654,8 +682,8 @@ class PasswordStore {
|
||||||
|
|
||||||
Utils.removeFileIfExists(atPath: Globals.pgpPublicKeyPath)
|
Utils.removeFileIfExists(atPath: Globals.pgpPublicKeyPath)
|
||||||
Utils.removeFileIfExists(atPath: Globals.pgpPrivateKeyPath)
|
Utils.removeFileIfExists(atPath: Globals.pgpPrivateKeyPath)
|
||||||
Utils.removeFileIfExists(at: Globals.sshPrivateKeyURL)
|
Utils.removeFileIfExists(atPath: Globals.gitSSHPublicKeyPath)
|
||||||
Utils.removeFileIfExists(at: Globals.sshPublicKeyURL)
|
Utils.removeFileIfExists(atPath: Globals.gitSSHPrivateKeyPath)
|
||||||
|
|
||||||
Utils.removeAllKeychain()
|
Utils.removeAllKeychain()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue