Merge branch 'release/0.2.3'

This commit is contained in:
Bob Sun 2017-04-02 22:57:13 -07:00
commit ec987c115f
No known key found for this signature in database
GPG key ID: 1F86BA2052FED3B4
57 changed files with 1483 additions and 391 deletions

2
.gitignore vendored
View file

@ -62,7 +62,7 @@ Carthage/Build
# For more information about the recommended setup visit: # For more information about the recommended setup visit:
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
fastlane fastlane/README.md
fastlane/report.xml fastlane/report.xml
fastlane/Preview.html fastlane/Preview.html
fastlane/screenshots fastlane/screenshots

9
.travis.yml Normal file
View file

@ -0,0 +1,9 @@
language: objective-c
osx_image: xcode8.3
branches:
only:
- develop
before_install:
- echo -e "machine github.com\n login $GITHUB_ACCESS_TOKEN" >> ~/.netrc
script:
- ./fastlane/travis.sh

View file

@ -1,6 +1,6 @@
github "SVProgressHUD/SVProgressHUD" github "SVProgressHUD/SVProgressHUD"
github "radex/SwiftyUserDefaults" github "radex/SwiftyUserDefaults"
github "libgit2/objective-git" "master" github "libgit2/objective-git"
github "zahlz/SwiftPasscodeLock" "master" github "zahlz/SwiftPasscodeLock" "master"
github "bitserf/FavIcon" github "bitserf/FavIcon"
github "kishikawakatsumi/KeychainAccess" "master" github "kishikawakatsumi/KeychainAccess" "master"

View file

@ -4,6 +4,7 @@
[![GitHub release](https://img.shields.io/github/release/mssun/pass-ios.svg)](https://github.com/mssun/pass-ios/releases) [![GitHub release](https://img.shields.io/github/release/mssun/pass-ios.svg)](https://github.com/mssun/pass-ios/releases)
![Swift 3.1](https://img.shields.io/badge/Swift-3.1-orange.svg) ![Swift 3.1](https://img.shields.io/badge/Swift-3.1-orange.svg)
[![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/passforios/passforios) [![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/passforios/passforios)
[![Build Status](https://travis-ci.org/mssun/passforios.svg?branch=develop)](https://travis-ci.org/mssun/passforios)
Pass is an iOS client compatible with [ZX2C4's Pass command line Pass is an iOS client compatible with [ZX2C4's Pass command line
application](http://www.passwordstore.org/). It is a password manager using application](http://www.passwordstore.org/). It is a password manager using

4
fastlane/Appfile Normal file
View file

@ -0,0 +1,4 @@
app_identifier ENV["APP_IDENTIFIER"]
apple_id ENV["APPLE_ID"]
team_id ENV["TEAM_ID"]
itc_team_id ENV["ITC_TEAM_ID"]

101
fastlane/Fastfile Normal file
View file

@ -0,0 +1,101 @@
# Customise this file, documentation can be found here:
# https://github.com/fastlane/fastlane/tree/master/fastlane/docs
# All available actions: https://docs.fastlane.tools/actions
# can also be listed using the `fastlane actions` command
# Change the syntax highlighting to Ruby
# All lines starting with a # are ignored when running `fastlane`
# If you want to automatically update fastlane if a new version is available:
# update_fastlane
# This is the minimum version number required.
# Update this, if you use features of a newer version
fastlane_version "2.17.0"
default_platform :ios
platform :ios do
before_all do
cocoapods
carthage(platform: "iOS")
end
desc "Travis"
lane :travis do
test
beta
end
desc "Runs all the tests"
lane :test do
scan(
scheme: "pass",
device: "iPhone 7"
)
end
desc "Submit a new Beta Build to Apple TestFlight"
desc "This will also make sure the profile is up to date"
lane :beta do
create_keychain(
name: ENV["MATCH_KEYCHAIN_NAME"],
password: ENV["MATCH_KEYCHAIN_PASSWORD"],
default_keychain: true,
unlock: true,
timeout: 3600,
add_to_search_list: true
)
match(
type: "appstore",
keychain_name: ENV["MATCH_KEYCHAIN_NAME"],
keychain_password: ENV["MATCH_KEYCHAIN_PASSWORD"],
readonly: true
)
# ensure_git_status_clean
increment_build_number(
build_number: latest_testflight_build_number + 1,
xcodeproj: "pass.xcodeproj"
)
# commit_version_bump(xcodeproj: "pass.xcodeproj")
# push_to_git_remote
gym(scheme: "pass")
pilot(skip_waiting_for_build_processing: true)
mailgun(
postmaster: ENV["MY_POSTMASTER"],
apikey: ENV["MY_API_KEY"],
to: ENV["DESTINATION_EMAIL"],
from: ENV["EMAIL_FROM_NAME"],
reply_to: ENV["EMAIL_REPLY_TO"],
subject: "A new build of Pass for iOS has been uploaded",
success: true,
app_link: "https://github.com/mssun/passforios",
ci_build_link: "https://travis-ci.org/mssun/passforios",
message: "A new build has been uploaded by Travis CI.",
)
end
desc "Deploy a new version to the App Store"
lane :release do
# match(type: "appstore")
# snapshot
gym(scheme: "pass") # Build your app - more options available
deliver(force: true)
# frameit
end
# You can define as many lanes as you want
after_all do |lane|
end
error do |lane, exception|
end
end
# More information about multiple platforms in fastlane: https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Platforms.md
# All available actions: https://docs.fastlane.tools/actions
# fastlane reports which actions are used
# No personal data is recorded. Learn more at https://github.com/fastlane/enhancer

9
fastlane/Matchfile Normal file
View file

@ -0,0 +1,9 @@
git_url "https://github.com/mssun/certificates-passforios.git"
type "development" # The default type, can be: appstore, adhoc, enterprise or development
# app_identifier ["tools.fastlane.app", "tools.fastlane.app2"]
# username "user@fastlane.tools" # Your Apple Developer Portal username
# For all available options run `fastlane match --help`
# Remove the # in the beginning of the line to enable the other options

9
fastlane/travis.sh Executable file
View file

@ -0,0 +1,9 @@
#!/bin/sh
gem update fastlane
if [ "$TRAVIS_PULL_REQUEST" == "true" ]; then
fastlane test;
else
fastlane travis;
fi
exit $?

View file

@ -24,6 +24,7 @@
DC037CBF1E4ED4E100609409 /* TextViewTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC037CBD1E4ED4E100609409 /* TextViewTableViewCell.swift */; }; DC037CBF1E4ED4E100609409 /* TextViewTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC037CBD1E4ED4E100609409 /* TextViewTableViewCell.swift */; };
DC037CC01E4ED4E100609409 /* TextViewTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DC037CBE1E4ED4E100609409 /* TextViewTableViewCell.xib */; }; DC037CC01E4ED4E100609409 /* TextViewTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DC037CBE1E4ED4E100609409 /* TextViewTableViewCell.xib */; };
DC1208581E35EBE60042942E /* ObjectiveGit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1208571E35EBE60042942E /* ObjectiveGit.framework */; }; DC1208581E35EBE60042942E /* ObjectiveGit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1208571E35EBE60042942E /* ObjectiveGit.framework */; };
DC13B1511E8640810097803F /* passTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC13B1501E8640810097803F /* passTests.swift */; };
DC193FFA1E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC193FF91E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift */; }; DC193FFA1E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC193FF91E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift */; };
DC193FFC1E49E0340077E0A3 /* PasscodeLock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC193FFB1E49E0340077E0A3 /* PasscodeLock.framework */; }; DC193FFC1E49E0340077E0A3 /* PasscodeLock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC193FFB1E49E0340077E0A3 /* PasscodeLock.framework */; };
DC193FFE1E49E0760077E0A3 /* PasscodeLockRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC193FFD1E49E0760077E0A3 /* PasscodeLockRepository.swift */; }; DC193FFE1E49E0760077E0A3 /* PasscodeLockRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC193FFD1E49E0760077E0A3 /* PasscodeLockRepository.swift */; };
@ -52,10 +53,10 @@
DCC277D21E30D6EA00402246 /* pass.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DCC408C81E30BA1300F29B0E /* pass.xcdatamodeld */; }; DCC277D21E30D6EA00402246 /* pass.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DCC408C81E30BA1300F29B0E /* pass.xcdatamodeld */; };
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 */; };
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 */; };
DCE6C2681E71261C003038C6 /* PasswordWithFolderTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DCE6C2661E71261C003038C6 /* PasswordWithFolderTableViewCell.xib */; };
DCFB779A1E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCFB77981E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift */; }; DCFB779A1E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCFB77981E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift */; };
DCFB779B1E4F3BCF008DE471 /* TitleTextFieldTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DCFB77991E4F3BCF008DE471 /* TitleTextFieldTableViewCell.xib */; }; DCFB779B1E4F3BCF008DE471 /* TitleTextFieldTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DCFB77991E4F3BCF008DE471 /* TitleTextFieldTableViewCell.xib */; };
DCFB779E1E4F40C7008DE471 /* FillPasswordTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCFB779C1E4F40C7008DE471 /* FillPasswordTableViewCell.swift */; }; DCFB779E1E4F40C7008DE471 /* FillPasswordTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCFB779C1E4F40C7008DE471 /* FillPasswordTableViewCell.swift */; };
@ -67,6 +68,16 @@
DCFB77AB1E503729008DE471 /* ContentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCFB77AA1E503729008DE471 /* ContentTableViewCell.swift */; }; DCFB77AB1E503729008DE471 /* ContentTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCFB77AA1E503729008DE471 /* ContentTableViewCell.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
DC13B1531E8640810097803F /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = DC917BCB1E2E8231000FDF54 /* Project object */;
proxyType = 1;
remoteGlobalIDString = DC917BD21E2E8231000FDF54;
remoteInfo = pass;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
274CCFCF32444A2FF46BE7F4 /* Pods-pass.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-pass.debug.xcconfig"; path = "Pods/Target Support Files/Pods-pass/Pods-pass.debug.xcconfig"; sourceTree = "<group>"; }; 274CCFCF32444A2FF46BE7F4 /* Pods-pass.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-pass.debug.xcconfig"; path = "Pods/Target Support Files/Pods-pass/Pods-pass.debug.xcconfig"; sourceTree = "<group>"; };
A262A58C1E68749C006B0890 /* Base32.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Base32.framework; path = Carthage/Build/iOS/Base32.framework; sourceTree = "<group>"; }; A262A58C1E68749C006B0890 /* Base32.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Base32.framework; path = Carthage/Build/iOS/Base32.framework; sourceTree = "<group>"; };
@ -87,6 +98,9 @@
DC037CBD1E4ED4E100609409 /* TextViewTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextViewTableViewCell.swift; sourceTree = "<group>"; }; DC037CBD1E4ED4E100609409 /* TextViewTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextViewTableViewCell.swift; sourceTree = "<group>"; };
DC037CBE1E4ED4E100609409 /* TextViewTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TextViewTableViewCell.xib; sourceTree = "<group>"; }; DC037CBE1E4ED4E100609409 /* TextViewTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TextViewTableViewCell.xib; sourceTree = "<group>"; };
DC1208571E35EBE60042942E /* ObjectiveGit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjectiveGit.framework; path = Carthage/Build/iOS/ObjectiveGit.framework; sourceTree = "<group>"; }; DC1208571E35EBE60042942E /* ObjectiveGit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ObjectiveGit.framework; path = Carthage/Build/iOS/ObjectiveGit.framework; sourceTree = "<group>"; };
DC13B14E1E8640810097803F /* passTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = passTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
DC13B1501E8640810097803F /* passTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = passTests.swift; sourceTree = "<group>"; };
DC13B1521E8640810097803F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
DC193FF91E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsTableViewController.swift; sourceTree = "<group>"; }; DC193FF91E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedSettingsTableViewController.swift; sourceTree = "<group>"; };
DC193FFB1E49E0340077E0A3 /* PasscodeLock.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PasscodeLock.framework; path = Carthage/Build/iOS/PasscodeLock.framework; sourceTree = "<group>"; }; DC193FFB1E49E0340077E0A3 /* PasscodeLock.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PasscodeLock.framework; path = Carthage/Build/iOS/PasscodeLock.framework; sourceTree = "<group>"; };
DC193FFD1E49E0760077E0A3 /* PasscodeLockRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasscodeLockRepository.swift; sourceTree = "<group>"; }; DC193FFD1E49E0760077E0A3 /* PasscodeLockRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasscodeLockRepository.swift; sourceTree = "<group>"; };
@ -118,10 +132,10 @@
DCC408A31E2FCC9E00F29B0E /* PasswordStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordStore.swift; sourceTree = "<group>"; }; DCC408A31E2FCC9E00F29B0E /* PasswordStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordStore.swift; sourceTree = "<group>"; };
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>"; };
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>"; };
DCE6C2661E71261C003038C6 /* PasswordWithFolderTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PasswordWithFolderTableViewCell.xib; sourceTree = "<group>"; };
DCFB77981E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TitleTextFieldTableViewCell.swift; sourceTree = "<group>"; }; DCFB77981E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TitleTextFieldTableViewCell.swift; sourceTree = "<group>"; };
DCFB77991E4F3BCF008DE471 /* TitleTextFieldTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TitleTextFieldTableViewCell.xib; sourceTree = "<group>"; }; DCFB77991E4F3BCF008DE471 /* TitleTextFieldTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TitleTextFieldTableViewCell.xib; sourceTree = "<group>"; };
DCFB779C1E4F40C7008DE471 /* FillPasswordTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FillPasswordTableViewCell.swift; sourceTree = "<group>"; }; DCFB779C1E4F40C7008DE471 /* FillPasswordTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FillPasswordTableViewCell.swift; sourceTree = "<group>"; };
@ -134,6 +148,13 @@
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
DC13B14B1E8640810097803F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
DC917BD01E2E8231000FDF54 /* Frameworks */ = { DC917BD01E2E8231000FDF54 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -162,6 +183,15 @@
name = Pods; name = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
DC13B14F1E8640810097803F /* passTests */ = {
isa = PBXGroup;
children = (
DC13B1501E8640810097803F /* passTests.swift */,
DC13B1521E8640810097803F /* Info.plist */,
);
path = passTests;
sourceTree = "<group>";
};
DC19400C1E4B39400077E0A3 /* Controllers */ = { DC19400C1E4B39400077E0A3 /* Controllers */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -177,12 +207,14 @@
DCA049991E335CC800522E8F /* GitServerSettingTableViewController.swift */, DCA049991E335CC800522E8F /* GitServerSettingTableViewController.swift */,
DC037CA51E4B883900609409 /* OpenSourceComponentsTableViewController.swift */, DC037CA51E4B883900609409 /* OpenSourceComponentsTableViewController.swift */,
DC4914981E434600007FF592 /* PasswordDetailTableViewController.swift */, DC4914981E434600007FF592 /* PasswordDetailTableViewController.swift */,
DCC441511E8F6C06008A90C4 /* RawPasswordViewController.swift */,
DCFB77A81E502FF6008DE471 /* PasswordEditorTableViewController.swift */, DCFB77A81E502FF6008DE471 /* PasswordEditorTableViewController.swift */,
DC5734AD1E439AD400D09270 /* PasswordsViewController.swift */, DC5734AD1E439AD400D09270 /* PasswordsViewController.swift */,
DCA0499B1E3362F400522E8F /* PGPKeySettingTableViewController.swift */, DCA0499B1E3362F400522E8F /* PGPKeySettingTableViewController.swift */,
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>";
@ -229,8 +261,6 @@
DC037CBD1E4ED4E100609409 /* TextViewTableViewCell.swift */, DC037CBD1E4ED4E100609409 /* TextViewTableViewCell.swift */,
DC037CBE1E4ED4E100609409 /* TextViewTableViewCell.xib */, DC037CBE1E4ED4E100609409 /* TextViewTableViewCell.xib */,
DCFB77AA1E503729008DE471 /* ContentTableViewCell.swift */, DCFB77AA1E503729008DE471 /* ContentTableViewCell.swift */,
DCE6C2651E71261C003038C6 /* PasswordWithFolderTableViewCell.swift */,
DCE6C2661E71261C003038C6 /* PasswordWithFolderTableViewCell.xib */,
); );
path = Views; path = Views;
sourceTree = "<group>"; sourceTree = "<group>";
@ -239,6 +269,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DC917BD51E2E8231000FDF54 /* pass */, DC917BD51E2E8231000FDF54 /* pass */,
DC13B14F1E8640810097803F /* passTests */,
DC917BD41E2E8231000FDF54 /* Products */, DC917BD41E2E8231000FDF54 /* Products */,
DC917BED1E2F38C4000FDF54 /* Frameworks */, DC917BED1E2F38C4000FDF54 /* Frameworks */,
A51B01737D08DB47BB58F85A /* Pods */, A51B01737D08DB47BB58F85A /* Pods */,
@ -249,6 +280,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DC917BD31E2E8231000FDF54 /* pass.app */, DC917BD31E2E8231000FDF54 /* pass.app */,
DC13B14E1E8640810097803F /* passTests.xctest */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@ -289,6 +321,24 @@
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
DC13B14D1E8640810097803F /* passTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = DC13B1571E8640810097803F /* Build configuration list for PBXNativeTarget "passTests" */;
buildPhases = (
DC13B14A1E8640810097803F /* Sources */,
DC13B14B1E8640810097803F /* Frameworks */,
DC13B14C1E8640810097803F /* Resources */,
);
buildRules = (
);
dependencies = (
DC13B1541E8640810097803F /* PBXTargetDependency */,
);
name = passTests;
productName = passTests;
productReference = DC13B14E1E8640810097803F /* passTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
DC917BD21E2E8231000FDF54 /* pass */ = { DC917BD21E2E8231000FDF54 /* pass */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = DC917BE51E2E8231000FDF54 /* Build configuration list for PBXNativeTarget "pass" */; buildConfigurationList = DC917BE51E2E8231000FDF54 /* Build configuration list for PBXNativeTarget "pass" */;
@ -316,14 +366,20 @@
DC917BCB1E2E8231000FDF54 /* Project object */ = { DC917BCB1E2E8231000FDF54 /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftUpdateCheck = 0820; LastSwiftUpdateCheck = 0830;
LastUpgradeCheck = 0820; LastUpgradeCheck = 0820;
ORGANIZATIONNAME = "Bob Sun"; ORGANIZATIONNAME = "Bob Sun";
TargetAttributes = { TargetAttributes = {
DC13B14D1E8640810097803F = {
CreatedOnToolsVersion = 8.3;
DevelopmentTeam = 4WDM8E95VU;
ProvisioningStyle = Automatic;
TestTargetID = DC917BD21E2E8231000FDF54;
};
DC917BD21E2E8231000FDF54 = { DC917BD21E2E8231000FDF54 = {
CreatedOnToolsVersion = 8.2.1; CreatedOnToolsVersion = 8.2.1;
DevelopmentTeam = 4WDM8E95VU; DevelopmentTeam = 4WDM8E95VU;
ProvisioningStyle = Automatic; ProvisioningStyle = Manual;
}; };
}; };
}; };
@ -341,11 +397,19 @@
projectRoot = ""; projectRoot = "";
targets = ( targets = (
DC917BD21E2E8231000FDF54 /* pass */, DC917BD21E2E8231000FDF54 /* pass */,
DC13B14D1E8640810097803F /* passTests */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */ /* Begin PBXResourcesBuildPhase section */
DC13B14C1E8640810097803F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
DC917BD11E2E8231000FDF54 /* Resources */ = { DC917BD11E2E8231000FDF54 /* Resources */ = {
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -357,7 +421,6 @@
DCDDEAB01E4639F300F68193 /* LabelTableViewCell.xib in Resources */, DCDDEAB01E4639F300F68193 /* LabelTableViewCell.xib in Resources */,
DC917BDC1E2E8231000FDF54 /* Main.storyboard in Resources */, DC917BDC1E2E8231000FDF54 /* Main.storyboard in Resources */,
A2802BFA1E70813A00879216 /* SliderTableViewCell.xib in Resources */, A2802BFA1E70813A00879216 /* SliderTableViewCell.xib in Resources */,
DCE6C2681E71261C003038C6 /* PasswordWithFolderTableViewCell.xib in Resources */,
DCFB779B1E4F3BCF008DE471 /* TitleTextFieldTableViewCell.xib in Resources */, DCFB779B1E4F3BCF008DE471 /* TitleTextFieldTableViewCell.xib in Resources */,
DCFB779F1E4F40C7008DE471 /* FillPasswordTableViewCell.xib in Resources */, DCFB779F1E4F40C7008DE471 /* FillPasswordTableViewCell.xib in Resources */,
DC037CC01E4ED4E100609409 /* TextViewTableViewCell.xib in Resources */, DC037CC01E4ED4E100609409 /* TextViewTableViewCell.xib in Resources */,
@ -437,12 +500,21 @@
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
DC13B14A1E8640810097803F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
DC13B1511E8640810097803F /* passTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
DC917BCF1E2E8231000FDF54 /* Sources */ = { DC917BCF1E2E8231000FDF54 /* Sources */ = {
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
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 */,
@ -452,7 +524,6 @@
DC5F385B1E56AADB00C69ACA /* PGPKeyArmorSettingTableViewController.swift in Sources */, DC5F385B1E56AADB00C69ACA /* PGPKeyArmorSettingTableViewController.swift in Sources */,
A27424D91E7C35960093F436 /* NotificationNames.swift in Sources */, A27424D91E7C35960093F436 /* NotificationNames.swift in Sources */,
DCAAF7451E2FA66800AB94BC /* SettingsTableViewController.swift in Sources */, DCAAF7451E2FA66800AB94BC /* SettingsTableViewController.swift in Sources */,
DCE6C2671E71261C003038C6 /* PasswordWithFolderTableViewCell.swift in Sources */,
DCFB77A71E502DF9008DE471 /* EditPasswordTableViewController.swift in Sources */, DCFB77A71E502DF9008DE471 /* EditPasswordTableViewController.swift in Sources */,
DCA0499A1E335CC800522E8F /* GitServerSettingTableViewController.swift in Sources */, DCA0499A1E335CC800522E8F /* GitServerSettingTableViewController.swift in Sources */,
DCDDEAB31E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift in Sources */, DCDDEAB31E4896BF00F68193 /* PasswordDetailTitleTableViewCell.swift in Sources */,
@ -469,6 +540,7 @@
DC037CB21E4CAB1700609409 /* AboutRepositoryTableViewController.swift in Sources */, DC037CB21E4CAB1700609409 /* AboutRepositoryTableViewController.swift in Sources */,
DC037CB01E4CA51F00609409 /* GeneralSettingsTableViewController.swift in Sources */, DC037CB01E4CA51F00609409 /* GeneralSettingsTableViewController.swift in Sources */,
DC037CB81E4DD1A500609409 /* AddPasswordTableViewController.swift in Sources */, DC037CB81E4DD1A500609409 /* AddPasswordTableViewController.swift in Sources */,
DCC441521E8F6C06008A90C4 /* RawPasswordViewController.swift in Sources */,
DC1940001E49E1A60077E0A3 /* PasscodeLockConfiguration.swift in Sources */, DC1940001E49E1A60077E0A3 /* PasscodeLockConfiguration.swift in Sources */,
DC917BD71E2E8231000FDF54 /* AppDelegate.swift in Sources */, DC917BD71E2E8231000FDF54 /* AppDelegate.swift in Sources */,
DCFB779A1E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift in Sources */, DCFB779A1E4F3BCF008DE471 /* TitleTextFieldTableViewCell.swift in Sources */,
@ -484,6 +556,14 @@
}; };
/* End PBXSourcesBuildPhase section */ /* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
DC13B1541E8640810097803F /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = DC917BD21E2E8231000FDF54 /* pass */;
targetProxy = DC13B1531E8640810097803F /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */ /* Begin PBXVariantGroup section */
DC917BDA1E2E8231000FDF54 /* Main.storyboard */ = { DC917BDA1E2E8231000FDF54 /* Main.storyboard */ = {
isa = PBXVariantGroup; isa = PBXVariantGroup;
@ -504,6 +584,38 @@
/* End PBXVariantGroup section */ /* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
DC13B1551E8640810097803F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
DEVELOPMENT_TEAM = 4WDM8E95VU;
INFOPLIST_FILE = passTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pass.app/pass";
};
name = Debug;
};
DC13B1561E8640810097803F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
DEVELOPMENT_TEAM = 4WDM8E95VU;
INFOPLIST_FILE = passTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/pass.app/pass";
};
name = Release;
};
DC917BE31E2E8231000FDF54 /* Debug */ = { DC917BE31E2E8231000FDF54 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
@ -601,7 +713,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 24; CURRENT_PROJECT_VERSION = 2;
DEFINES_MODULE = NO; DEFINES_MODULE = NO;
DEVELOPMENT_TEAM = 4WDM8E95VU; DEVELOPMENT_TEAM = 4WDM8E95VU;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@ -620,6 +732,8 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios; PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "893c10b3-79b1-46f7-914a-e625bf10d665";
PROVISIONING_PROFILE_SPECIFIER = "match Development me.mssun.passforios";
SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/pass/Helpers/Objective-CBridgingHeader.h"; SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/pass/Helpers/Objective-CBridgingHeader.h";
SWIFT_VERSION = 3.0; SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
@ -632,8 +746,8 @@
baseConfigurationReference = AEAD6B31EAF5D061447A68CC /* Pods-pass.release.xcconfig */; baseConfigurationReference = AEAD6B31EAF5D061447A68CC /* Pods-pass.release.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CURRENT_PROJECT_VERSION = 24; CURRENT_PROJECT_VERSION = 2;
DEFINES_MODULE = NO; DEFINES_MODULE = NO;
DEVELOPMENT_TEAM = 4WDM8E95VU; DEVELOPMENT_TEAM = 4WDM8E95VU;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@ -652,6 +766,8 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios; PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE = "aefeea85-1194-4db2-9ce4-fb9995e2fdff";
PROVISIONING_PROFILE_SPECIFIER = "match AppStore me.mssun.passforios";
SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/pass/Helpers/Objective-CBridgingHeader.h"; SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/pass/Helpers/Objective-CBridgingHeader.h";
SWIFT_VERSION = 3.0; SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2"; TARGETED_DEVICE_FAMILY = "1,2";
@ -662,6 +778,15 @@
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
DC13B1571E8640810097803F /* Build configuration list for PBXNativeTarget "passTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
DC13B1551E8640810097803F /* Debug */,
DC13B1561E8640810097803F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
DC917BCE1E2E8231000FDF54 /* Build configuration list for PBXProject "pass" */ = { DC917BCE1E2E8231000FDF54 /* Build configuration list for PBXProject "pass" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (

View file

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0820"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
BuildableName = "pass.app"
BlueprintName = "pass"
ReferencedContainer = "container:pass.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DC13B14D1E8640810097803F"
BuildableName = "passTests.xctest"
BlueprintName = "passTests"
ReferencedContainer = "container:pass.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
BuildableName = "pass.app"
BlueprintName = "pass"
ReferencedContainer = "container:pass.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
BuildableName = "pass.app"
BlueprintName = "pass"
ReferencedContainer = "container:pass.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<EnvironmentVariables>
<EnvironmentVariable
key = "OS_ACTIVITY_MODE"
value = "disable"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DC917BD21E2E8231000FDF54"
BuildableName = "pass.app"
BlueprintName = "pass"
ReferencedContainer = "container:pass.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "Screenshot-50.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "Screenshot-100.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 B

View file

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "Copy-50.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "Copy-100.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 B

View file

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "Horizontal Settings Mixer-50.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "Horizontal Settings Mixer-75.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

View file

@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "not-visible-interface-symbol-of-an-eye-with-a-slash-on-it.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "Refresh-64.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "Refresh-75.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 939 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "eye-visible-outlined-interface-symbol.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="YoR-iB-XAd"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12106.1" systemVersion="16F43c" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="YoR-iB-XAd">
<device id="retina5_5" orientation="portrait"> <device id="retina5_5" orientation="portrait">
<adaptation id="fullscreen"/> <adaptation id="fullscreen"/>
</device> </device>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12074.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/> <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
@ -158,7 +158,7 @@
</tableViewCell> </tableViewCell>
</cells> </cells>
</tableViewSection> </tableViewSection>
<tableViewSection headerTitle="PASSCODE" id="Cx7-e4-wCO"> <tableViewSection headerTitle="SECURITY" id="Cx7-e4-wCO">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="passcodeTableViewCell" textLabel="RaZ-6t-0CU" detailTextLabel="HXb-ZX-HUv" style="IBUITableViewCellStyleValue1" id="6Y0-mj-qhA"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="passcodeTableViewCell" textLabel="RaZ-6t-0CU" detailTextLabel="HXb-ZX-HUv" style="IBUITableViewCellStyleValue1" id="6Y0-mj-qhA">
<rect key="frame" x="0.0" y="223" width="414" height="44"/> <rect key="frame" x="0.0" y="223" width="414" height="44"/>
@ -167,8 +167,8 @@
<rect key="frame" x="0.0" y="0.0" width="381" height="43.666666666666664"/> <rect key="frame" x="0.0" y="0.0" width="381" height="43.666666666666664"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Passcode" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="RaZ-6t-0CU"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Passcode Lock" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="RaZ-6t-0CU">
<rect key="frame" x="15" y="11.999999999999998" width="74.333333333333329" height="20.333333333333332"/> <rect key="frame" x="15" y="11.999999999999998" width="115" height="20.333333333333332"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/> <nil key="textColor"/>
@ -288,7 +288,7 @@
<rect key="frame" x="0.0" y="28" width="414" height="44"/> <rect key="frame" x="0.0" y="28" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="OfB-1N-1Am" id="fh0-au-C6q"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="OfB-1N-1Am" id="fh0-au-C6q">
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/> <rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" tag="101" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="00/00/0000" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hj4-EP-LFW"> <label opaque="NO" userInteractionEnabled="NO" tag="101" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="00/00/0000" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hj4-EP-LFW">
@ -340,10 +340,10 @@
<tableViewSection headerTitle="Git Repository URL" id="pbe-W6-w4V"> <tableViewSection headerTitle="Git Repository URL" id="pbe-W6-w4V">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="gitRepositoryURLTabelViewCell" rowHeight="52" id="FRr-pf-aPO"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="gitRepositoryURLTabelViewCell" rowHeight="52" id="FRr-pf-aPO">
<rect key="frame" x="0.0" y="55" width="414" height="52"/> <rect key="frame" x="0.0" y="55.5" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="FRr-pf-aPO" id="60A-PS-qGe"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="FRr-pf-aPO" id="60A-PS-qGe">
<rect key="frame" x="0.0" y="0.0" width="414" height="51"/> <rect key="frame" x="0.0" y="0.0" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Git Repository URL" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="EVT-VU-sCi"> <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Git Repository URL" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="EVT-VU-sCi">
@ -366,10 +366,10 @@
<tableViewSection headerTitle="Username" id="fRu-A2-SCk"> <tableViewSection headerTitle="Username" id="fRu-A2-SCk">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="usernameTableVIewCell" rowHeight="52" id="tnj-5U-kMB"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="usernameTableVIewCell" rowHeight="52" id="tnj-5U-kMB">
<rect key="frame" x="0.0" y="163" width="414" height="52"/> <rect key="frame" x="0.0" y="163.5" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tnj-5U-kMB" id="f0c-pI-MSJ"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="tnj-5U-kMB" id="f0c-pI-MSJ">
<rect key="frame" x="0.0" y="0.0" width="414" height="51"/> <rect key="frame" x="0.0" y="0.0" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Username" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="TMg-Gk-7nG"> <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Username" textAlignment="natural" minimumFontSize="17" clearButtonMode="whileEditing" translatesAutoresizingMaskIntoConstraints="NO" id="TMg-Gk-7nG">
@ -392,10 +392,10 @@
<tableViewSection headerTitle="Authentication Method" id="h0N-tI-shZ"> <tableViewSection headerTitle="Authentication Method" id="h0N-tI-shZ">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="2" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="KrP-nb-haa"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="2" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="KrP-nb-haa">
<rect key="frame" x="0.0" y="271" width="414" height="44"/> <rect key="frame" x="0.0" y="271.5" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KrP-nb-haa" id="1uB-oE-kfI"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KrP-nb-haa" id="1uB-oE-kfI">
<rect key="frame" x="0.0" y="0.0" width="414" height="43"/> <rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Password" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LfQ-Af-j2O"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Password" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LfQ-Af-j2O">
@ -423,10 +423,10 @@
<inset key="separatorInset" minX="62" minY="0.0" maxX="0.0" maxY="0.0"/> <inset key="separatorInset" minX="62" minY="0.0" maxX="0.0" maxY="0.0"/>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" accessoryType="detailButton" hidesAccessoryWhenEditing="NO" indentationLevel="2" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="Qmt-bo-CuJ"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="blue" accessoryType="detailButton" hidesAccessoryWhenEditing="NO" indentationLevel="2" indentationWidth="0.0" shouldIndentWhileEditing="NO" id="Qmt-bo-CuJ">
<rect key="frame" x="0.0" y="315" width="414" height="44"/> <rect key="frame" x="0.0" y="315.5" width="414" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Qmt-bo-CuJ" id="p3u-8b-h3U"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Qmt-bo-CuJ" id="p3u-8b-h3U">
<rect key="frame" x="0.0" y="0.0" width="367" height="43"/> <rect key="frame" x="0.0" y="0.0" width="367" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SSH Key" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ezz-76-a53"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="SSH Key" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ezz-76-a53">
@ -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"/>
@ -503,7 +504,7 @@
<rect key="frame" x="0.0" y="35" width="414" height="52"/> <rect key="frame" x="0.0" y="35" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="BYZ-9g-xZy" id="Zfn-rK-sN1"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="BYZ-9g-xZy" id="Zfn-rK-sN1">
<rect key="frame" x="0.0" y="0.0" width="414" height="52"/> <rect key="frame" x="0.0" y="0.0" width="414" height="51.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Public Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dWi-eh-7Eq"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Public Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dWi-eh-7Eq">
@ -533,7 +534,7 @@
<rect key="frame" x="0.0" y="87" width="414" height="52"/> <rect key="frame" x="0.0" y="87" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="vpk-J8-j7t" id="1td-qT-6ts"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="vpk-J8-j7t" id="1td-qT-6ts">
<rect key="frame" x="0.0" y="0.0" width="414" height="52"/> <rect key="frame" x="0.0" y="0.0" width="414" height="51.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Private Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qht-RC-Yeg"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Private Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Qht-RC-Yeg">
@ -626,7 +627,7 @@
<scene sceneID="9wY-d0-fB1"> <scene sceneID="9wY-d0-fB1">
<objects> <objects>
<tableViewController id="tW4-E9-CGv" customClass="PasswordDetailTableViewController" customModule="pass" customModuleProvider="target" sceneMemberID="viewController"> <tableViewController id="tW4-E9-CGv" customClass="PasswordDetailTableViewController" customModule="pass" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="hfi-6O-04U"> <tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="hfi-6O-04U">
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/> <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/> <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
@ -638,6 +639,7 @@
</tableView> </tableView>
<connections> <connections>
<segue destination="eui-w4-P7T" kind="show" identifier="editPasswordSegue" id="Ydg-pZ-oNS"/> <segue destination="eui-w4-P7T" kind="show" identifier="editPasswordSegue" id="Ydg-pZ-oNS"/>
<segue destination="kNf-lG-BeC" kind="presentation" identifier="showRawPasswordSegue" modalTransitionStyle="flipHorizontal" id="qpR-3X-eyt"/>
</connections> </connections>
</tableViewController> </tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="9sC-44-OKL" userLabel="First Responder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="9sC-44-OKL" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -736,6 +738,50 @@
</objects> </objects>
<point key="canvasLocation" x="6084" y="601"/> <point key="canvasLocation" x="6084" y="601"/>
</scene> </scene>
<!--Raw Password View Controller-->
<scene sceneID="Oqg-Vh-EYD">
<objects>
<viewController id="mlB-OK-hLo" customClass="RawPasswordViewController" customModule="pass" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="XeK-cv-AXf"/>
<viewControllerLayoutGuide type="bottom" id="7JD-uM-IyS"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="5YZ-6i-LST">
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<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"/>
<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>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstAttribute="trailingMargin" secondItem="3dt-Ph-4As" secondAttribute="trailing" id="2IV-7r-9eG"/>
<constraint firstItem="7JD-uM-IyS" firstAttribute="top" secondItem="3dt-Ph-4As" secondAttribute="bottom" id="3yp-aL-exH"/>
<constraint firstItem="3dt-Ph-4As" firstAttribute="top" secondItem="XeK-cv-AXf" secondAttribute="bottom" constant="-60" id="R2h-nh-8eZ"/>
<constraint firstAttribute="leadingMargin" secondItem="3dt-Ph-4As" secondAttribute="leading" id="jgf-j1-lNa"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="c13-zM-tLf">
<barButtonItem key="leftBarButtonItem" title="Back" id="9yM-Mg-Cg8">
<connections>
<segue destination="pNY-ul-yzB" kind="unwind" unwindAction="backWithSegue:" id="SzI-Au-9rJ"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="rawPasswordTextView" destination="3dt-Ph-4As" id="SVL-F8-5yD"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="zgb-Ji-ZBp" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="pNY-ul-yzB" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="7721.739130434783" y="-24.456521739130437"/>
</scene>
<!--About Repository Table View Controller--> <!--About Repository Table View Controller-->
<scene sceneID="u1v-BP-jaG"> <scene sceneID="u1v-BP-jaG">
<objects> <objects>
@ -791,7 +837,7 @@
<rect key="frame" x="0.0" y="35" width="414" height="52"/> <rect key="frame" x="0.0" y="35" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Jy1-4S-Lvf" id="tJE-ww-okf"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Jy1-4S-Lvf" id="tJE-ww-okf">
<rect key="frame" x="0.0" y="0.0" width="414" height="52"/> <rect key="frame" x="0.0" y="0.0" width="414" height="51.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Public Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Oys-xP-ZrB"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Public Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Oys-xP-ZrB">
@ -821,7 +867,7 @@
<rect key="frame" x="0.0" y="87" width="414" height="52"/> <rect key="frame" x="0.0" y="87" width="414" height="52"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="MA5-lE-8dT" id="pTv-Wj-psC"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="MA5-lE-8dT" id="pTv-Wj-psC">
<rect key="frame" x="0.0" y="0.0" width="414" height="52"/> <rect key="frame" x="0.0" y="0.0" width="414" height="51.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Private Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="C2w-dd-roS"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Private Key URL" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="C2w-dd-roS">
@ -847,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="52"/>
<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>
@ -886,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">
@ -1135,7 +1150,7 @@
<rect key="frame" x="0.0" y="35" width="414" height="170"/> <rect key="frame" x="0.0" y="35" width="414" height="170"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Pv0-ev-stj" id="ywz-II-W1g"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Pv0-ev-stj" id="ywz-II-W1g">
<rect key="frame" x="0.0" y="0.0" width="414" height="170"/> <rect key="frame" x="0.0" y="0.0" width="414" height="169.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <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="xzQ-5d-kdL"> <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="xzQ-5d-kdL">
@ -1193,7 +1208,7 @@
<rect key="frame" x="0.0" y="261" width="414" height="160"/> <rect key="frame" x="0.0" y="261" width="414" height="160"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Lom-iT-l16" id="eya-Tv-r0q"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Lom-iT-l16" id="eya-Tv-r0q">
<rect key="frame" x="0.0" y="0.0" width="414" height="160"/> <rect key="frame" x="0.0" y="0.0" width="414" height="159.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oyB-oI-1fS"> <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="oyB-oI-1fS">
@ -1249,7 +1264,7 @@ pfZ36xQbOAQYKKf6ZTT5R/Y=
<rect key="frame" x="0.0" y="477" width="414" height="160"/> <rect key="frame" x="0.0" y="477" width="414" height="160"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="J8U-ev-FRQ" id="eb0-vb-Fcc"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="J8U-ev-FRQ" id="eb0-vb-Fcc">
<rect key="frame" x="0.0" y="0.0" width="414" height="160"/> <rect key="frame" x="0.0" y="0.0" width="414" height="159.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lrQ-Ln-ZOv"> <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="lrQ-Ln-ZOv">
@ -1326,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">
@ -1346,6 +1361,218 @@ pfZ36xQbOAQYKKf6ZTT5R/Y=
</objects> </objects>
<point key="canvasLocation" x="5131.884057971015" y="4307.608695652174"/> <point key="canvasLocation" x="5131.884057971015" y="4307.608695652174"/>
</scene> </scene>
<!--Navigation Controller-->
<scene sceneID="Ps2-MC-JQX">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="kNf-lG-BeC" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="Dx6-8j-IzX">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="mlB-OK-hLo" kind="relationship" relationship="rootViewController" id="wp3-xi-lwY"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="ycf-Zv-ej8" userLabel="First Responder" sceneMemberID="firstResponder"/>
</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> </scenes>
<resources> <resources>
<image name="Lock" width="25" height="25"/> <image name="Lock" width="25" height="25"/>

View file

@ -63,7 +63,7 @@ class AboutRepositoryTableViewController: BasicStaticTableViewController {
[[.style: CellDataStyle.value1, .accessoryType: type, .title: "Passwords", .detailText: numberOfPasswordsString], [[.style: CellDataStyle.value1, .accessoryType: type, .title: "Passwords", .detailText: numberOfPasswordsString],
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Size", .detailText: sizeOfRepositoryString], [.style: CellDataStyle.value1, .accessoryType: type, .title: "Size", .detailText: sizeOfRepositoryString],
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Local Commits", .detailText: String(self?.passwordStore.numberOfLocalCommits() ?? 0)], [.style: CellDataStyle.value1, .accessoryType: type, .title: "Local Commits", .detailText: String(self?.passwordStore.numberOfLocalCommits() ?? 0)],
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Last Synced", .detailText: Utils.getLastUpdatedTimeString()], [.style: CellDataStyle.value1, .accessoryType: type, .title: "Last Synced", .detailText: Utils.getLastSyncedTimeString()],
[.style: CellDataStyle.value1, .accessoryType: type, .title: "Commits", .detailText: numberOfCommitsString], [.style: CellDataStyle.value1, .accessoryType: type, .title: "Commits", .detailText: numberOfCommitsString],
[.title: "Commit Logs", .action: "segue", .link: "showCommitLogsSegue"], [.title: "Commit Logs", .action: "segue", .link: "showCommitLogsSegue"],
], ],

View file

@ -22,14 +22,15 @@ class EditPasswordTableViewController: PasswordEditorTableViewController {
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if identifier == "saveEditPasswordSegue" { if identifier == "saveEditPasswordSegue" {
let nameCell = tableView.cellForRow(at: IndexPath(row: 0, section: 0)) as! ContentTableViewCell if let nameCell = tableView.cellForRow(at: IndexPath(row: 0, section: 0)) as? ContentTableViewCell {
if nameCell.getContent() != password?.name { if nameCell.getContent() != password?.name {
let alertTitle = "Cannot Save Edit" let alertTitle = "Cannot Save Edit"
let alertMessage = "Editing name is not supported." let alertMessage = "Editing name is not supported."
Utils.alert(title: alertTitle, message: alertMessage, controller: self) { Utils.alert(title: alertTitle, message: alertMessage, controller: self) {
nameCell.setContent(content: self.password!.name) nameCell.setContent(content: self.password!.name)
}
return false
} }
return false
} }
} }
return true return true

View file

@ -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)
}
}

View file

@ -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)
}
} }

View file

@ -39,6 +39,11 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
content = "" content = ""
} }
init(title: String) {
self.title = title
self.content = ""
}
init(title: String, content: String) { init(title: String, content: String) {
self.title = title self.title = title
self.content = content self.content = content
@ -46,24 +51,39 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
} }
private struct TableSection { private struct TableSection {
var title: String var type: PasswordDetailTableViewControllerSectionType
var header: String?
var item: Array<TableCell> var item: Array<TableCell>
init(type: PasswordDetailTableViewControllerSectionType) {
self.type = type
header = nil
item = [TableCell]()
}
init(type: PasswordDetailTableViewControllerSectionType, header: String) {
self.init(type: type)
self.header = header
}
} }
private var tableData = Array<TableSection>() private var tableData = Array<TableSection>()
private enum PasswordDetailTableViewControllerSectionType {
case name, main, addition, misc
}
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
tableView.register(UINib(nibName: "LabelTableViewCell", bundle: nil), forCellReuseIdentifier: "labelCell") tableView.register(UINib(nibName: "LabelTableViewCell", bundle: nil), forCellReuseIdentifier: "labelCell")
tableView.register(UINib(nibName: "PasswordDetailTitleTableViewCell", bundle: nil), forCellReuseIdentifier: "passwordDetailTitleTableViewCell") tableView.register(UINib(nibName: "PasswordDetailTitleTableViewCell", bundle: nil), forCellReuseIdentifier: "passwordDetailTitleTableViewCell")
passwordCategoryText = passwordEntity!.getCategoryText() passwordCategoryText = passwordEntity!.getCategoryText()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(PasswordDetailTableViewController.tapMenu(recognizer:))) let tapGesture = UITapGestureRecognizer(target: self, action: #selector(PasswordDetailTableViewController.tapMenu(recognizer:)))
tapGesture.cancelsTouchesInView = false
tableView.addGestureRecognizer(tapGesture) tableView.addGestureRecognizer(tapGesture)
tapGesture.delegate = self tapGesture.delegate = self
tableView.contentInset = UIEdgeInsetsMake(-36, 0, 0, 0); tableView.contentInset = UIEdgeInsetsMake(-36, 0, 44, 0);
tableView.rowHeight = UITableViewAutomaticDimension tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 52 tableView.estimatedRowHeight = 52
@ -224,23 +244,31 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
private func setTableData() { private func setTableData() {
self.tableData = Array<TableSection>() self.tableData = Array<TableSection>()
tableData.append(TableSection(title: "", item: []))
tableData[0].item.append(TableCell()) // name section
var tableDataIndex = 1 var section = TableSection(type: .name)
self.tableData.append(TableSection(title: "", item: [])) section.item.append(TableCell())
tableData.append(section)
// main section
section = TableSection(type: .main)
let password = self.password! let password = self.password!
if let username = password.getUsername() { if let username = password.getUsername() {
self.tableData[tableDataIndex].item.append(TableCell(title: "username", content: username)) section.item.append(TableCell(title: "username", content: username))
} }
self.tableData[tableDataIndex].item.append(TableCell(title: "password", content: password.password)) section.item.append(TableCell(title: "password", content: password.password))
tableData.append(section)
// addition section
// show one time password // show one time password
if password.otpType != .none { if password.otpType != .none {
if let (title, otp) = self.password?.getOtpStrings() { if let (title, otp) = self.password?.getOtpStrings() {
self.tableData.append(TableSection(title: "One time password", item: [])) section = TableSection(type: .addition, header: "One Time Password")
tableDataIndex += 1 section.item.append(TableCell(title: title, content: otp))
oneTimePasswordIndexPath = IndexPath(row: 0, section: tableDataIndex) tableData.append(section)
self.tableData[tableDataIndex].item.append(TableCell(title: title, content: otp)) oneTimePasswordIndexPath = IndexPath(row: 0, section: tableData.count - 1)
} }
} }
@ -252,12 +280,18 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
(!Password.otpKeywords.contains($0) || !Defaults[.isHideOTPOn]) } (!Password.otpKeywords.contains($0) || !Defaults[.isHideOTPOn]) }
if filteredAdditionKeys.count > 0 { if filteredAdditionKeys.count > 0 {
self.tableData.append(TableSection(title: "additions", item: [])) section = TableSection(type: .addition, header: "additions")
tableDataIndex += 1
for additionKey in filteredAdditionKeys { for additionKey in filteredAdditionKeys {
self.tableData[tableDataIndex].item.append(TableCell(title: additionKey, content: password.additions[additionKey]!)) section.item.append(TableCell(title: additionKey, content: password.additions[additionKey]!))
} }
tableData.append(section)
} }
// misc section
section = TableSection(type: .misc)
section.item.append(TableCell(title: "Show Raw"))
tableData.append(section)
} }
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
@ -267,6 +301,12 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
editController.password = password editController.password = password
} }
} }
} else if segue.identifier == "showRawPasswordSegue" {
if let controller = segue.destination as? UINavigationController {
if let controller = controller.viewControllers.first as? RawPasswordViewController {
controller.password = password
}
}
} }
} }
@ -328,6 +368,16 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
} }
} }
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
if touch.view!.isKind(of: UIButton.classForCoder()) {
return false
}
return true
}
@IBAction func back(segue:UIStoryboardSegue) {
}
func getNextHOTP() { func getNextHOTP() {
guard password != nil, passwordEntity != nil, password?.otpType == .hotp else { guard password != nil, passwordEntity != nil, password?.otpType == .hotp else {
DispatchQueue.main.async { DispatchQueue.main.async {
@ -380,8 +430,9 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let sectionIndex = indexPath.section let sectionIndex = indexPath.section
let rowIndex = indexPath.row let rowIndex = indexPath.row
let tableDataItem = tableData[sectionIndex].item[rowIndex]
if sectionIndex == 0 && rowIndex == 0 { switch(tableData[sectionIndex].type) {
case .name:
let cell = tableView.dequeueReusableCell(withIdentifier: "passwordDetailTitleTableViewCell", for: indexPath) as! PasswordDetailTitleTableViewCell let cell = tableView.dequeueReusableCell(withIdentifier: "passwordDetailTitleTableViewCell", for: indexPath) as! PasswordDetailTitleTableViewCell
cell.passwordImageImageView.image = passwordImage ?? #imageLiteral(resourceName: "PasswordImagePlaceHolder") cell.passwordImageImageView.image = passwordImage ?? #imageLiteral(resourceName: "PasswordImagePlaceHolder")
var passwordName = passwordEntity!.name! var passwordName = passwordEntity!.name!
@ -390,22 +441,29 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
} }
cell.nameLabel.text = passwordName cell.nameLabel.text = passwordName
cell.categoryLabel.text = passwordCategoryText cell.categoryLabel.text = passwordCategoryText
cell.selectionStyle = .none
return cell return cell
} else { case .main, .addition:
let cell = tableView.dequeueReusableCell(withIdentifier: "labelCell", for: indexPath) as! LabelTableViewCell let cell = tableView.dequeueReusableCell(withIdentifier: "labelCell", for: indexPath) as! LabelTableViewCell
let titleData = tableData[sectionIndex].item[rowIndex].title let titleData = tableDataItem.title
let contentData = tableData[sectionIndex].item[rowIndex].content let contentData = tableDataItem.content
cell.delegatePasswordTableView = self cell.delegatePasswordTableView = self
cell.isPasswordCell = (titleData.lowercased() == "password" ? true : false) cell.isPasswordCell = (titleData.lowercased() == "password" ? true : false)
cell.isURLCell = (titleData.lowercased() == "url" ? true : false) cell.isURLCell = (titleData.lowercased() == "url" ? true : false)
cell.isHOTPCell = (titleData == "HMAC-based" ? true : false) cell.isHOTPCell = (titleData == "HMAC-based" ? true : false)
cell.cellData = LabelTableViewCellData(title: titleData, content: contentData) cell.cellData = LabelTableViewCellData(title: titleData, content: contentData)
cell.selectionStyle = .none
return cell
case .misc:
let cell = UITableViewCell()
cell.textLabel?.text = tableDataItem.title
cell.selectionStyle = .default
return cell return cell
} }
} }
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return tableData[section].title return tableData[section].header
} }
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
@ -430,10 +488,26 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
} }
override func tableView(_ tableView: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) -> Bool { override func tableView(_ tableView: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
return action == #selector(UIResponderStandardEditActions.copy(_:)) let section = tableData[indexPath.section]
switch(section.type) {
case .main, .addition:
return action == #selector(UIResponderStandardEditActions.copy(_:))
default:
return false
}
} }
override func tableView(_ tableView: UITableView, shouldShowMenuForRowAt indexPath: IndexPath) -> Bool { override func tableView(_ tableView: UITableView, shouldShowMenuForRowAt indexPath: IndexPath) -> Bool {
return true return true
} }
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let section = tableData[indexPath.section]
if section.type == .misc {
if section.item[indexPath.row].title == "Show Raw" {
performSegue(withIdentifier: "showRawPasswordSegue", sender: self)
}
}
tableView.deselectRow(at: indexPath, animated: true)
}
} }

View file

@ -7,6 +7,8 @@
// //
import UIKit import UIKit
import SwiftyUserDefaults
enum PasswordEditorCellType { enum PasswordEditorCellType {
case textFieldCell, textViewCell, fillPasswordCell, passwordLengthCell, deletePasswordCell case textFieldCell, textViewCell, fillPasswordCell, passwordLengthCell, deletePasswordCell
} }
@ -54,11 +56,6 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
tableView.estimatedRowHeight = 48 tableView.estimatedRowHeight = 48
self.tableView.sectionFooterHeight = UITableViewAutomaticDimension; self.tableView.sectionFooterHeight = UITableViewAutomaticDimension;
self.tableView.estimatedSectionFooterHeight = 0; self.tableView.estimatedSectionFooterHeight = 0;
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tableTapped))
tapGesture.delegate = self
tapGesture.cancelsTouchesInView = false
tableView.addGestureRecognizer(tapGesture)
} }
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
@ -76,7 +73,12 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
return fillPasswordCell! return fillPasswordCell!
case .passwordLengthCell: case .passwordLengthCell:
passwordLengthCell = tableView.dequeueReusableCell(withIdentifier: "passwordLengthCell", for: indexPath) as? SliderTableViewCell passwordLengthCell = tableView.dequeueReusableCell(withIdentifier: "passwordLengthCell", for: indexPath) as? SliderTableViewCell
passwordLengthCell?.reset(title: "Length", minimumValue: Globals.passwordMinimumLength, maximumValue: Globals.passwordMaximumLength, defaultValue: Globals.passwordDefaultLength) let lengthSetting = Globals.passwordDefaultLength[Defaults[.passwordGeneratorFlavor]] ??
Globals.passwordDefaultLength["Random"]
passwordLengthCell?.reset(title: "Length",
minimumValue: lengthSetting?.min ?? 0,
maximumValue: lengthSetting?.max ?? 0,
defaultValue: lengthSetting?.def ?? 0)
passwordLengthCell?.delegate = self passwordLengthCell?.delegate = self
return passwordLengthCell! return passwordLengthCell!
case .deletePasswordCell: case .deletePasswordCell:
@ -148,7 +150,7 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
hidePasswordSettings = false hidePasswordSettings = false
tableView.reloadSections([passwordSection], with: .fade) tableView.reloadSections([passwordSection], with: .fade)
} }
let length = passwordLengthCell?.roundedValue ?? Globals.passwordDefaultLength let length = passwordLengthCell?.roundedValue ?? 0
let plainPassword = Utils.generatePassword(length: length) let plainPassword = Utils.generatePassword(length: length)
Utils.copyToPasteboard(textToCopy: plainPassword) Utils.copyToPasteboard(textToCopy: plainPassword)
@ -159,35 +161,8 @@ class PasswordEditorTableViewController: UITableViewController, FillPasswordTabl
fillPasswordCell?.setContent(content: plainPassword) fillPasswordCell?.setContent(content: plainPassword)
} }
func tableTapped(recognizer: UITapGestureRecognizer) { func showHidePasswordSettings() {
if recognizer.state == UIGestureRecognizerState.ended { hidePasswordSettings = !hidePasswordSettings
let tapLocation = recognizer.location(in: self.tableView) tableView.reloadSections([passwordSection], with: .fade)
let tapIndexPath = self.tableView.indexPathForRow(at: tapLocation)
// do nothing, if delete is tapped (a temporary solution)
if tapIndexPath != nil, deletePasswordCell != nil,
tableView.cellForRow(at: tapIndexPath!) == deletePasswordCell {
return
}
// hide password settings (e.g., the length slider)
if tapIndexPath?.section != passwordSection, hidePasswordSettings == false {
hidePasswordSettings = true
tableView.reloadSections([passwordSection], with: .fade)
// select the row at tapIndexPath manually
if tapIndexPath != nil {
self.tableView(self.tableView, didSelectRowAt: tapIndexPath!)
}
}
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer is UITapGestureRecognizer {
// so that the tap gesture could be passed by
return true
} else {
return false
}
} }
} }

View file

@ -86,7 +86,6 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
passwordEntities = self.passwordStore.fetchPasswordEntityCoreData(parent: parent) passwordEntities = self.passwordStore.fetchPasswordEntityCoreData(parent: parent)
} else { } else {
passwordEntities = self.passwordStore.fetchPasswordEntityCoreData(withDir: false) passwordEntities = self.passwordStore.fetchPasswordEntityCoreData(withDir: false)
} }
passwordsTableEntries = passwordEntities.map { passwordsTableEntries = passwordEntities.map {
PasswordsTableEntry(title: $0.name!, isDir: $0.isDir, passwordEntity: $0) PasswordsTableEntry(title: $0.name!, isDir: $0.isDir, passwordEntity: $0)
@ -109,8 +108,8 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
SVProgressHUD.showProgress(progress, status: "Encrypting") SVProgressHUD.showProgress(progress, status: "Encrypting")
} }
}) })
DispatchQueue.main.async { DispatchQueue.main.async {
// will trigger reloadTableView() by a notification
SVProgressHUD.showSuccess(withStatus: "Done") SVProgressHUD.showSuccess(withStatus: "Done")
SVProgressHUD.dismiss(withDelay: 1) SVProgressHUD.dismiss(withDelay: 1)
} }
@ -144,8 +143,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
} }
DispatchQueue.main.async { DispatchQueue.main.async {
self.reloadTableView(parent: nil) self.reloadTableView(parent: nil)
Defaults[.lastUpdatedTime] = Date() Defaults[.gitPasswordAttempts] = 0
Defaults[.gitRepositoryPasswordAttempts] = 0
SVProgressHUD.showSuccess(withStatus: "Done") SVProgressHUD.showSuccess(withStatus: "Done")
SVProgressHUD.dismiss(withDelay: 1) SVProgressHUD.dismiss(withDelay: 1)
} }
@ -174,9 +172,9 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
reloadTableView(parent: nil) reloadTableView(parent: nil)
// reset the data table if some password (maybe another one) has been updated // reset the data table if some password (maybe another one) has been updated
NotificationCenter.default.addObserver(self, selector: #selector(reloadTableView as (Void) -> Void), name: .passwordStoreUpdated, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(actOnReloadTableViewRelatedNotification), name: .passwordStoreUpdated, object: nil)
// reset the data table if the disaply settings have been changed // reset the data table if the disaply settings have been changed
NotificationCenter.default.addObserver(self, selector: #selector(reloadTableView as (Void) -> Void), name: .passwordDisplaySettingChanged, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(actOnReloadTableViewRelatedNotification), name: .passwordDisplaySettingChanged, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(actOnSearchNotification), name: .passwordSearch, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(actOnSearchNotification), name: .passwordSearch, object: nil)
} }
@ -221,20 +219,23 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
} else { } else {
cell.textLabel?.text = "\(entry.title)" cell.textLabel?.text = "\(entry.title)"
cell.accessoryType = .disclosureIndicator cell.accessoryType = .disclosureIndicator
cell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .body)
cell.detailTextLabel?.text = "\(entry.passwordEntity?.children?.count ?? 0)" cell.detailTextLabel?.text = "\(entry.passwordEntity?.children?.count ?? 0)"
} }
return cell return cell
} else { } else {
let passwordWithFolderCell = tableView.dequeueReusableCell(withIdentifier: "passwordWithFolderTableViewCell", for: indexPath) as! PasswordWithFolderTableViewCell let cell = tableView.dequeueReusableCell(withIdentifier: "passwordTableViewCell", for: indexPath)
let entry = getPasswordEntry(by: indexPath) let entry = getPasswordEntry(by: indexPath)
if entry.passwordEntity!.synced { if entry.passwordEntity!.synced {
passwordWithFolderCell.passwordLabel?.text = entry.title cell.textLabel?.text = entry.title
} else { } else {
passwordWithFolderCell.passwordLabel?.text = "\(entry.title)" cell.textLabel?.text = "\(entry.title)"
} }
passwordWithFolderCell.folderLabel.text = entry.passwordEntity?.getCategoryText() cell.accessoryType = .none
passwordWithFolderCell.addGestureRecognizer(longPressGestureRecognizer) cell.detailTextLabel?.font = UIFont.preferredFont(forTextStyle: .footnote)
return passwordWithFolderCell cell.detailTextLabel?.text = entry.passwordEntity?.getCategoryText()
cell.addGestureRecognizer(longPressGestureRecognizer)
return cell
} }
} }
@ -429,7 +430,7 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
self.tableView.layer.removeAnimation(forKey: "UITableViewReloadDataAnimationKey") self.tableView.layer.removeAnimation(forKey: "UITableViewReloadDataAnimationKey")
// set the sync control title // set the sync control title
let atribbutedTitle = "Last Synced: \(Utils.getLastUpdatedTimeString())" let atribbutedTitle = "Last Synced: \(Utils.getLastSyncedTimeString())"
syncControl.attributedTitle = NSAttributedString(string: atribbutedTitle) syncControl.attributedTitle = NSAttributedString(string: atribbutedTitle)
} }
@ -438,9 +439,12 @@ class PasswordsViewController: UIViewController, UITableViewDataSource, UITableV
reloadTableView(data: passwordsTableEntries, anim: anim) reloadTableView(data: passwordsTableEntries, anim: anim)
} }
func reloadTableView() { func actOnReloadTableViewRelatedNotification() {
initPasswordsTableEntries(parent: nil) initPasswordsTableEntries(parent: nil)
reloadTableView(data: passwordsTableEntries) DispatchQueue.main.async { [weak weakSelf = self] in
guard let strongSelf = weakSelf else { return }
strongSelf.reloadTableView(data: strongSelf.passwordsTableEntries)
}
} }
func handleRefresh(_ syncControl: UIRefreshControl) { func handleRefresh(_ syncControl: UIRefreshControl) {

View file

@ -0,0 +1,21 @@
//
// RawPasswordViewController.swift
// pass
//
// Created by Mingshen Sun on 31/3/2017.
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
class RawPasswordViewController: UIViewController {
@IBOutlet weak var rawPasswordTextView: UITextView!
var password: Password?
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Raw"
rawPasswordTextView.text = password?.plainText
}
}

View file

@ -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)
} }
} }

View file

@ -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,12 +140,11 @@ class SettingsTableViewController: UITableViewController {
} }
}) })
DispatchQueue.main.async { DispatchQueue.main.async {
Defaults[.lastUpdatedTime] = Date() Defaults[.gitURL] = URL(string: gitRepostiroyURL)
Defaults[.gitRepositoryURL] = URL(string: gitRepostiroyURL) Defaults[.gitUsername] = username
Defaults[.gitRepositoryUsername] = username Defaults[.gitAuthenticationMethod] = auth
Defaults[.gitRepositoryAuthenticationMethod] = auth Defaults[.gitPasswordAttempts] = 0
Defaults[.gitRepositoryPasswordAttempts] = 0 self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitURL]?.host
self.passwordRepositoryTableViewCell.detailTextLabel?.text = Defaults[.gitRepositoryURL]?.host
SVProgressHUD.showSuccess(withStatus: "Done") SVProgressHUD.showSuccess(withStatus: "Done")
SVProgressHUD.dismiss(withDelay: 1) SVProgressHUD.dismiss(withDelay: 1)
} }
@ -163,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()
@ -190,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
} }
} }
@ -219,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
}) })

View file

@ -17,14 +17,19 @@ 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 lastUpdatedTime = DefaultsKey<Date?>("lasteUpdatedTime")
static let lastSyncedTime = DefaultsKey<Date?>("lastSyncedTime")
static let isTouchIDOn = DefaultsKey<Bool>("isTouchIDOn") static let isTouchIDOn = DefaultsKey<Bool>("isTouchIDOn")
static let passcodeKey = DefaultsKey<String?>("passcodeKey") static let passcodeKey = DefaultsKey<String?>("passcodeKey")

View file

@ -15,22 +15,25 @@ 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()
static let red = UIColor(red:1.00, green:0.23, blue:0.19, alpha:1.0) static let passwordDefaultLength = ["Random": (min: 6, max: 24, def: 16),
static let blue = UIColor(red:0.00, green:0.48, blue:1.00, alpha:1.0) "Apple": (min: 15, max: 15, def: 15)]
static let passwordMinimumLength = 6
static let passwordMaximumLength = 24
static let passwordDefaultLength = 16
static let passwordDots = "••••••••••••" static let passwordDots = "••••••••••••"
static let passwordFonts = "Menlo" static let passwordFonts = "Menlo"
// UI related
static let red = UIColor(red:1.00, green:0.23, blue:0.19, alpha:1.0)
static let blue = UIColor(red:0.00, green:0.48, blue:1.00, alpha:1.0)
static let tableCellButtonSize = CGFloat(20.0)
private init() { } private init() { }
} }

View file

@ -27,15 +27,14 @@ class Utils {
removeFileIfExists(atPath: url.path) removeFileIfExists(atPath: url.path)
} }
static func getLastUpdatedTimeString() -> String { static func getLastSyncedTimeString() -> String {
var lastUpdatedTimeString = "" guard let lastSyncedTime = Defaults[.lastSyncedTime] else {
if let lastUpdatedTime = Defaults[.lastUpdatedTime] { return "Oops! Sync again?"
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
lastUpdatedTimeString = formatter.string(from: lastUpdatedTime)
} }
return lastUpdatedTimeString let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
return formatter.string(from: lastSyncedTime)
} }
static func generatePassword(length: Int) -> String{ static func generatePassword(length: Int) -> String{
@ -84,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 {

View file

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

View file

@ -24,8 +24,8 @@ class Password {
var additions = [String: String]() var additions = [String: String]()
var additionKeys = [String]() var additionKeys = [String]()
var changed = false var changed = false
var plainText = ""
private var plainText = ""
private var firstLineIsOTPField = false private var firstLineIsOTPField = false
private var otpToken: Token? private var otpToken: Token?
@ -99,14 +99,17 @@ class Password {
// return a key-value pair from the line // return a key-value pair from the line
// key might be nil, if there is no ":" in the line // key might be nil, if there is no ":" in the line
static private func getKeyValuePair(from line: String) -> (key: String?, value: String) { static private func getKeyValuePair(from line: String) -> (key: String?, value: String) {
let items = line.characters.split(separator: ":", maxSplits: 1, omittingEmptySubsequences: true).map(String.init) let items = line.characters.split(separator: ":", maxSplits: 1, omittingEmptySubsequences: false).map{String($0).trimmingCharacters(in: .whitespaces)}
var key : String? var key : String? = nil
var value = "" var value = ""
if items.count == 1 { if items.count == 1 || (items[0].isEmpty && items[1].isEmpty) {
value = items[0] // no ":" found, or empty on both sides of ":" (e.g., " : ")
} else if items.count == 2 { value = line
key = items[0] } else {
value = items[1].trimmingCharacters(in: .whitespaces) if !items[0].isEmpty {
key = items[0]
}
value = items[1]
} }
return (key, value) return (key, value)
} }
@ -178,6 +181,8 @@ class Password {
*/ */
private func updateOtpToken() { private func updateOtpToken() {
self.otpToken = nil
// get otpauth, if we are able to generate a token, return // get otpauth, if we are able to generate a token, return
if var otpauthString = getAdditionValue(withKey: "otpauth") { if var otpauthString = getAdditionValue(withKey: "otpauth") {
if !otpauthString.hasPrefix("otpauth:") { if !otpauthString.hasPrefix("otpauth:") {

View file

@ -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() {
@ -302,9 +330,11 @@ class PasswordStore {
} }
storeRepository = try GTRepository(url: storeURL) storeRepository = try GTRepository(url: storeURL)
gitCredential = credential gitCredential = credential
self.updatePasswordEntityCoreData() Defaults[.lastSyncedTime] = Date()
DispatchQueue.main.async {
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) self.updatePasswordEntityCoreData()
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
}
} }
func pullRepository(transferProgressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void) throws { func pullRepository(transferProgressBlock: @escaping (UnsafePointer<git_transfer_progress>, UnsafeMutablePointer<ObjCBool>) -> Void) throws {
@ -317,9 +347,12 @@ class PasswordStore {
] ]
let remote = try GTRemote(name: "origin", in: storeRepository!) let remote = try GTRemote(name: "origin", in: storeRepository!)
try storeRepository?.pull((storeRepository?.currentBranch())!, from: remote, withOptions: options, progress: transferProgressBlock) try storeRepository?.pull((storeRepository?.currentBranch())!, from: remote, withOptions: options, progress: transferProgressBlock)
self.setAllSynced() Defaults[.lastSyncedTime] = Date()
self.updatePasswordEntityCoreData() DispatchQueue.main.async {
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) self.setAllSynced()
self.updatePasswordEntityCoreData()
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
}
} }
private func updatePasswordEntityCoreData() { private func updatePasswordEntityCoreData() {
@ -649,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()
@ -678,6 +711,8 @@ class PasswordStore {
try self.storeRepository?.reset(to: newHead, resetType: GTRepositoryResetType.hard) try self.storeRepository?.reset(to: newHead, resetType: GTRepositoryResetType.hard)
self.setAllSynced() self.setAllSynced()
self.updatePasswordEntityCoreData() self.updatePasswordEntityCoreData()
Defaults[.lastSyncedTime] = nil
NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil) NotificationCenter.default.post(name: .passwordStoreUpdated, object: nil)
NotificationCenter.default.post(name: .passwordStoreChangeDiscarded, object: nil) NotificationCenter.default.post(name: .passwordStoreChangeDiscarded, object: nil)
return localCommits.count return localCommits.count

View file

@ -10,6 +10,7 @@ import UIKit
protocol FillPasswordTableViewCellDelegate { protocol FillPasswordTableViewCellDelegate {
func generateAndCopyPassword() func generateAndCopyPassword()
func showHidePasswordSettings()
} }
class FillPasswordTableViewCell: ContentTableViewCell { class FillPasswordTableViewCell: ContentTableViewCell {
@ -17,10 +18,17 @@ class FillPasswordTableViewCell: ContentTableViewCell {
@IBOutlet weak var contentTextField: UITextField! @IBOutlet weak var contentTextField: UITextField!
var delegate: FillPasswordTableViewCellDelegate? var delegate: FillPasswordTableViewCellDelegate?
@IBOutlet weak var settingButton: UIButton!
@IBOutlet weak var generateButton: UIButton!
override func awakeFromNib() { override func awakeFromNib() {
super.awakeFromNib() super.awakeFromNib()
// Initialization code // Initialization code
contentTextField.font = UIFont(name: Globals.passwordFonts, size: (contentTextField.font?.pointSize)!) contentTextField.font = UIFont(name: Globals.passwordFonts, size: (contentTextField.font?.pointSize)!)
// Force aspect ratio of button images
settingButton.imageView?.contentMode = .scaleAspectFit
generateButton.imageView?.contentMode = .scaleAspectFit
} }
override func setSelected(_ selected: Bool, animated: Bool) { override func setSelected(_ selected: Bool, animated: Bool) {
@ -33,6 +41,10 @@ class FillPasswordTableViewCell: ContentTableViewCell {
self.delegate?.generateAndCopyPassword() self.delegate?.generateAndCopyPassword()
} }
@IBAction func showHidePasswordSettings() {
self.delegate?.showHidePasswordSettings()
}
// re-color // re-color
@IBAction func textFieldDidChange(_ sender: UITextField) { @IBAction func textFieldDidChange(_ sender: UITextField) {
contentTextField.attributedText = Utils.attributedPassword(plainPassword: sender.text ?? "") contentTextField.attributedText = Utils.attributedPassword(plainPassword: sender.text ?? "")

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12106.1" systemVersion="16F43c" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait"> <device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/> <adaptation id="fullscreen"/>
</device> </device>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12074.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/> <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
@ -16,13 +16,13 @@
<rect key="frame" x="0.0" y="0.0" width="320" height="90"/> <rect key="frame" x="0.0" y="0.0" width="320" height="90"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="320" height="89"/> <rect key="frame" x="0.0" y="0.0" width="320" height="89.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="password" textAlignment="natural" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="k0U-2N-YaX"> <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="password" textAlignment="natural" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="k0U-2N-YaX" userLabel="Password">
<rect key="frame" x="15" y="8" width="220" height="74"/> <rect key="frame" x="16" y="8" width="231" height="74"/>
<constraints> <constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="38" id="qVX-ui-dIn"/> <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="38" id="9gX-VT-F9P"/>
</constraints> </constraints>
<nil key="textColor"/> <nil key="textColor"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/> <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
@ -31,31 +31,52 @@
<action selector="textFieldDidChange:" destination="KGk-i7-Jjw" eventType="editingChanged" id="U0t-2B-JxY"/> <action selector="textFieldDidChange:" destination="KGk-i7-Jjw" eventType="editingChanged" id="U0t-2B-JxY"/>
</connections> </connections>
</textField> </textField>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" reversesTitleShadowWhenHighlighted="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hTh-ek-Xam"> <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SZJ-aY-45Y" userLabel="Setting">
<rect key="frame" x="243" y="-0.5" width="64" height="89.5"/> <rect key="frame" x="275" y="8" width="30" height="73.5"/>
<constraints> <constraints>
<constraint firstAttribute="width" constant="64" id="X1A-kc-qJy"/> <constraint firstAttribute="width" constant="30" id="D9D-FC-ANz"/>
</constraints> </constraints>
<state key="normal" title="Generate"/> <inset key="contentEdgeInsets" minX="5" minY="10" maxX="5" maxY="10"/>
<state key="normal" image="HorizontalSettings"/>
<connections>
<action selector="showHidePasswordSettings" destination="KGk-i7-Jjw" eventType="touchUpInside" id="3I8-S0-qlo"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hTh-ek-Xam" userLabel="Generate">
<rect key="frame" x="245" y="8" width="30" height="73.5"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="l0l-7B-Tws"/>
</constraints>
<inset key="contentEdgeInsets" minX="5" minY="10" maxX="5" maxY="10"/>
<state key="normal" image="Refresh"/>
<connections> <connections>
<action selector="generatePassword:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="M61-hs-PCP"/> <action selector="generatePassword:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="M61-hs-PCP"/>
</connections> </connections>
</button> </button>
</subviews> </subviews>
<constraints> <constraints>
<constraint firstAttribute="trailingMargin" secondItem="k0U-2N-YaX" secondAttribute="trailing" constant="77" id="3S1-gj-XVP" userLabel="trailingMargin = Content Text Field.trailing + 71"/> <constraint firstItem="SZJ-aY-45Y" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="5XP-xZ-YWY"/>
<constraint firstItem="hTh-ek-Xam" firstAttribute="centerY" secondItem="k0U-2N-YaX" secondAttribute="centerY" id="Fls-do-khd"/> <constraint firstAttribute="trailingMargin" secondItem="SZJ-aY-45Y" secondAttribute="trailing" constant="7" id="5bp-bm-9vv"/>
<constraint firstItem="hTh-ek-Xam" firstAttribute="height" secondItem="H2p-sc-9uM" secondAttribute="height" id="Gok-dX-tQ5"/> <constraint firstAttribute="bottomMargin" secondItem="SZJ-aY-45Y" secondAttribute="bottom" id="CMF-1f-MdG"/>
<constraint firstItem="hTh-ek-Xam" firstAttribute="leading" secondItem="k0U-2N-YaX" secondAttribute="trailing" constant="8" id="hsy-gb-ero" userLabel="Generate.leading = Content Text Field.trailing"/> <constraint firstItem="hTh-ek-Xam" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="OjQ-mD-CWV"/>
<constraint firstItem="k0U-2N-YaX" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="jKd-Xa-tr5"/> <constraint firstItem="SZJ-aY-45Y" firstAttribute="leading" secondItem="hTh-ek-Xam" secondAttribute="trailing" id="UlR-NB-9So"/>
<constraint firstItem="k0U-2N-YaX" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="7" id="lAm-D6-pir"/> <constraint firstAttribute="bottomMargin" secondItem="hTh-ek-Xam" secondAttribute="bottom" id="bvu-Q0-QAG"/>
<constraint firstAttribute="bottomMargin" secondItem="k0U-2N-YaX" secondAttribute="bottom" constant="-1" id="pLC-H7-JTU" userLabel="bottomMargin = Content Text Field.bottom"/> <constraint firstAttribute="trailingMargin" secondItem="k0U-2N-YaX" secondAttribute="trailing" constant="65" id="fz0-HW-sCe"/>
<constraint firstAttribute="bottomMargin" secondItem="k0U-2N-YaX" secondAttribute="bottom" id="lRv-MC-Cru"/>
<constraint firstItem="k0U-2N-YaX" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="sUk-sk-JLT"/>
<constraint firstItem="k0U-2N-YaX" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="8" id="zGn-an-SlK"/>
</constraints> </constraints>
</tableViewCellContentView> </tableViewCellContentView>
<connections> <connections>
<outlet property="contentTextField" destination="k0U-2N-YaX" id="kQO-tR-Epp"/> <outlet property="contentTextField" destination="k0U-2N-YaX" id="kQO-tR-Epp"/>
<outlet property="generateButton" destination="hTh-ek-Xam" id="MUa-qs-uw4"/>
<outlet property="settingButton" destination="SZJ-aY-45Y" id="G4T-04-NBD"/>
</connections> </connections>
<point key="canvasLocation" x="34" y="77"/> <point key="canvasLocation" x="34" y="77"/>
</tableViewCell> </tableViewCell>
</objects> </objects>
<resources>
<image name="HorizontalSettings" width="25" height="25"/>
<image name="Refresh" width="32" height="32"/>
</resources>
</document> </document>

View file

@ -27,6 +27,9 @@ class LabelTableViewCell: UITableViewCell {
weak var delegatePasswordTableView : PasswordDetailTableViewController? weak var delegatePasswordTableView : PasswordDetailTableViewController?
var passwordDisplayButton: UIButton?
var buttons: UIView?
var cellData: LabelTableViewCellData? { var cellData: LabelTableViewCellData? {
didSet { didSet {
titleLabel.text = cellData?.title ?? "" titleLabel.text = cellData?.title ?? ""
@ -43,9 +46,11 @@ class LabelTableViewCell: UITableViewCell {
} else { } else {
contentLabel.text = Globals.passwordDots contentLabel.text = Globals.passwordDots
} }
contentLabel.font = UIFont(name: Globals.passwordFonts, size: contentLabel.font.pointSize)
} else { } else {
contentLabel.text = cellData?.content contentLabel.text = cellData?.content
} }
updateButtons()
} }
} }
@ -58,6 +63,13 @@ class LabelTableViewCell: UITableViewCell {
override func awakeFromNib() { override func awakeFromNib() {
super.awakeFromNib() super.awakeFromNib()
} }
override func layoutSubviews() {
super.layoutSubviews()
if buttons != nil {
self.accessoryView = buttons
}
}
override func setSelected(_ selected: Bool, animated: Bool) { override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated) super.setSelected(selected, animated: animated)
@ -99,13 +111,26 @@ class LabelTableViewCell: UITableViewCell {
contentLabel.text = "" contentLabel.text = ""
} }
isReveal = true isReveal = true
passwordDisplayButton?.setImage(#imageLiteral(resourceName: "Invisible"), for: .normal)
} }
func concealPassword(_ sender: Any?) { func concealPassword(_ sender: Any?) {
contentLabel.text = Globals.passwordDots contentLabel.text = Globals.passwordDots
isReveal = false isReveal = false
passwordDisplayButton?.setImage(#imageLiteral(resourceName: "Visible"), for: .normal)
} }
func reversePasswordDisplay(_ sender: Any?) {
if isReveal {
// conceal
concealPassword(sender)
} else {
// reveal
revealPassword(sender)
}
}
func openLink(_ sender: Any?) { func openLink(_ sender: Any?) {
// if isURLCell, passwordTableView should not be nil // if isURLCell, passwordTableView should not be nil
delegatePasswordTableView!.openLink() delegatePasswordTableView!.openLink()
@ -115,4 +140,50 @@ class LabelTableViewCell: UITableViewCell {
// if isHOTPCell, passwordTableView should not be nil // if isHOTPCell, passwordTableView should not be nil
delegatePasswordTableView!.getNextHOTP() delegatePasswordTableView!.getNextHOTP()
} }
func updateButtons() {
passwordDisplayButton = nil
buttons = nil
// total width and height of a button
let height = min(self.bounds.height, 36.0)
let width = max(height * 0.8, Globals.tableCellButtonSize)
// margins (between button boundary and icon)
let marginY = max((height - Globals.tableCellButtonSize) / 2, 0.0)
let marginX = max((width - Globals.tableCellButtonSize) / 2, 0.0)
if isPasswordCell {
// password button
passwordDisplayButton = UIButton(type: .system)
passwordDisplayButton!.frame = CGRect(x: 0, y: 0, width: width, height: height)
passwordDisplayButton!.setImage(#imageLiteral(resourceName: "Visible"), for: .normal)
passwordDisplayButton!.imageView?.contentMode = .scaleAspectFit
passwordDisplayButton!.contentEdgeInsets = UIEdgeInsetsMake(marginY, marginX, marginY, marginX)
passwordDisplayButton!.addTarget(self, action: #selector(reversePasswordDisplay), for: UIControlEvents.touchUpInside)
buttons = passwordDisplayButton
} else if isHOTPCell {
// hotp button
let nextButton = UIButton(type: .system)
nextButton.frame = CGRect(x: 0, y: 0, width: width, height: height)
nextButton.setImage(#imageLiteral(resourceName: "Refresh"), for: .normal)
nextButton.imageView?.contentMode = .scaleAspectFit
nextButton.contentEdgeInsets = UIEdgeInsetsMake(marginY, marginX, marginY, marginX)
nextButton.addTarget(self, action: #selector(getNextHOTP), for: UIControlEvents.touchUpInside)
// password button
passwordDisplayButton = UIButton(type: .system)
passwordDisplayButton!.frame = CGRect(x: width, y: 0, width: width, height: height)
passwordDisplayButton!.setImage(#imageLiteral(resourceName: "Visible"), for: .normal)
passwordDisplayButton!.imageView?.contentMode = .scaleAspectFit
passwordDisplayButton!.contentEdgeInsets = UIEdgeInsetsMake(marginY, marginX, marginY, marginX)
passwordDisplayButton!.addTarget(self, action: #selector(reversePasswordDisplay), for: UIControlEvents.touchUpInside)
buttons = UIView()
buttons!.frame = CGRect(x: 0, y: 0, width: width * 2, height: height)
buttons!.addSubview(nextButton)
buttons!.addSubview(passwordDisplayButton!)
}
}
} }

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12106.1" systemVersion="16F43c" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait"> <device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/> <adaptation id="fullscreen"/>
</device> </device>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12074.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/> <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
@ -16,17 +16,20 @@
<rect key="frame" x="0.0" y="0.0" width="333" height="52"/> <rect key="frame" x="0.0" y="0.0" width="333" height="52"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="333" height="51"/> <rect key="frame" x="0.0" y="0.0" width="333" height="51.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yyr-cF-QN0"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="content" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yyr-cF-QN0">
<rect key="frame" x="15" y="26" width="310" height="17.5"/> <rect key="frame" x="16" y="22.5" width="309" height="21"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="21" id="pgw-DF-LQa"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/> <fontDescription key="fontDescription" type="system" pointSize="16"/>
<nil key="textColor"/> <nil key="textColor"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dqz-7n-uEZ"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Dqz-7n-uEZ">
<rect key="frame" x="15" y="8" width="310" height="15"/> <rect key="frame" x="16" y="8" width="309" height="11.5"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/> <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
<color key="textColor" red="0.0" green="0.47843137254901957" blue="1" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.47843137254901957" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
@ -34,7 +37,7 @@
</subviews> </subviews>
<constraints> <constraints>
<constraint firstAttribute="trailingMargin" secondItem="Dqz-7n-uEZ" secondAttribute="trailing" id="228-VM-Z8Y"/> <constraint firstAttribute="trailingMargin" secondItem="Dqz-7n-uEZ" secondAttribute="trailing" id="228-VM-Z8Y"/>
<constraint firstItem="Dqz-7n-uEZ" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="7" id="CVm-uc-iVo"/> <constraint firstItem="Dqz-7n-uEZ" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="8" id="CVm-uc-iVo"/>
<constraint firstAttribute="topMargin" secondItem="Dqz-7n-uEZ" secondAttribute="top" id="N4y-iT-CiY"/> <constraint firstAttribute="topMargin" secondItem="Dqz-7n-uEZ" secondAttribute="top" id="N4y-iT-CiY"/>
<constraint firstItem="yyr-cF-QN0" firstAttribute="leading" secondItem="Dqz-7n-uEZ" secondAttribute="leading" id="TpW-bu-QIx"/> <constraint firstItem="yyr-cF-QN0" firstAttribute="leading" secondItem="Dqz-7n-uEZ" secondAttribute="leading" id="TpW-bu-QIx"/>
<constraint firstItem="yyr-cF-QN0" firstAttribute="width" secondItem="Dqz-7n-uEZ" secondAttribute="width" id="ZXa-fK-0Bg"/> <constraint firstItem="yyr-cF-QN0" firstAttribute="width" secondItem="Dqz-7n-uEZ" secondAttribute="width" id="ZXa-fK-0Bg"/>

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12106.1" systemVersion="16F43c" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait"> <device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/> <adaptation id="fullscreen"/>
</device> </device>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12074.1"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/> <capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/> <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@ -17,7 +17,7 @@
<rect key="frame" x="0.0" y="0.0" width="320" height="84"/> <rect key="frame" x="0.0" y="0.0" width="320" height="84"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="320" height="83"/> <rect key="frame" x="0.0" y="0.0" width="320" height="83.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="250" placeholderIntrinsicWidth="52" placeholderIntrinsicHeight="52" translatesAutoresizingMaskIntoConstraints="NO" id="gKV-Cd-wIk"> <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="250" placeholderIntrinsicWidth="52" placeholderIntrinsicHeight="52" translatesAutoresizingMaskIntoConstraints="NO" id="gKV-Cd-wIk">

View file

@ -1,27 +0,0 @@
//
// PasswordTableViewCell.swift
// pass
//
// Created by Mingshen Sun on 8/3/2017.
// Copyright © 2017 Bob Sun. All rights reserved.
//
import UIKit
class PasswordWithFolderTableViewCell: UITableViewCell {
@IBOutlet weak var passwordLabel: UILabel!
@IBOutlet weak var folderLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}

View file

@ -1,52 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12106.1" systemVersion="16E183b" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12074.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="passwordWithFolderTableViewCell" rowHeight="43" id="KGk-i7-Jjw" customClass="PasswordWithFolderTableViewCell" customModule="pass" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="320" height="43"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="320" height="42.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Password Entry" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="y5A-3S-tcq">
<rect key="frame" x="15" y="8" width="297" height="26.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Family &gt; Parents" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GEv-Cf-Cnx">
<rect key="frame" x="8" y="12.5" width="297" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" red="0.5568627451" green="0.5568627451" blue="0.57647058819999997" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="y5A-3S-tcq" firstAttribute="centerY" secondItem="GEv-Cf-Cnx" secondAttribute="centerY" id="Ev0-0v-v1c"/>
<constraint firstAttribute="trailingMargin" secondItem="GEv-Cf-Cnx" secondAttribute="trailing" constant="7" id="Hyk-Q8-5uU"/>
<constraint firstItem="y5A-3S-tcq" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="7" id="VDn-B1-Tyg"/>
<constraint firstItem="y5A-3S-tcq" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="e9F-C0-yGP"/>
<constraint firstAttribute="bottomMargin" secondItem="y5A-3S-tcq" secondAttribute="bottom" id="f52-hU-sEC"/>
<constraint firstAttribute="leadingMargin" secondItem="GEv-Cf-Cnx" secondAttribute="leading" id="rjm-bp-jT3"/>
<constraint firstAttribute="trailingMargin" secondItem="y5A-3S-tcq" secondAttribute="trailing" id="vsW-4d-EEl"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="folderLabel" destination="GEv-Cf-Cnx" id="HHd-LU-wYW"/>
<outlet property="passwordLabel" destination="y5A-3S-tcq" id="1OK-Io-6mP"/>
</connections>
<point key="canvasLocation" x="34" y="53.5"/>
</tableViewCell>
</objects>
</document>

View file

@ -58,6 +58,13 @@ class SliderTableViewCell: ContentTableViewCell {
slider.maximumValue = Float(maximumValue) slider.maximumValue = Float(maximumValue)
slider.value = Float(defaultValue) slider.value = Float(defaultValue)
valueLabel.text = String(defaultValue) valueLabel.text = String(defaultValue)
// "not editable"
if minimumValue == maximumValue {
titleLabel.textColor = UIColor.gray
valueLabel.textColor = UIColor.gray
slider.isUserInteractionEnabled = false
}
} }
} }

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12106.1" systemVersion="16F43c" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait"> <device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/> <adaptation id="fullscreen"/>
</device> </device>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12074.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/> <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
@ -20,7 +20,7 @@
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="MwT-Jl-hhE"> <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" translatesAutoresizingMaskIntoConstraints="NO" id="MwT-Jl-hhE">
<rect key="frame" x="60.5" y="22" width="205.5" height="31"/> <rect key="frame" x="61.5" y="22" width="204.5" height="31"/>
<connections> <connections>
<action selector="handleSliderValueChange:" destination="KGk-i7-Jjw" eventType="valueChanged" id="WwM-ZE-yIB"/> <action selector="handleSliderValueChange:" destination="KGk-i7-Jjw" eventType="valueChanged" id="WwM-ZE-yIB"/>
</connections> </connections>
@ -34,8 +34,8 @@
<nil key="textColor"/> <nil key="textColor"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="t7T-HC-hUd" userLabel="Title"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="t7T-HC-hUd" userLabel="Title">
<rect key="frame" x="15" y="8" width="30" height="57.5"/> <rect key="frame" x="16" y="8" width="30" height="57.5"/>
<constraints> <constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="38" id="8Tz-Qo-Mkg"/> <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="38" id="8Tz-Qo-Mkg"/>
</constraints> </constraints>
@ -46,7 +46,7 @@
</subviews> </subviews>
<constraints> <constraints>
<constraint firstItem="MwT-Jl-hhE" firstAttribute="leading" secondItem="t7T-HC-hUd" secondAttribute="trailing" constant="17" id="Cc9-kV-nZf"/> <constraint firstItem="MwT-Jl-hhE" firstAttribute="leading" secondItem="t7T-HC-hUd" secondAttribute="trailing" constant="17" id="Cc9-kV-nZf"/>
<constraint firstItem="t7T-HC-hUd" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="7" id="Kje-Zj-RaX"/> <constraint firstItem="t7T-HC-hUd" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="8" id="Kje-Zj-RaX"/>
<constraint firstAttribute="trailingMargin" secondItem="GJP-Fj-VZt" secondAttribute="trailing" constant="7" id="LjD-JH-dRT"/> <constraint firstAttribute="trailingMargin" secondItem="GJP-Fj-VZt" secondAttribute="trailing" constant="7" id="LjD-JH-dRT"/>
<constraint firstItem="MwT-Jl-hhE" firstAttribute="centerY" secondItem="t7T-HC-hUd" secondAttribute="centerY" id="MHN-Vl-1le"/> <constraint firstItem="MwT-Jl-hhE" firstAttribute="centerY" secondItem="t7T-HC-hUd" secondAttribute="centerY" id="MHN-Vl-1le"/>
<constraint firstAttribute="bottomMargin" secondItem="GJP-Fj-VZt" secondAttribute="bottom" id="NmC-sS-9Yt"/> <constraint firstAttribute="bottomMargin" secondItem="GJP-Fj-VZt" secondAttribute="bottom" id="NmC-sS-9Yt"/>

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12106.1" systemVersion="16F43c" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait"> <device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/> <adaptation id="fullscreen"/>
</device> </device>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12074.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/> <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
@ -16,11 +16,11 @@
<rect key="frame" x="0.0" y="0.0" width="320" height="56"/> <rect key="frame" x="0.0" y="0.0" width="320" height="56"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="320" height="55"/> <rect key="frame" x="0.0" y="0.0" width="320" height="55.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="8Ky-UZ-sLu"> <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="8Ky-UZ-sLu">
<rect key="frame" x="15" y="8" width="297" height="39.5"/> <rect key="frame" x="16" y="8" width="296" height="39.5"/>
<constraints> <constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="38" id="R1z-fU-Xr2"/> <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="38" id="R1z-fU-Xr2"/>
</constraints> </constraints>
@ -30,7 +30,7 @@
</textField> </textField>
</subviews> </subviews>
<constraints> <constraints>
<constraint firstItem="8Ky-UZ-sLu" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="7" id="3h4-9E-oDJ"/> <constraint firstItem="8Ky-UZ-sLu" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="8" id="3h4-9E-oDJ"/>
<constraint firstItem="8Ky-UZ-sLu" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="FH4-4T-aaK"/> <constraint firstItem="8Ky-UZ-sLu" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="FH4-4T-aaK"/>
<constraint firstAttribute="trailingMargin" secondItem="8Ky-UZ-sLu" secondAttribute="trailing" id="Nii-Cg-gC1"/> <constraint firstAttribute="trailingMargin" secondItem="8Ky-UZ-sLu" secondAttribute="trailing" id="Nii-Cg-gC1"/>
<constraint firstAttribute="bottomMargin" secondItem="8Ky-UZ-sLu" secondAttribute="bottom" id="h72-l3-Sb3"/> <constraint firstAttribute="bottomMargin" secondItem="8Ky-UZ-sLu" secondAttribute="bottom" id="h72-l3-Sb3"/>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12106.1" systemVersion="16E189a" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12106.1" systemVersion="16F43c" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait"> <device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/> <adaptation id="fullscreen"/>
</device> </device>
@ -20,7 +20,7 @@
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xHX-Sh-1pR"> <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xHX-Sh-1pR">
<rect key="frame" x="15" y="15" width="297" height="186.5"/> <rect key="frame" x="12" y="16" width="300" height="184.5"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints> <constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="120" id="Tvq-j8-Nvh"/> <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="120" id="Tvq-j8-Nvh"/>
@ -31,9 +31,9 @@
</subviews> </subviews>
<constraints> <constraints>
<constraint firstAttribute="trailingMargin" secondItem="xHX-Sh-1pR" secondAttribute="trailing" id="LWS-JW-9dS"/> <constraint firstAttribute="trailingMargin" secondItem="xHX-Sh-1pR" secondAttribute="trailing" id="LWS-JW-9dS"/>
<constraint firstItem="xHX-Sh-1pR" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="7" id="SRq-7t-Gyr"/> <constraint firstItem="xHX-Sh-1pR" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="4" id="SRq-7t-Gyr"/>
<constraint firstAttribute="bottomMargin" secondItem="xHX-Sh-1pR" secondAttribute="bottom" constant="7" id="UPQ-jk-QJR"/> <constraint firstAttribute="bottomMargin" secondItem="xHX-Sh-1pR" secondAttribute="bottom" constant="8" id="UPQ-jk-QJR"/>
<constraint firstItem="xHX-Sh-1pR" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" constant="7" id="gwb-2C-4wp"/> <constraint firstItem="xHX-Sh-1pR" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" constant="8" id="gwb-2C-4wp"/>
</constraints> </constraints>
</tableViewCellContentView> </tableViewCellContentView>
<connections> <connections>

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12106.1" systemVersion="16F43c" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait"> <device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/> <adaptation id="fullscreen"/>
</device> </device>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12074.1"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/> <capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
@ -16,17 +16,20 @@
<rect key="frame" x="0.0" y="0.0" width="320" height="56"/> <rect key="frame" x="0.0" y="0.0" width="320" height="56"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="320" height="55"/> <rect key="frame" x="0.0" y="0.0" width="320" height="55.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HPC-rQ-39b"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" verticalCompressionResistancePriority="751" text="title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="HPC-rQ-39b">
<rect key="frame" x="15" y="8" width="297" height="15"/> <rect key="frame" x="16" y="8" width="296" height="15"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/> <fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
<color key="textColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="calibratedRGB"/> <color key="textColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="8Ky-UZ-sLu"> <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="123" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="8Ky-UZ-sLu">
<rect key="frame" x="15" y="26" width="297" height="21"/> <rect key="frame" x="16" y="26" width="296" height="21"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="21" id="dHY-dw-mFe"/>
</constraints>
<nil key="textColor"/> <nil key="textColor"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/> <fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" returnKeyType="next"/> <textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no" returnKeyType="next"/>
@ -36,17 +39,17 @@
<constraint firstAttribute="bottomMargin" secondItem="8Ky-UZ-sLu" secondAttribute="bottom" id="11n-KG-zy6"/> <constraint firstAttribute="bottomMargin" secondItem="8Ky-UZ-sLu" secondAttribute="bottom" id="11n-KG-zy6"/>
<constraint firstItem="8Ky-UZ-sLu" firstAttribute="trailing" secondItem="HPC-rQ-39b" secondAttribute="trailing" id="42z-vE-AsJ"/> <constraint firstItem="8Ky-UZ-sLu" firstAttribute="trailing" secondItem="HPC-rQ-39b" secondAttribute="trailing" id="42z-vE-AsJ"/>
<constraint firstItem="8Ky-UZ-sLu" firstAttribute="leading" secondItem="HPC-rQ-39b" secondAttribute="leading" id="8F6-w6-BDY"/> <constraint firstItem="8Ky-UZ-sLu" firstAttribute="leading" secondItem="HPC-rQ-39b" secondAttribute="leading" id="8F6-w6-BDY"/>
<constraint firstItem="HPC-rQ-39b" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="8" id="8ps-9g-9zG"/>
<constraint firstAttribute="trailingMargin" secondItem="HPC-rQ-39b" secondAttribute="trailing" id="Ayv-Bg-JxT"/> <constraint firstAttribute="trailingMargin" secondItem="HPC-rQ-39b" secondAttribute="trailing" id="Ayv-Bg-JxT"/>
<constraint firstItem="HPC-rQ-39b" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="JN2-lI-0ZY"/> <constraint firstItem="HPC-rQ-39b" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="topMargin" id="JN2-lI-0ZY"/>
<constraint firstItem="8Ky-UZ-sLu" firstAttribute="top" secondItem="HPC-rQ-39b" secondAttribute="bottom" constant="3" id="Pqs-gm-93j"/> <constraint firstItem="8Ky-UZ-sLu" firstAttribute="top" secondItem="HPC-rQ-39b" secondAttribute="bottom" constant="3" id="Pqs-gm-93j"/>
<constraint firstItem="HPC-rQ-39b" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leadingMargin" constant="7" id="vfA-M9-FEp"/>
</constraints> </constraints>
</tableViewCellContentView> </tableViewCellContentView>
<connections> <connections>
<outlet property="contentTextField" destination="8Ky-UZ-sLu" id="unz-5T-fuK"/> <outlet property="contentTextField" destination="8Ky-UZ-sLu" id="unz-5T-fuK"/>
<outlet property="titleLabel" destination="HPC-rQ-39b" id="VoV-gT-5lh"/> <outlet property="titleLabel" destination="HPC-rQ-39b" id="VoV-gT-5lh"/>
</connections> </connections>
<point key="canvasLocation" x="34" y="60"/> <point key="canvasLocation" x="0.0" y="61"/>
</tableViewCell> </tableViewCell>
</objects> </objects>
</document> </document>

22
passTests/Info.plist Normal file
View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>2</string>
</dict>
</plist>

35
passTests/passTests.swift Normal file
View file

@ -0,0 +1,35 @@
//
// passTests.swift
// passTests
//
// Created by Mingshen Sun on 24/3/2017.
// Copyright © 2017 Bob Sun. All rights reserved.
//
import XCTest
class passTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
}