Add ability to import SSH keys from the Files app

This commit is contained in:
Danny Moesch 2020-02-15 18:14:06 +01:00 committed by Mingshen Sun
parent 94a5f8c501
commit d33e63cd83
8 changed files with 176 additions and 0 deletions

View file

@ -20,6 +20,7 @@
3032327422C7F710009EBD9C /* KeyFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3032327322C7F710009EBD9C /* KeyFileManager.swift */; }; 3032327422C7F710009EBD9C /* KeyFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3032327322C7F710009EBD9C /* KeyFileManager.swift */; };
3032328A22C9FBA2009EBD9C /* KeyFileManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3032328922C9FBA2009EBD9C /* KeyFileManagerTest.swift */; }; 3032328A22C9FBA2009EBD9C /* KeyFileManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3032328922C9FBA2009EBD9C /* KeyFileManagerTest.swift */; };
3032328E22CBD4CD009EBD9C /* CryptographicKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3032328D22CBD4CD009EBD9C /* CryptographicKeys.swift */; }; 3032328E22CBD4CD009EBD9C /* CryptographicKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3032328D22CBD4CD009EBD9C /* CryptographicKeys.swift */; };
30650E7123F82AF8005CCD5E /* SSHKeyFileImportTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30650E7023F82AF8005CCD5E /* SSHKeyFileImportTableViewController.swift */; };
30650E7323F847FC005CCD5E /* KeyImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30650E7223F847FC005CCD5E /* KeyImporter.swift */; }; 30650E7323F847FC005CCD5E /* KeyImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30650E7223F847FC005CCD5E /* KeyImporter.swift */; };
3066AD6823EE0D6500F65535 /* PGPKeyImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3066AD6723EE0D6500F65535 /* PGPKeyImporter.swift */; }; 3066AD6823EE0D6500F65535 /* PGPKeyImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3066AD6723EE0D6500F65535 /* PGPKeyImporter.swift */; };
30697C2A21F63C5A0064FCAC /* NotificationNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C2321F63C580064FCAC /* NotificationNames.swift */; }; 30697C2A21F63C5A0064FCAC /* NotificationNames.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30697C2321F63C580064FCAC /* NotificationNames.swift */; };
@ -242,6 +243,7 @@
3032327322C7F710009EBD9C /* KeyFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyFileManager.swift; sourceTree = "<group>"; }; 3032327322C7F710009EBD9C /* KeyFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyFileManager.swift; sourceTree = "<group>"; };
3032328922C9FBA2009EBD9C /* KeyFileManagerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyFileManagerTest.swift; sourceTree = "<group>"; }; 3032328922C9FBA2009EBD9C /* KeyFileManagerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyFileManagerTest.swift; sourceTree = "<group>"; };
3032328D22CBD4CD009EBD9C /* CryptographicKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptographicKeys.swift; sourceTree = "<group>"; }; 3032328D22CBD4CD009EBD9C /* CryptographicKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptographicKeys.swift; sourceTree = "<group>"; };
30650E7023F82AF8005CCD5E /* SSHKeyFileImportTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SSHKeyFileImportTableViewController.swift; sourceTree = "<group>"; };
30650E7223F847FC005CCD5E /* KeyImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyImporter.swift; sourceTree = "<group>"; }; 30650E7223F847FC005CCD5E /* KeyImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyImporter.swift; sourceTree = "<group>"; };
3066AD6723EE0D6500F65535 /* PGPKeyImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PGPKeyImporter.swift; sourceTree = "<group>"; }; 3066AD6723EE0D6500F65535 /* PGPKeyImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PGPKeyImporter.swift; sourceTree = "<group>"; };
30697C2321F63C580064FCAC /* NotificationNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationNames.swift; sourceTree = "<group>"; }; 30697C2321F63C580064FCAC /* NotificationNames.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationNames.swift; sourceTree = "<group>"; };
@ -721,6 +723,7 @@
DCAAF7441E2FA66800AB94BC /* SettingsTableViewController.swift */, DCAAF7441E2FA66800AB94BC /* SettingsTableViewController.swift */,
DC037CA91E4B8EAE00609409 /* SpecialThanksTableViewController.swift */, DC037CA91E4B8EAE00609409 /* SpecialThanksTableViewController.swift */,
DCC441531E916382008A90C4 /* SSHKeyArmorImportTableViewController.swift */, DCC441531E916382008A90C4 /* SSHKeyArmorImportTableViewController.swift */,
30650E7023F82AF8005CCD5E /* SSHKeyFileImportTableViewController.swift */,
DC8963BF1E38EEB900828B09 /* SSHKeyUrlImportTableViewController.swift */, DC8963BF1E38EEB900828B09 /* SSHKeyUrlImportTableViewController.swift */,
); );
path = Controllers; path = Controllers;
@ -1383,6 +1386,7 @@
A2A61C201EEFABAD00CFE063 /* UtilsExtension.swift in Sources */, A2A61C201EEFABAD00CFE063 /* UtilsExtension.swift in Sources */,
DC8963C01E38EEB900828B09 /* SSHKeyUrlImportTableViewController.swift in Sources */, DC8963C01E38EEB900828B09 /* SSHKeyUrlImportTableViewController.swift in Sources */,
3066AD6823EE0D6500F65535 /* PGPKeyImporter.swift in Sources */, 3066AD6823EE0D6500F65535 /* PGPKeyImporter.swift in Sources */,
30650E7123F82AF8005CCD5E /* SSHKeyFileImportTableViewController.swift in Sources */,
DC193FFA1E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift in Sources */, DC193FFA1E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift in Sources */,
DCFB77AB1E503729008DE471 /* ContentProvider.swift in Sources */, DCFB77AB1E503729008DE471 /* ContentProvider.swift in Sources */,
DCA0499C1E3362F400522E8F /* PGPKeyUrlImportTableViewController.swift in Sources */, DCA0499C1E3362F400522E8F /* PGPKeyUrlImportTableViewController.swift in Sources */,

View file

@ -496,6 +496,7 @@
<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="setGitSSHKeyByURLSegue" 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"/> <segue destination="WgM-cY-mig" kind="show" identifier="setGitSSHKeyByArmorSegue" id="HLm-0q-hUg"/>
<segue destination="Jnt-d8-bQx" kind="show" identifier="setGitSSHKeyByFileSegue" id="4Bn-TN-gBI"/>
</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"/>
@ -1878,6 +1879,87 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
</objects> </objects>
<point key="canvasLocation" x="3845" y="2969"/> <point key="canvasLocation" x="3845" y="2969"/>
</scene> </scene>
<!--SSH Key-->
<scene sceneID="kOg-Uk-VyV">
<objects>
<tableViewController id="Jnt-d8-bQx" customClass="SSHKeyFileImportTableViewController" customModule="pass" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="urc-Su-PL8">
<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="Nlg-0d-JGw">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="11" reuseIdentifier="sshPrivateKeyFile" textLabel="1h3-cQ-4bj" detailTextLabel="pqH-wg-EIn" style="IBUITableViewCellStyleSubtitle" id="yyX-RO-fws" userLabel="SSH private key from file description">
<rect key="frame" x="0.0" y="18" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="yyX-RO-fws" id="QcH-CI-X9n">
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="ASCII-Armor Keys" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="1h3-cQ-4bj">
<rect key="frame" x="20.000000000000007" y="6" width="121.66666666666667" height="17"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="SshAsciiArmorFileExplanation." lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="pqH-wg-EIn" customClass="UICodeHighlightingLabel" customModule="pass" customModuleProvider="target">
<rect key="frame" x="20" y="23" width="191.33333333333334" height="16.333333333333332"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" name="HelveticaNeue" family="Helvetica Neue" pointSize="14"/>
<color key="textColor" white="0.40782000000000002" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection headerTitle="PRIVATE KEY" id="pEq-Ii-lwe" userLabel="PRIVATE KEY">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="sshPrivateKeyFile" textLabel="9KE-VA-cx2" rowHeight="52" style="IBUITableViewCellStyleDefault" id="qWo-Q3-m4Z" userLabel="SSH private key file">
<rect key="frame" x="0.0" y="118" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="qWo-Q3-m4Z" id="Jjt-3W-boo">
<rect key="frame" x="0.0" y="0.0" width="383" height="52"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Select file ..." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="9KE-VA-cx2">
<rect key="frame" x="20" y="0.0" width="355" height="52"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
<connections>
<outlet property="dataSource" destination="Jnt-d8-bQx" id="Dse-Bk-idM"/>
<outlet property="delegate" destination="Jnt-d8-bQx" id="fKs-GA-48h"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="SSH Key" id="vaA-as-6yJ">
<barButtonItem key="rightBarButtonItem" style="done" systemItem="done" id="OmP-jt-rJh">
<connections>
<action selector="doneButtonTapped:" destination="Jnt-d8-bQx" id="skg-sj-oLw"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="sshPrivateKeyFile" destination="qWo-Q3-m4Z" id="vrz-89-rLv"/>
<segue destination="T4H-XT-sbN" kind="unwind" identifier="importSSHKeySegue" unwindAction="importSSHKeyWithSegue:" id="yy9-zG-Yes"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="rw2-Uq-xF8" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="T4H-XT-sbN" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="6990" y="2967"/>
</scene>
</scenes> </scenes>
<resources> <resources>
<image name="Lock" width="25" height="25"/> <image name="Lock" width="25" height="25"/>

View file

@ -247,6 +247,9 @@ class GitRepositorySettingsTableViewController: UITableViewController {
optionMenu.addAction(UIAlertAction(title: SSHKeyArmorImportTableViewController.menuLabel, style: .default) { _ in optionMenu.addAction(UIAlertAction(title: SSHKeyArmorImportTableViewController.menuLabel, style: .default) { _ in
self.performSegue(withIdentifier: "setGitSSHKeyByArmorSegue", sender: self) self.performSegue(withIdentifier: "setGitSSHKeyByArmorSegue", sender: self)
}) })
optionMenu.addAction(UIAlertAction(title: SSHKeyFileImportTableViewController.menuLabel, style: .default) { _ in
self.performSegue(withIdentifier: "setGitSSHKeyByFileSegue", sender: self)
})
if isReadyToUse() { if isReadyToUse() {
optionMenu.addAction(UIAlertAction(title: "\(Self.menuLabel) (\("Import".localize()))", style: .default) { _ in optionMenu.addAction(UIAlertAction(title: "\(Self.menuLabel) (\("Import".localize()))", style: .default) { _ in

View file

@ -0,0 +1,72 @@
//
// SSHKeyFileImportTableViewController.swift
// pass
//
// Created by Danny Moesch on 15.02.20.
// Copyright © 2020 Bob Sun. All rights reserved.
//
import passKit
import SVProgressHUD
class SSHKeyFileImportTableViewController: AutoCellHeightUITableViewController {
@IBOutlet weak var sshPrivateKeyFile: UITableViewCell!
private var privateKey: String? = nil
@IBAction func doneButtonTapped(_ sender: Any) {
performSegue(withIdentifier: "importSSHKeySegue", sender: self)
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
let picker = UIDocumentPickerViewController(documentTypes: ["public.data"], in: .open)
cell?.isSelected = false
guard cell == sshPrivateKeyFile else {
return
}
picker.delegate = self
if #available(iOS 13.0, *) {
picker.shouldShowFileExtensions = true
}
present(picker, animated: true, completion: nil)
}
}
extension SSHKeyFileImportTableViewController: UIDocumentPickerDelegate {
func documentPicker(_: UIDocumentPickerViewController, didPickDocumentsAt url: [URL]) {
guard let url = url.first else {
return
}
let fileName = url.lastPathComponent
do {
privateKey = try String(contentsOf: url, encoding: .ascii)
sshPrivateKeyFile.textLabel?.text = fileName
} catch {
Utils.alert(title: "CannotImportFile".localize(), message: "FileCannotBeImported.".localize(fileName), controller: self)
}
}
}
extension SSHKeyFileImportTableViewController: KeyImporter {
static let keySource = KeySource.file
static let label = "LoadFromFiles".localize()
func isReadyToUse() -> Bool {
guard privateKey != nil else {
Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKeyUrl.".localize(), controller: self)
return false
}
return true
}
func importKeys() throws {
guard let privateKey = privateKey else {
return
}
try KeyFileManager.PrivateSsh.importKey(from: privateKey)
}
}

View file

@ -280,6 +280,12 @@ gibt den Schlüssel in diesem speziellen Format aus. Die Zwischenablage wird nac
gibt den Schlüssel in diesem speziellen Format aus. Kopiere ihn so zu einem Key-Server."; gibt den Schlüssel in diesem speziellen Format aus. Kopiere ihn so zu einem Key-Server.";
"SshAsciiArmorFileExplanation." = "Das Format \"ASCII-Armor\" ist anders als das Binärformat eine einfache Zeichenkette. Der Befehl
$ cat ~/.ssh/id_rsa
gibt den Schlüssel in diesem speziellen Format aus. Kopiere ihn so zu einem Speicherort, der für die Dateien-App zugänglich ist.";
"GpgAsciiArmorCopyExplanation." = "GnuPG unterstützt die Kommandozeilenoption \"-a\", welche die Schlüssel im Format \"ASCII-Armor\" ausgibt. Es ist anders als das Binärformat eine einfache Zeichenkette. Die Befehle "GpgAsciiArmorCopyExplanation." = "GnuPG unterstützt die Kommandozeilenoption \"-a\", welche die Schlüssel im Format \"ASCII-Armor\" ausgibt. Es ist anders als das Binärformat eine einfache Zeichenkette. Die Befehle
$ gpg --export -a KEY_ID $ gpg --export -a KEY_ID

View file

@ -23,6 +23,9 @@
/* Class = "UIBarButtonItem"; title = "Back"; ObjectID = "9yM-Mg-Cg8"; */ /* Class = "UIBarButtonItem"; title = "Back"; ObjectID = "9yM-Mg-Cg8"; */
"9yM-Mg-Cg8.title" = "Zurück"; "9yM-Mg-Cg8.title" = "Zurück";
/* Class = "UILabel"; text = "Select file ..."; ObjectID = "9KE-VA-cx2"; */
"9KE-VA-cx2.text" = "Datei auswählen ...";
/* Class = "UILabel"; text = "Private Key URL"; ObjectID = "C2w-dd-roS"; */ /* Class = "UILabel"; text = "Private Key URL"; ObjectID = "C2w-dd-roS"; */
"C2w-dd-roS.text" = "URL des privaten Schlüssels"; "C2w-dd-roS.text" = "URL des privaten Schlüssels";

View file

@ -280,6 +280,12 @@ to get the key in this specific format. The clipboard will be cleared 45s after
to get the key in this specific format. Subsequently, copy it to your secured key server."; to get the key in this specific format. Subsequently, copy it to your secured key server.";
"SshAsciiArmorFileExplanation." = "The ASCII-armored key format is similar to unencoded documents rather than the binary format. Use
$ cat ~/.ssh/id_rsa
to get the key in this specific format. Subsequently, copy it to a location accessible by the Files app.";
"GpgAsciiArmorCopyExplanation." = "GnuPG supports the command-line option \"-a\" that causes output to be generated in an ASCII-armored format similar to unencoded documents rather than the binary format. Use "GpgAsciiArmorCopyExplanation." = "GnuPG supports the command-line option \"-a\" that causes output to be generated in an ASCII-armored format similar to unencoded documents rather than the binary format. Use
$ gpg --export -a KEY_ID $ gpg --export -a KEY_ID

Binary file not shown.