From 13804b79e6dd78a91e5b460c1910aa8a882e984a Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Fri, 7 Jan 2022 10:04:40 -0800
Subject: [PATCH 001/103] Version bump to 0.13.0
---
pass.xcodeproj/project.pbxproj | 30 +++++++++++++++---------------
passAutoFillExtension/Info.plist | 4 ++--
2 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj
index 15bacc56..09fe3ed1 100644
--- a/pass.xcodeproj/project.pbxproj
+++ b/pass.xcodeproj/project.pbxproj
@@ -1798,7 +1798,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.12.0;
+ MARKETING_VERSION = 0.13.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios.shortcuts;
@@ -1833,7 +1833,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.12.0;
+ MARKETING_VERSION = 0.13.0;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforios.shortcuts;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -1930,7 +1930,7 @@
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
- MARKETING_VERSION = 0.12.0;
+ MARKETING_VERSION = 0.13.0;
OTHER_CFLAGS = "$(inherited)";
OTHER_LDFLAGS = "${inherited}";
OTHER_SWIFT_FLAGS = "$(inherited)";
@@ -1991,7 +1991,7 @@
"@executable_path/../../Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
- MARKETING_VERSION = 0.12.0;
+ MARKETING_VERSION = 0.13.0;
OTHER_CFLAGS = "$(inherited)";
OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).find-login-action-extension";
@@ -2026,7 +2026,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = "$(inherited)";
- MARKETING_VERSION = 0.12.0;
+ MARKETING_VERSION = 0.13.0;
MODULEMAP_FILE = "";
OTHER_CFLAGS = "$(inherited)";
OTHER_LDFLAGS = "$(inherited)";
@@ -2091,7 +2091,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.12.0;
+ MARKETING_VERSION = 0.13.0;
MTL_FAST_MATH = YES;
OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = "me.mssun.passforiosbeta.auto-fill-credential-extension";
@@ -2127,7 +2127,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.12.0;
+ MARKETING_VERSION = 0.13.0;
MTL_FAST_MATH = YES;
OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = me.mssun.passforiosbeta.shortcuts;
@@ -2162,7 +2162,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.12.0;
+ MARKETING_VERSION = 0.13.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "me.mssun.passforios.auto-fill-credential-extension";
@@ -2198,7 +2198,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.12.0;
+ MARKETING_VERSION = 0.13.0;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "me.mssun.passforios.auto-fill-credential-extension";
PRODUCT_NAME = passAutoFillExtension;
@@ -2231,7 +2231,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = "$(inherited)";
- MARKETING_VERSION = 0.12.0;
+ MARKETING_VERSION = 0.13.0;
MODULEMAP_FILE = "";
OTHER_CFLAGS = "$(inherited)";
OTHER_LDFLAGS = "$(inherited)";
@@ -2271,7 +2271,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = "$(inherited)";
- MARKETING_VERSION = 0.12.0;
+ MARKETING_VERSION = 0.13.0;
MODULEMAP_FILE = "";
OTHER_CFLAGS = "$(inherited)";
OTHER_LDFLAGS = "$(inherited)";
@@ -2355,7 +2355,7 @@
"@executable_path/../../Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
- MARKETING_VERSION = 0.12.0;
+ MARKETING_VERSION = 0.13.0;
OTHER_CFLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).find-login-action-extension";
PRODUCT_NAME = passExtension;
@@ -2390,7 +2390,7 @@
"@executable_path/../../Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
- MARKETING_VERSION = 0.12.0;
+ MARKETING_VERSION = 0.13.0;
OTHER_CFLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER).find-login-action-extension";
PRODUCT_NAME = passExtension;
@@ -2605,7 +2605,7 @@
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
- MARKETING_VERSION = 0.12.0;
+ MARKETING_VERSION = 0.13.0;
OTHER_CFLAGS = "$(inherited)";
OTHER_LDFLAGS = "${inherited}";
PRODUCT_BUNDLE_IDENTIFIER = "$(PRODUCT_BUNDLE_IDENTIFIER)";
@@ -2639,7 +2639,7 @@
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
- MARKETING_VERSION = 0.12.0;
+ MARKETING_VERSION = 0.13.0;
OTHER_CFLAGS = "$(inherited)";
OTHER_LDFLAGS = "${inherited}";
OTHER_SWIFT_FLAGS = "";
diff --git a/passAutoFillExtension/Info.plist b/passAutoFillExtension/Info.plist
index 7f13ea9c..d5967914 100644
--- a/passAutoFillExtension/Info.plist
+++ b/passAutoFillExtension/Info.plist
@@ -20,8 +20,6 @@
$(MARKETING_VERSION)
CFBundleVersion
0
- NSFaceIDUsageDescription
- Enable access to Face ID to unlock Pass.
NSExtension
NSExtensionMainStoryboard
@@ -29,5 +27,7 @@
NSExtensionPointIdentifier
com.apple.authentication-services-credential-provider-ui
+ NSFaceIDUsageDescription
+ Enable access to Face ID to unlock Pass.
From 955e50c3d3611f65915060b9da412d242d07576a Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Sun, 9 Jan 2022 21:38:39 -0800
Subject: [PATCH 002/103] Initial implementation of using YubiKey for
decryption (#533)
---
Gemfile.lock | 66 +-------
pass.xcodeproj/project.pbxproj | 81 ++++++++-
.../xcshareddata/swiftpm/Package.resolved | 9 +
pass/AppDelegate.swift | 3 +
...PGPKeyArmorImportTableViewController.swift | 2 +-
.../PGPKeyFIleImportTableViewController.swift | 21 +--
.../PGPKeyURLImportTableViewController.swift | 49 +++---
.../PasswordDetailTableViewController.swift | 81 ++++++++-
.../PasswordNavigationViewController.swift | 2 +-
.../SettingsTableViewController.swift | 11 ++
pass/Helpers/Objective-CBridgingHeader.h | 1 +
pass/Info.plist | 15 ++
pass/Services/PasswordDecryptor.swift | 160 +++++++++++++++++-
pass/pass.entitlements | 5 +
pass/passBeta.entitlements | 5 +
.../UIAlertControllerExtension.swift | 6 +
passKit/Helpers/AppError.swift | 24 ++-
passKit/Helpers/DefaultsKeys.swift | 1 +
passKit/Helpers/YubiKeyAPDU.swift | 54 ++++++
passKit/Helpers/YubiKeyConnection.swift | 63 +++++++
passKit/Models/PasswordEntity.swift | 2 +-
passKit/Protocols/AlertPresenting.swift | 55 ++++++
scripts/gopenpgp_build.sh | 8 +-
23 files changed, 606 insertions(+), 118 deletions(-)
create mode 100644 passKit/Helpers/YubiKeyAPDU.swift
create mode 100644 passKit/Helpers/YubiKeyConnection.swift
create mode 100644 passKit/Protocols/AlertPresenting.swift
diff --git a/Gemfile.lock b/Gemfile.lock
index 247f8a0d..26cba895 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -2,16 +2,8 @@ GEM
remote: https://rubygems.org/
specs:
CFPropertyList (3.0.2)
- activesupport (4.2.11.3)
- i18n (~> 0.7)
- minitest (~> 5.1)
- thread_safe (~> 0.3, >= 0.3.4)
- tzinfo (~> 1.1)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
- algoliasearch (1.27.5)
- httpclient (~> 2.8, >= 2.8.3)
- json (>= 1.5.1)
atomos (0.1.3)
aws-eventstream (1.1.0)
aws-partitions (1.345.0)
@@ -31,48 +23,10 @@ GEM
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.3)
claide (1.0.3)
- cocoapods (1.9.3)
- activesupport (>= 4.0.2, < 5)
- claide (>= 1.0.2, < 2.0)
- cocoapods-core (= 1.9.3)
- cocoapods-deintegrate (>= 1.0.3, < 2.0)
- cocoapods-downloader (>= 1.2.2, < 2.0)
- cocoapods-plugins (>= 1.0.0, < 2.0)
- cocoapods-search (>= 1.0.0, < 2.0)
- cocoapods-stats (>= 1.0.0, < 2.0)
- cocoapods-trunk (>= 1.4.0, < 2.0)
- cocoapods-try (>= 1.1.0, < 2.0)
- colored2 (~> 3.1)
- escape (~> 0.0.4)
- fourflusher (>= 2.3.0, < 3.0)
- gh_inspector (~> 1.0)
- molinillo (~> 0.6.6)
- nap (~> 1.0)
- ruby-macho (~> 1.4)
- xcodeproj (>= 1.14.0, < 2.0)
- cocoapods-core (1.9.3)
- activesupport (>= 4.0.2, < 6)
- algoliasearch (~> 1.0)
- concurrent-ruby (~> 1.1)
- fuzzy_match (~> 2.0.4)
- nap (~> 1.0)
- netrc (~> 0.11)
- typhoeus (~> 1.0)
- cocoapods-deintegrate (1.0.4)
- cocoapods-downloader (1.4.0)
- cocoapods-plugins (1.0.0)
- nap
- cocoapods-search (1.0.0)
- cocoapods-stats (1.1.0)
- cocoapods-trunk (1.5.0)
- nap (>= 0.8, < 2.0)
- netrc (~> 0.11)
- cocoapods-try (1.2.0)
colored (1.2)
colored2 (3.1.2)
commander-fastlane (4.4.6)
highline (~> 1.7.2)
- concurrent-ruby (1.1.7)
declarative (0.0.20)
declarative-option (0.1.0)
digest-crc (0.6.1)
@@ -81,9 +35,6 @@ GEM
unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.6)
emoji_regex (3.0.0)
- escape (0.0.4)
- ethon (0.12.0)
- ffi (>= 1.3.0)
excon (0.75.0)
faraday (1.0.1)
multipart-post (>= 1.2, < 3)
@@ -129,9 +80,6 @@ GEM
xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
- ffi (1.13.1)
- fourflusher (2.3.1)
- fuzzy_match (2.0.4)
gh_inspector (1.1.3)
google-api-client (0.38.0)
addressable (~> 2.5, >= 2.5.1)
@@ -166,8 +114,6 @@ GEM
http-cookie (1.0.3)
domain_name (~> 0.5)
httpclient (2.8.3)
- i18n (0.9.5)
- concurrent-ruby (~> 1.0)
jmespath (1.4.0)
json (2.3.1)
jwt (2.2.1)
@@ -177,12 +123,9 @@ GEM
mime-types-data (3.2020.0512)
mini_magick (4.10.1)
mini_mime (1.0.2)
- minitest (5.14.2)
- molinillo (0.6.6)
multi_json (1.15.0)
multipart-post (2.0.0)
nanaimo (0.3.0)
- nap (1.1.0)
naturally (2.2.0)
netrc (0.11.0)
os (1.1.0)
@@ -200,7 +143,6 @@ GEM
netrc (~> 0.8)
retriable (3.1.2)
rouge (2.0.7)
- ruby-macho (1.4.0)
rubyzip (2.3.0)
security (0.1.3)
signet (0.14.0)
@@ -215,15 +157,10 @@ GEM
terminal-notifier (2.0.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
- thread_safe (0.3.6)
tty-cursor (0.7.1)
tty-screen (0.8.1)
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
- typhoeus (1.4.0)
- ethon (>= 0.9.0)
- tzinfo (1.2.8)
- thread_safe (~> 0.1)
uber (0.1.0)
unf (0.1.4)
unf_ext
@@ -245,10 +182,9 @@ PLATFORMS
ruby
DEPENDENCIES
- cocoapods
fastlane
rest-client
xcodeproj
BUNDLED WITH
- 2.1.4
+ 2.2.25
diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj
index 09fe3ed1..0139052e 100644
--- a/pass.xcodeproj/project.pbxproj
+++ b/pass.xcodeproj/project.pbxproj
@@ -112,6 +112,10 @@
9A1D1CE526E5D1CE0052028E /* OneTimePassword in Frameworks */ = {isa = PBXBuildFile; productRef = 9A1D1CE426E5D1CE0052028E /* OneTimePassword */; };
9A1D1CE726E5D2230052028E /* OneTimePassword in Frameworks */ = {isa = PBXBuildFile; productRef = 9A1D1CE626E5D2230052028E /* OneTimePassword */; };
9A1F47FA26E5CF4B000C0E01 /* OneTimePassword in Frameworks */ = {isa = PBXBuildFile; productRef = 9A1F47F926E5CF4B000C0E01 /* OneTimePassword */; };
+ 9A2C7D822782CB2F00BD9AF3 /* YubiKit in Frameworks */ = {isa = PBXBuildFile; productRef = 9A2C7D812782CB2F00BD9AF3 /* YubiKit */; };
+ 9A2C7D842783FF5200BD9AF3 /* YubiKeyConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2C7D832783FF5200BD9AF3 /* YubiKeyConnection.swift */; };
+ 9A2C7D862783FF9600BD9AF3 /* YubiKit in Frameworks */ = {isa = PBXBuildFile; productRef = 9A2C7D852783FF9600BD9AF3 /* YubiKit */; };
+ 9A2C7D8B2784139200BD9AF3 /* YubiKeyAPDU.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A2C7D8A2784139200BD9AF3 /* YubiKeyAPDU.swift */; };
9A55C158259E785600FA8FD9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DC917BDD1E2E8231000FDF54 /* Assets.xcassets */; };
9A55C15F259E785700FA8FD9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DC917BDD1E2E8231000FDF54 /* Assets.xcassets */; };
9A55C185259E8C5600FA8FD9 /* PasswordsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A55C184259E8C5600FA8FD9 /* PasswordsViewController.swift */; };
@@ -122,13 +126,20 @@
9A58662925AAAA79006719C2 /* PasswordSelectionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9ECB259ECB410027CE15 /* PasswordSelectionDelegate.swift */; };
9A58664825AAAB7E006719C2 /* SearchPassword.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9A5865EF25AA944B006719C2 /* SearchPassword.storyboard */; };
9A58665125AADB76006719C2 /* CredentialProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A58665025AADB76006719C2 /* CredentialProvider.swift */; };
+ 9A5C6EF42786CA5F0003F340 /* AlertPresenting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A5C6EEF2786C8710003F340 /* AlertPresenting.swift */; };
+ 9A5C6EF92786CE170003F340 /* YubiKit in Frameworks */ = {isa = PBXBuildFile; productRef = 9A5C6EF82786CE170003F340 /* YubiKit */; };
+ 9A5C6EFB2786CE5E0003F340 /* YubiKit in Frameworks */ = {isa = PBXBuildFile; productRef = 9A5C6EFA2786CE5E0003F340 /* YubiKit */; };
+ 9A5C6EFF2787F0980003F340 /* Gopenpgp.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9ADAB21C26DDA52400900F10 /* Gopenpgp.xcframework */; };
+ 9A5C6F022787F09A0003F340 /* passKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A26075781EEC6F34005DB03E /* passKit.framework */; };
+ 9A5C6F042787F09D0003F340 /* Gopenpgp.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9ADAB21C26DDA52400900F10 /* Gopenpgp.xcframework */; };
+ 9A5C6F082787F0C20003F340 /* SwiftyUserDefaults in Frameworks */ = {isa = PBXBuildFile; productRef = 9A5C6F072787F0C20003F340 /* SwiftyUserDefaults */; };
9A5D06EE25A56F0800FA59D4 /* PasswordTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9EE1259EDD520027CE15 /* PasswordTableViewCell.swift */; };
9A5D06F525A56F0E00FA59D4 /* PasswordTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9EE1259EDD520027CE15 /* PasswordTableViewCell.swift */; };
9A5D070225A5769A00FA59D4 /* PasswordTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9EE1259EDD520027CE15 /* PasswordTableViewCell.swift */; };
9A652414244BB33300DA0A41 /* UIAlertActionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A652413244BB33300DA0A41 /* UIAlertActionExtension.swift */; };
9A74D2E0277D2F8C00F7BC44 /* UIAlertControllerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A74D2DF277D2F8C00F7BC44 /* UIAlertControllerExtension.swift */; };
9A78A7CC277BECE80093222D /* SVProgressHUD.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30F6C1B327664C7200BE5AB2 /* SVProgressHUD.xcframework */; };
- 9A78A7CD277BECE80093222D /* SVProgressHUD.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 30F6C1B327664C7200BE5AB2 /* SVProgressHUD.xcframework */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+ 9A78A7CD277BECE80093222D /* SVProgressHUD.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 30F6C1B327664C7200BE5AB2 /* SVProgressHUD.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9A8F9EBD259EA4C50027CE15 /* PasswordsTableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9EBC259EA4C50027CE15 /* PasswordsTableDataSource.swift */; };
9A8F9ECC259ECB410027CE15 /* PasswordSelectionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9ECB259ECB410027CE15 /* PasswordSelectionDelegate.swift */; };
9A8F9F4025A1A91F0027CE15 /* CredentialProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A8F9F3F25A1A91F0027CE15 /* CredentialProvider.swift */; };
@@ -141,7 +152,6 @@
9A996C6826DEB96B00A4485D /* passShortcuts.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 30A69945240EED5E00B7D967 /* passShortcuts.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
9A996C6B26DEB97600A4485D /* passExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = A26700241EEC466A00176B8A /* passExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
9A996C6E26DEB99200A4485D /* passKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A26075781EEC6F34005DB03E /* passKit.framework */; };
- 9A996C7126DEB99500A4485D /* passKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A26075781EEC6F34005DB03E /* passKit.framework */; };
9ADAB21D26DDA52400900F10 /* Gopenpgp.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9ADAB21C26DDA52400900F10 /* Gopenpgp.xcframework */; };
9ADC954124418A5F0005402E /* PasswordStoreTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9ADC954024418A5F0005402E /* PasswordStoreTest.swift */; };
9AFC87D325B39FF3008D6060 /* PasswordNavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AFC87D225B39FF2008D6060 /* PasswordNavigationViewController.swift */; };
@@ -407,9 +417,12 @@
9A1EF0B424C50E780074FEAC /* passBetaAutoFillExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = passBetaAutoFillExtension.entitlements; sourceTree = ""; };
9A1EF0B524C50EE00074FEAC /* passBetaExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = passBetaExtension.entitlements; sourceTree = ""; };
9A1EF0B624C50FEA0074FEAC /* passBetaShortcuts.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = passBetaShortcuts.entitlements; sourceTree = ""; };
+ 9A2C7D832783FF5200BD9AF3 /* YubiKeyConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YubiKeyConnection.swift; sourceTree = ""; };
+ 9A2C7D8A2784139200BD9AF3 /* YubiKeyAPDU.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YubiKeyAPDU.swift; sourceTree = ""; };
9A55C184259E8C5600FA8FD9 /* PasswordsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordsViewController.swift; sourceTree = ""; };
9A5865EF25AA944B006719C2 /* SearchPassword.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = SearchPassword.storyboard; sourceTree = ""; };
9A58665025AADB76006719C2 /* CredentialProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CredentialProvider.swift; sourceTree = ""; };
+ 9A5C6EEF2786C8710003F340 /* AlertPresenting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertPresenting.swift; sourceTree = ""; };
9A652413244BB33300DA0A41 /* UIAlertActionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIAlertActionExtension.swift; sourceTree = ""; };
9A74D2DF277D2F8C00F7BC44 /* UIAlertControllerExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIAlertControllerExtension.swift; sourceTree = ""; };
9A8F9EBC259EA4C50027CE15 /* PasswordsTableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordsTableDataSource.swift; sourceTree = ""; };
@@ -506,8 +519,10 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 9A5C6EF92786CE170003F340 /* YubiKit in Frameworks */,
9A996C6E26DEB99200A4485D /* passKit.framework in Frameworks */,
30A3001A26DA697C002A734E /* SwiftyUserDefaults in Frameworks */,
+ 9A5C6F042787F09D0003F340 /* Gopenpgp.xcframework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -521,6 +536,7 @@
9A1D1CE526E5D1CE0052028E /* OneTimePassword in Frameworks */,
30A3001626DA6697002A734E /* SwiftyUserDefaults in Frameworks */,
3032DA5626DAF4E500A7728C /* ObjectivePGP in Frameworks */,
+ 9A2C7D862783FF9600BD9AF3 /* YubiKit in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -539,7 +555,10 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 9A996C7126DEB99500A4485D /* passKit.framework in Frameworks */,
+ 9A5C6F022787F09A0003F340 /* passKit.framework in Frameworks */,
+ 9A5C6EFB2786CE5E0003F340 /* YubiKit in Frameworks */,
+ 9A5C6EFF2787F0980003F340 /* Gopenpgp.xcframework in Frameworks */,
+ 9A5C6F082787F0C20003F340 /* SwiftyUserDefaults in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -560,6 +579,7 @@
9A996C5326DDF61F00A4485D /* Base32 in Frameworks */,
9A78A7CC277BECE80093222D /* SVProgressHUD.xcframework in Frameworks */,
3032DA5426DAF4C200A7728C /* ObjectivePGP in Frameworks */,
+ 9A2C7D822782CB2F00BD9AF3 /* YubiKit in Frameworks */,
3010CB6626DA500F008964D2 /* KeychainAccess in Frameworks */,
9A996C5826DEB0D100A4485D /* passKit.framework in Frameworks */,
30ED1777276F8842009BA876 /* ObjectiveGit in Frameworks */,
@@ -724,6 +744,14 @@
path = Services;
sourceTree = "";
};
+ 9A5C6EF32786C9C00003F340 /* Protocols */ = {
+ isa = PBXGroup;
+ children = (
+ 9A5C6EEF2786C8710003F340 /* AlertPresenting.swift */,
+ );
+ path = Protocols;
+ sourceTree = "";
+ };
9A8F9EBB259EA4A80027CE15 /* Services */ = {
isa = PBXGroup;
children = (
@@ -806,6 +834,7 @@
A26075791EEC6F34005DB03E /* passKit */ = {
isa = PBXGroup;
children = (
+ 9A5C6EF32786C9C00003F340 /* Protocols */,
A2C532B9201DD07500DB9F53 /* Controllers */,
30CCA90C232584560048CA51 /* Crypto */,
30B6AABA21F49095006B352D /* Extensions */,
@@ -877,6 +906,8 @@
A2F4E20F1EED7F0A0011986E /* Helpers */ = {
isa = PBXGroup;
children = (
+ 9A2C7D832783FF5200BD9AF3 /* YubiKeyConnection.swift */,
+ 9A2C7D8A2784139200BD9AF3 /* YubiKeyAPDU.swift */,
30697C2921F63C590064FCAC /* AppError.swift */,
302B2C9722C2BDE700D831EE /* AppKeychain.swift */,
3087574E2343E42A00B971A2 /* Colors.swift */,
@@ -1075,6 +1106,7 @@
name = passAutoFillExtension;
packageProductDependencies = (
30A3001926DA697C002A734E /* SwiftyUserDefaults */,
+ 9A5C6EF82786CE170003F340 /* YubiKit */,
);
productName = passAutoFillExtension;
productReference = A239F5952158C08B00576CBF /* passAutoFillExtension.appex */;
@@ -1100,6 +1132,7 @@
3032DA5526DAF4E500A7728C /* ObjectivePGP */,
9A996C5626DDF65900A4485D /* Base32 */,
9A1D1CE426E5D1CE0052028E /* OneTimePassword */,
+ 9A2C7D852783FF9600BD9AF3 /* YubiKit */,
);
productName = passKit;
productReference = A26075781EEC6F34005DB03E /* passKit.framework */;
@@ -1142,6 +1175,10 @@
dependencies = (
);
name = passExtension;
+ packageProductDependencies = (
+ 9A5C6EFA2786CE5E0003F340 /* YubiKit */,
+ 9A5C6F072787F0C20003F340 /* SwiftyUserDefaults */,
+ );
productName = passExtension;
productReference = A26700241EEC466A00176B8A /* passExtension.appex */;
productType = "com.apple.product-type.app-extension";
@@ -1197,6 +1234,7 @@
9A996C5226DDF61F00A4485D /* Base32 */,
9A1F47F926E5CF4B000C0E01 /* OneTimePassword */,
30ED1776276F8842009BA876 /* ObjectiveGit */,
+ 9A2C7D812782CB2F00BD9AF3 /* YubiKit */,
);
productName = pass;
productReference = DC917BD31E2E8231000FDF54 /* Pass.app */;
@@ -1300,6 +1338,7 @@
3032DA5226DAF4C200A7728C /* XCRemoteSwiftPackageReference "ObjectivePGP" */,
9A1F47F826E5CF4B000C0E01 /* XCRemoteSwiftPackageReference "OneTimePassword" */,
30ED1775276F8842009BA876 /* XCRemoteSwiftPackageReference "objective-git-swift-package" */,
+ 9A2C7D802782CB2F00BD9AF3 /* XCRemoteSwiftPackageReference "yubikit-ios" */,
);
productRefGroup = DC917BD41E2E8231000FDF54 /* Products */;
projectDirPath = "";
@@ -1491,6 +1530,7 @@
30697C3C21F63C990064FCAC /* UITextFieldExtension.swift in Sources */,
302E85632125EE550031BA64 /* Constants.swift in Sources */,
9A652414244BB33300DA0A41 /* UIAlertActionExtension.swift in Sources */,
+ 9A2C7D842783FF5200BD9AF3 /* YubiKeyConnection.swift in Sources */,
301F6463216162550071A4CE /* AdditionField.swift in Sources */,
30697C3021F63C5A0064FCAC /* AppError.swift in Sources */,
30697C2B21F63C5A0064FCAC /* Globals.swift in Sources */,
@@ -1513,6 +1553,7 @@
30B4C7BA24084AAA008B86F7 /* PasswordGenerator.swift in Sources */,
30A1D2A621B2D46100E2D1F7 /* OTPType.swift in Sources */,
3032328E22CBD4CD009EBD9C /* CryptographicKeys.swift in Sources */,
+ 9A5C6EF42786CA5F0003F340 /* AlertPresenting.swift in Sources */,
30697C2A21F63C5A0064FCAC /* NotificationNames.swift in Sources */,
30CCA91623258C380048CA51 /* PGPInterface.swift in Sources */,
30DAFD4A240985A7002456E7 /* Array+Slices.swift in Sources */,
@@ -1527,6 +1568,7 @@
30697C3A21F63C990064FCAC /* UIViewControllerExtension.swift in Sources */,
30697C2E21F63C5A0064FCAC /* Utils.swift in Sources */,
30CCA91823258E760048CA51 /* GopenPGPInterface.swift in Sources */,
+ 9A2C7D8B2784139200BD9AF3 /* YubiKeyAPDU.swift in Sources */,
30697C4521F63CAB0064FCAC /* Password.swift in Sources */,
30697C4421F63CAB0064FCAC /* PasswordEntity.swift in Sources */,
30BAC8CD22E3BB9700438475 /* KeyStore.swift in Sources */,
@@ -2796,6 +2838,14 @@
revision = 8d59e4abba762d0f1e9aed161081f7b3fe21daa0;
};
};
+ 9A2C7D802782CB2F00BD9AF3 /* XCRemoteSwiftPackageReference "yubikit-ios" */ = {
+ isa = XCRemoteSwiftPackageReference;
+ repositoryURL = "https://github.com/Yubico/yubikit-ios";
+ requirement = {
+ kind = upToNextMajorVersion;
+ minimumVersion = 4.0.0;
+ };
+ };
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
@@ -2874,6 +2924,31 @@
package = 9A1F47F826E5CF4B000C0E01 /* XCRemoteSwiftPackageReference "OneTimePassword" */;
productName = OneTimePassword;
};
+ 9A2C7D812782CB2F00BD9AF3 /* YubiKit */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 9A2C7D802782CB2F00BD9AF3 /* XCRemoteSwiftPackageReference "yubikit-ios" */;
+ productName = YubiKit;
+ };
+ 9A2C7D852783FF9600BD9AF3 /* YubiKit */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 9A2C7D802782CB2F00BD9AF3 /* XCRemoteSwiftPackageReference "yubikit-ios" */;
+ productName = YubiKit;
+ };
+ 9A5C6EF82786CE170003F340 /* YubiKit */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 9A2C7D802782CB2F00BD9AF3 /* XCRemoteSwiftPackageReference "yubikit-ios" */;
+ productName = YubiKit;
+ };
+ 9A5C6EFA2786CE5E0003F340 /* YubiKit */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 9A2C7D802782CB2F00BD9AF3 /* XCRemoteSwiftPackageReference "yubikit-ios" */;
+ productName = YubiKit;
+ };
+ 9A5C6F072787F0C20003F340 /* SwiftyUserDefaults */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 3010CB5E26DA4F87008964D2 /* XCRemoteSwiftPackageReference "SwiftyUserDefaults" */;
+ productName = SwiftyUserDefaults;
+ };
9A996C5226DDF61F00A4485D /* Base32 */ = {
isa = XCSwiftPackageProductDependency;
package = 30A3000C26DA62F4002A734E /* XCRemoteSwiftPackageReference "Base32" */;
diff --git a/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 39a1af92..253dc27a 100644
--- a/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -63,6 +63,15 @@
"revision": "f66bcd04088582c8fbb5cb8554d577e303bae396",
"version": "5.3.0"
}
+ },
+ {
+ "package": "YubiKit",
+ "repositoryURL": "https://github.com/Yubico/yubikit-ios",
+ "state": {
+ "branch": null,
+ "revision": "7e75fe8f057acf9bf7ac134d375783a1d409f79e",
+ "version": "4.1.0"
+ }
}
]
},
diff --git a/pass/AppDelegate.swift b/pass/AppDelegate.swift
index 4412adaf..a65ca6ee 100644
--- a/pass/AppDelegate.swift
+++ b/pass/AppDelegate.swift
@@ -35,6 +35,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
}
UNUserNotificationCenter.current().delegate = NotificationCenterDispatcher.shared
+ #if !targetEnvironment(simulator)
+ _ = passKit.YubiKeyConnection.shared
+ #endif
return true
}
diff --git a/pass/Controllers/PGPKeyArmorImportTableViewController.swift b/pass/Controllers/PGPKeyArmorImportTableViewController.swift
index ac407694..fef56a3a 100644
--- a/pass/Controllers/PGPKeyArmorImportTableViewController.swift
+++ b/pass/Controllers/PGPKeyArmorImportTableViewController.swift
@@ -101,7 +101,7 @@ extension PGPKeyArmorImportTableViewController: PGPKeyImporter {
Utils.alert(title: "CannotSave".localize(), message: "SetPublicKey.".localize(), controller: self, completion: nil)
return false
}
- guard !armorPrivateKeyTextView.text.isEmpty else {
+ guard Defaults.isYubiKeyEnabled || !armorPrivateKeyTextView.text.isEmpty else {
Utils.alert(title: "CannotSave".localize(), message: "SetPrivateKey.".localize(), controller: self, completion: nil)
return false
}
diff --git a/pass/Controllers/PGPKeyFIleImportTableViewController.swift b/pass/Controllers/PGPKeyFIleImportTableViewController.swift
index 6a6322a0..58dd834f 100644
--- a/pass/Controllers/PGPKeyFIleImportTableViewController.swift
+++ b/pass/Controllers/PGPKeyFIleImportTableViewController.swift
@@ -8,7 +8,7 @@
import passKit
-class PGPKeyFileImportTableViewController: AutoCellHeightUITableViewController {
+class PGPKeyFileImportTableViewController: AutoCellHeightUITableViewController, AlertPresenting {
@IBOutlet var pgpPublicKeyFile: UITableViewCell!
@IBOutlet var pgpPrivateKeyFile: UITableViewCell!
@@ -25,7 +25,7 @@ class PGPKeyFileImportTableViewController: AutoCellHeightUITableViewController {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath)
- let picker = UIDocumentPickerViewController(documentTypes: ["public.data"], in: .open)
+ let picker = UIDocumentPickerViewController(documentTypes: ["public.item"], in: .open)
cell?.isSelected = false
if cell == pgpPublicKeyFile {
currentlyPicking = .public
@@ -71,7 +71,7 @@ extension PGPKeyFileImportTableViewController: UIDocumentPickerDelegate {
}
} catch {
let message = "FileCannotBeImported.".localize(fileName) | "UnderlyingError".localize(error.localizedDescription)
- Utils.alert(title: "CannotImportFile".localize(), message: message, controller: self)
+ presentFailureAlert(title: "CannotImportFile".localize(), message: message)
}
}
}
@@ -81,19 +81,20 @@ extension PGPKeyFileImportTableViewController: PGPKeyImporter {
static let label = "LoadFromFiles".localize()
func isReadyToUse() -> Bool {
- validate(key: publicKey) && validate(key: privateKey)
+ validate(key: publicKey) && (Defaults.isYubiKeyEnabled || validate(key: privateKey))
}
func importKeys() throws {
- guard let publicKey = publicKey, let privateKey = privateKey else {
- return
+ if let publicKey = publicKey {
+ try KeyFileManager.PublicPGP.importKey(from: publicKey)
+ }
+ if let privateKey = privateKey {
+ try KeyFileManager.PrivatePGP.importKey(from: privateKey)
}
- try KeyFileManager.PublicPGP.importKey(from: publicKey)
- try KeyFileManager.PrivatePGP.importKey(from: privateKey)
}
func doAfterImport() {
- Utils.alert(title: "RememberToRemoveKey".localize(), message: "RememberToRemoveKeyFromLocation.".localize(), controller: self)
+ presentAlert(title: "RememberToRemoveKey".localize(), message: "RememberToRemoveKeyFromLocation.".localize())
}
func saveImportedKeys() {
@@ -102,7 +103,7 @@ extension PGPKeyFileImportTableViewController: PGPKeyImporter {
private func validate(key: String?) -> Bool {
guard key != nil else {
- Utils.alert(title: "CannotSavePgpKey".localize(), message: "KeyFileNotSet.".localize(), controller: self)
+ presentFailureAlert(title: "CannotSavePgpKey".localize(), message: "KeyFileNotSet.".localize())
return false
}
return true
diff --git a/pass/Controllers/PGPKeyURLImportTableViewController.swift b/pass/Controllers/PGPKeyURLImportTableViewController.swift
index 9f5e4f3c..30c3deca 100644
--- a/pass/Controllers/PGPKeyURLImportTableViewController.swift
+++ b/pass/Controllers/PGPKeyURLImportTableViewController.swift
@@ -9,7 +9,7 @@
import passKit
import UIKit
-class PGPKeyURLImportTableViewController: AutoCellHeightUITableViewController {
+class PGPKeyURLImportTableViewController: AutoCellHeightUITableViewController, AlertPresenting {
@IBOutlet var pgpPublicKeyURLTextField: UITextField!
@IBOutlet var pgpPrivateKeyURLTextField: UITextField!
@@ -24,18 +24,11 @@ class PGPKeyURLImportTableViewController: AutoCellHeightUITableViewController {
@IBAction
private func save(_: Any) {
- guard let publicKeyURLText = pgpPublicKeyURLTextField.text,
- let publicKeyURL = URL(string: publicKeyURLText),
- let privateKeyURLText = pgpPrivateKeyURLTextField.text,
- let privateKeyURL = URL(string: privateKeyURLText) else {
- Utils.alert(title: "CannotSavePgpKey".localize(), message: "SetPgpKeyUrlsFirst.".localize(), controller: self)
- return
- }
- if privateKeyURL.scheme?.lowercased() == "http" || publicKeyURL.scheme?.lowercased() == "http" {
- Utils.alert(title: "HttpNotSecure".localize(), message: "ReallyUseHttp.".localize(), controller: self)
+ pgpPublicKeyURL = validate(pgpKeyURLText: pgpPublicKeyURLTextField.text)
+
+ if !Defaults.isYubiKeyEnabled {
+ pgpPrivateKeyURL = validate(pgpKeyURLText: pgpPrivateKeyURLTextField.text)
}
- pgpPrivateKeyURL = privateKeyURL
- pgpPublicKeyURL = publicKeyURL
saveImportedKeys()
}
}
@@ -45,35 +38,39 @@ extension PGPKeyURLImportTableViewController: PGPKeyImporter {
static let label = "DownloadFromUrl".localize()
func isReadyToUse() -> Bool {
- validate(pgpKeyURL: pgpPublicKeyURLTextField.text ?? "")
- && validate(pgpKeyURL: pgpPrivateKeyURLTextField.text ?? "")
+ validate(pgpKeyURLText: pgpPublicKeyURLTextField.text) != nil
+ && (Defaults.isYubiKeyEnabled || validate(pgpKeyURLText: pgpPrivateKeyURLTextField.text ?? "") != nil)
}
func importKeys() throws {
- Defaults.pgpPrivateKeyURL = pgpPrivateKeyURL
- Defaults.pgpPublicKeyURL = pgpPublicKeyURL
+ if let pgpPrivateKeyURL = pgpPrivateKeyURL {
+ Defaults.pgpPrivateKeyURL = pgpPrivateKeyURL
+ try KeyFileManager.PrivatePGP.importKey(from: pgpPrivateKeyURL)
+ }
- try KeyFileManager.PublicPGP.importKey(from: Defaults.pgpPublicKeyURL!)
- try KeyFileManager.PrivatePGP.importKey(from: Defaults.pgpPrivateKeyURL!)
+ if let pgpPublicKeyURL = pgpPublicKeyURL {
+ Defaults.pgpPublicKeyURL = pgpPublicKeyURL
+ try KeyFileManager.PublicPGP.importKey(from: pgpPublicKeyURL)
+ }
}
func doAfterImport() {
- Utils.alert(title: "RememberToRemoveKey".localize(), message: "RememberToRemoveKeyFromServer.".localize(), controller: self)
+ presentAlert(title: "RememberToRemoveKey".localize(), message: "RememberToRemoveKeyFromServer.".localize())
}
func saveImportedKeys() {
performSegue(withIdentifier: "savePGPKeySegue", sender: self)
}
- private func validate(pgpKeyURL: String) -> Bool {
- guard let url = URL(string: pgpKeyURL) else {
- Utils.alert(title: "CannotSavePgpKey".localize(), message: "SetPgpKeyUrlsFirst.".localize(), controller: self)
- return false
+ private func validate(pgpKeyURLText: String?) -> URL? {
+ guard let pgpKeyURL = pgpKeyURLText, let url = URL(string: pgpKeyURL) else {
+ presentFailureAlert(title: "CannotSavePgpKey".localize(), message: "SetPgpKeyUrlsFirst.".localize())
+ return nil
}
guard url.scheme == "https" || url.scheme == "http" else {
- Utils.alert(title: "CannotSavePgpKey".localize(), message: "UseEitherHttpsOrHttp.".localize(), controller: self)
- return false
+ presentFailureAlert(title: "CannotSavePgpKey".localize(), message: "UseEitherHttpsOrHttp.".localize())
+ return nil
}
- return true
+ return url
}
}
diff --git a/pass/Controllers/PasswordDetailTableViewController.swift b/pass/Controllers/PasswordDetailTableViewController.swift
index d5264999..cd1e4d48 100644
--- a/pass/Controllers/PasswordDetailTableViewController.swift
+++ b/pass/Controllers/PasswordDetailTableViewController.swift
@@ -7,11 +7,13 @@
//
import FavIcon
+import Gopenpgp
+import passAutoFillExtension
import passKit
import SVProgressHUD
import UIKit
-class PasswordDetailTableViewController: UITableViewController, UIGestureRecognizerDelegate {
+class PasswordDetailTableViewController: UITableViewController, UIGestureRecognizerDelegate, AlertPresenting {
var passwordEntity: PasswordEntity?
private var password: Password?
private var passwordImage: UIImage?
@@ -87,7 +89,15 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
decryptThenShowPassword()
}
- private func decryptThenShowPassword(keyID: String? = nil) {
+ private func decryptThenShowPassword() {
+ if Defaults.isYubiKeyEnabled {
+ decryptThenShowPasswordYubiKey()
+ } else {
+ decryptThenShowPasswordLocalKey()
+ }
+ }
+
+ private func decryptThenShowPasswordLocalKey(keyID: String? = nil) {
guard let passwordEntity = passwordEntity else {
Utils.alert(title: "CannotShowPassword".localize(), message: "PasswordDoesNotExist".localize(), controller: self, completion: {
self.navigationController!.popViewController(animated: true)
@@ -106,7 +116,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
let alert = UIAlertController(title: "CannotShowPassword".localize(), message: AppError.pgpPrivateKeyNotFound(keyID: key).localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
let selectKey = UIAlertAction.selectKey(controller: self) { action in
- self.decryptThenShowPassword(keyID: action.title)
+ self.decryptThenShowPasswordLocalKey(keyID: action.title)
}
alert.addAction(selectKey)
@@ -119,7 +129,7 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
alert.addAction(UIAlertAction.cancelAndPopView(controller: self))
alert.addAction(
UIAlertAction(title: "TryAgain".localize(), style: .default) { _ in
- self.decryptThenShowPassword()
+ self.decryptThenShowPasswordLocalKey()
}
)
self.present(alert, animated: true, completion: nil)
@@ -509,3 +519,66 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
tableView.deselectRow(at: indexPath, animated: true)
}
}
+
+extension PasswordDetailTableViewController {
+ private func requestYubiKeyPIN(completion: @escaping (String) -> Void) {
+ let alert = UIAlertController(title: "YubiKey PIN", message: "Verify YubiKey OpenPGP PIN.", preferredStyle: .alert)
+ alert.addAction(
+ UIAlertAction.cancel { _ in
+ self.navigationController!.popViewController(animated: true)
+ }
+ )
+ alert.addAction(
+ UIAlertAction.ok { _ in
+ let pin = alert.textFields?.first?.text ?? ""
+ completion(pin)
+ }
+ )
+ alert.addTextField { textField in
+ textField.isSecureTextEntry = true
+ }
+ present(alert, animated: true)
+ }
+
+ private func handleError(error: AppError) {
+ switch error {
+ case let .yubiKey(yubiKeyError):
+ let errorMessage = yubiKeyError.localizedDescription
+ if #available(iOS 13.0, *) {
+ YubiKitManager.shared.stopNFCConnection(withErrorMessage: errorMessage)
+ DispatchQueue.main.async {
+ self.navigationController?.popViewController(animated: true)
+ }
+ } else {
+ DispatchQueue.main.async {
+ self.presentFailureAlert(message: errorMessage) { _ in
+ self.navigationController?.popViewController(animated: true)
+ }
+ }
+ }
+ default:
+ DispatchQueue.main.async {
+ self.presentFailureAlert(message: error.localizedDescription) { _ in
+ self.navigationController?.popViewController(animated: true)
+ }
+ }
+ }
+ }
+
+ private func handleCancellation(_: Error) {
+ DispatchQueue.main.async {
+ self.navigationController?.popViewController(animated: true)
+ }
+ }
+
+ private func decryptThenShowPasswordYubiKey() {
+ guard let passwordEntity = passwordEntity else {
+ handleError(error: AppError.other(message: "PasswordDoesNotExist"))
+ return
+ }
+ Pass.yubiKeyDecrypt(passwordEntity: passwordEntity, requestPIN: requestYubiKeyPIN, errorHandler: handleError, cancellation: handleCancellation) { password in
+ self.password = password
+ self.showPassword()
+ }
+ }
+}
diff --git a/pass/Controllers/PasswordNavigationViewController.swift b/pass/Controllers/PasswordNavigationViewController.swift
index 60dc7d46..7ac2839d 100644
--- a/pass/Controllers/PasswordNavigationViewController.swift
+++ b/pass/Controllers/PasswordNavigationViewController.swift
@@ -319,7 +319,7 @@ extension PasswordNavigationViewController {
override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool {
if identifier == "showPasswordDetail" {
- guard PGPAgent.shared.isPrepared else {
+ guard Defaults.isYubiKeyEnabled || PGPAgent.shared.isPrepared else {
Utils.alert(title: "CannotShowPassword".localize(), message: "PgpKeyNotSet.".localize(), controller: self)
return false
}
diff --git a/pass/Controllers/SettingsTableViewController.swift b/pass/Controllers/SettingsTableViewController.swift
index 5463a2a0..1fe9aee2 100644
--- a/pass/Controllers/SettingsTableViewController.swift
+++ b/pass/Controllers/SettingsTableViewController.swift
@@ -87,12 +87,16 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
private func setPGPKeyTableViewCellDetailText() {
var label = "NotSet".localize()
+
let keyID = (try? PGPAgent.shared.getShortKeyID()) ?? []
if keyID.count == 1 {
label = keyID.first ?? ""
} else if keyID.count > 1 {
label = "Multiple"
}
+ if Defaults.isYubiKeyEnabled {
+ label += "+YubiKey"
+ }
pgpKeyTableViewCell.detailTextLabel?.text = label
}
@@ -180,6 +184,13 @@ class SettingsTableViewController: UITableViewController, UITabBarControllerDele
)
}
+ optionMenu.addAction(
+ UIAlertAction(title: Defaults.isYubiKeyEnabled ? "✓ YubiKey" : "YubiKey", style: .default) { _ in
+ Defaults.isYubiKeyEnabled.toggle()
+ self.setPGPKeyTableViewCellDetailText()
+ }
+ )
+
if Defaults.pgpKeySource != nil {
optionMenu.addAction(
UIAlertAction(title: "RemovePgpKeys".localize(), style: .destructive) { _ in
diff --git a/pass/Helpers/Objective-CBridgingHeader.h b/pass/Helpers/Objective-CBridgingHeader.h
index ff807e53..3a71b73d 100644
--- a/pass/Helpers/Objective-CBridgingHeader.h
+++ b/pass/Helpers/Objective-CBridgingHeader.h
@@ -10,5 +10,6 @@
#define Objective_CBridgingHeader_h
@import ObjectiveGit;
+#import
#endif /* Objective_CBridgingHeader_h */
diff --git a/pass/Info.plist b/pass/Info.plist
index 7faefec2..f5a7106e 100644
--- a/pass/Info.plist
+++ b/pass/Info.plist
@@ -2,6 +2,21 @@
+ com.apple.developer.nfc.readersession.iso7816.select-identifiers
+
+ A000000527471117
+ A0000006472F0001
+ A0000005272101
+ A000000308
+ D27600012401
+ A000000527200101
+
+ NFCReaderUsageDescription
+ The application needs access to NFC reading to communicate with your YubiKey.
+ UISupportedExternalAccessoryProtocols
+
+ com.yubico.ylp
+
CFBundleDevelopmentRegion
en
CFBundleDisplayName
diff --git a/pass/Services/PasswordDecryptor.swift b/pass/Services/PasswordDecryptor.swift
index 4a9c6a1f..0b6d0679 100644
--- a/pass/Services/PasswordDecryptor.swift
+++ b/pass/Services/PasswordDecryptor.swift
@@ -6,11 +6,28 @@
// Copyright © 2021 Bob Sun. All rights reserved.
//
+import CryptoTokenKit
+import Gopenpgp
import passKit
import SVProgressHUD
import UIKit
+import YubiKit
-func decryptPassword(in controller: UIViewController, with passwordPath: String, using keyID: String? = nil, completion: @escaping ((Password) -> Void)) {
+func decryptPassword(
+ in controller: UIViewController,
+ with passwordPath: String,
+ using keyID: String? = nil,
+ completion: @escaping ((Password) -> Void)
+) {
+ // YubiKey is not supported in extension
+ if Defaults.isYubiKeyEnabled {
+ DispatchQueue.main.async {
+ let alert = UIAlertController(title: "Error", message: "YubiKey is not supported in extension, please use the Pass app instead.", preferredStyle: .alert)
+ alert.addAction(UIAlertAction.ok())
+ controller.present(alert, animated: true)
+ }
+ return
+ }
DispatchQueue.global(qos: .userInteractive).async {
do {
let requestPGPKeyPassphrase = Utils.createRequestPGPKeyPassphraseHandler(controller: controller)
@@ -37,3 +54,144 @@ func decryptPassword(in controller: UIViewController, with passwordPath: String,
}
}
}
+
+public typealias RequestPINAction = (@escaping (String) -> Void) -> Void
+
+let symmetricKeyIDNameDict: [UInt8: String] = [
+ 2: "3des",
+ 3: "cast5",
+ 7: "aes128",
+ 8: "aes192",
+ 9: "aes256",
+]
+
+private func isEncryptKeyAlgoRSA(_ applicationRelatedData: Data) -> Bool {
+ let tlv = TKBERTLVRecord.sequenceOfRecords(from: applicationRelatedData)!
+ // 0x73: Discretionary data objects
+ for record in TKBERTLVRecord.sequenceOfRecords(from: tlv.first!.value)! where record.tag == 0x73 {
+ // 0xC2: Algorithm attributes decryption, 0x01: RSA
+ for record2 in TKBERTLVRecord.sequenceOfRecords(from: record.value)! where record2.tag == 0xC2 && record2.value.first! == 0x01 {
+ return true
+ }
+ }
+ return false
+}
+
+// swiftlint:disable cyclomatic_complexity
+public func yubiKeyDecrypt(
+ passwordEntity: PasswordEntity,
+ requestPIN: @escaping RequestPINAction,
+ errorHandler: @escaping ((AppError) -> Void),
+ cancellation: @escaping ((_ error: Error) -> Void),
+ completion: @escaping ((Password) -> Void)
+) {
+ let encryptedDataPath = PasswordStore.shared.storeURL.appendingPathComponent(passwordEntity.getPath())
+
+ guard let encryptedData = try? Data(contentsOf: encryptedDataPath) else {
+ errorHandler(AppError.other(message: "PasswordDoesNotExist".localize()))
+ return
+ }
+
+ // swiftlint:disable closure_body_length
+ requestPIN { pin in
+ // swiftlint:disable closure_body_length
+ passKit.YubiKeyConnection.shared.connection(cancellation: cancellation) { connection in
+ guard let smartCard = connection.smartCardInterface else {
+ errorHandler(AppError.yubiKey(.connection(message: "Failed to get smart card interface.")))
+ return
+ }
+
+ // 1. Select OpenPGP application
+ let selectOpenPGPAPDU = YubiKeyAPDU.selectOpenPGPApplication()
+ smartCard.selectApplication(selectOpenPGPAPDU) { _, error in
+ guard error == nil else {
+ errorHandler(AppError.yubiKey(.selectApplication(message: "Failed to select application.")))
+ return
+ }
+
+ // 2. Verify PIN
+ let verifyApdu = YubiKeyAPDU.verify(password: pin)
+ smartCard.executeCommand(verifyApdu) { _, error in
+ guard error == nil else {
+ errorHandler(AppError.yubiKey(.verify(message: "Failed to verify PIN.")))
+ return
+ }
+
+ let applicationRelatedDataApdu = YubiKeyAPDU.get_application_related_data()
+ smartCard.executeCommand(applicationRelatedDataApdu) { data, _ in
+ guard let data = data else {
+ errorHandler(AppError.yubiKey(.decipher(message: "Failed to get application related data.")))
+ return
+ }
+
+ if !isEncryptKeyAlgoRSA(data) {
+ errorHandler(AppError.yubiKey(.decipher(message: "Encryption key algorithm is not supported. Supported algorithm: RSA.")))
+ return
+ }
+
+ // 3. Decipher
+ let ciphertext = encryptedData
+ var error: NSError?
+ let message = CryptoNewPGPMessage(ciphertext)
+ guard let mpi1 = Gopenpgp.HelperPassGetEncryptedMPI1(message, &error) else {
+ errorHandler(AppError.yubiKey(.decipher(message: "Failed to get encrypted MPI.")))
+ return
+ }
+
+ let decipherApdu = YubiKeyAPDU.decipher(data: mpi1)
+ smartCard.executeCommand(decipherApdu) { data, error in
+ guard let data = data else {
+ errorHandler(AppError.yubiKey(.decipher(message: "Failed to execute decipher.")))
+ return
+ }
+
+ if #available(iOS 13.0, *) {
+ YubiKitManager.shared.stopNFCConnection()
+ }
+ guard let algoByte = data.first, let algo = symmetricKeyIDNameDict[algoByte] else {
+ errorHandler(AppError.yubiKey(.decipher(message: "Failed to new session key.")))
+ return
+ }
+ guard let session_key = Gopenpgp.CryptoNewSessionKeyFromToken(data[1 ..< data.count - 2], algo) else {
+ errorHandler(AppError.yubiKey(.decipher(message: "Failed to new session key.")))
+ return
+ }
+
+ var error: NSError?
+ let message = CryptoNewPGPMessage(ciphertext)
+
+ guard let plaintext = Gopenpgp.HelperPassDecryptWithSessionKey(message, session_key, &error)?.data else {
+ errorHandler(AppError.yubiKey(.decipher(message: "Failed to decrypt with session key.")))
+ return
+ }
+
+ guard let plaintext_str = String(data: plaintext, encoding: .utf8) else {
+ errorHandler(AppError.yubiKey(.decipher(message: "Failed to convert plaintext to string.")))
+ return
+ }
+
+ guard let password = try? Password(name: passwordEntity.getName(), url: passwordEntity.getURL(), plainText: plaintext_str) else {
+ errorHandler(AppError.yubiKey(.decipher(message: "Failed to construct password.")))
+ return
+ }
+
+ completion(password)
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+extension Data {
+ struct HexEncodingOptions: OptionSet {
+ let rawValue: Int
+ static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
+ }
+
+ func hexEncodedString(options: HexEncodingOptions = []) -> String {
+ let format = options.contains(.upperCase) ? "%02hhX" : "%02hhx"
+ return map { String(format: format, $0) }.joined()
+ }
+}
diff --git a/pass/pass.entitlements b/pass/pass.entitlements
index 1444b8a2..d9153414 100644
--- a/pass/pass.entitlements
+++ b/pass/pass.entitlements
@@ -4,6 +4,11 @@
com.apple.developer.authentication-services.autofill-credential-provider
+ com.apple.developer.nfc.readersession.formats
+
+ NDEF
+ TAG
+
com.apple.developer.siri
com.apple.security.application-groups
diff --git a/pass/passBeta.entitlements b/pass/passBeta.entitlements
index 5e2efc75..e34057c4 100644
--- a/pass/passBeta.entitlements
+++ b/pass/passBeta.entitlements
@@ -4,6 +4,11 @@
com.apple.developer.authentication-services.autofill-credential-provider
+ com.apple.developer.nfc.readersession.formats
+
+ NDEF
+ TAG
+
com.apple.developer.siri
com.apple.security.application-groups
diff --git a/passKit/Extensions/UIAlertControllerExtension.swift b/passKit/Extensions/UIAlertControllerExtension.swift
index 962c7074..a3617ff9 100644
--- a/passKit/Extensions/UIAlertControllerExtension.swift
+++ b/passKit/Extensions/UIAlertControllerExtension.swift
@@ -14,4 +14,10 @@ public extension UIAlertController {
alert.addAction(UIAlertAction.cancel())
return alert
}
+
+ class func showErrorAlert(title: String, message: String, completion: ((UIAlertAction) -> Void)? = nil) -> UIAlertController {
+ let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
+ alert.addAction(UIAlertAction.ok(handler: completion))
+ return alert
+ }
}
diff --git a/passKit/Helpers/AppError.swift b/passKit/Helpers/AppError.swift
index 08dbacec..a8a4ca1c 100644
--- a/passKit/Helpers/AppError.swift
+++ b/passKit/Helpers/AppError.swift
@@ -6,6 +6,8 @@
// Copyright © 2017 Bob Sun. All rights reserved.
//
+import Foundation
+
public enum AppError: Error, Equatable {
case repositoryNotSet
case repositoryRemoteBranchNotFound(branchName: String)
@@ -18,13 +20,31 @@ public enum AppError: Error, Equatable {
case gitPushNotSuccessful
case pgpPublicKeyNotFound(keyID: String)
case pgpPrivateKeyNotFound(keyID: String)
+ case yubiKey(YubiKeyError)
+ case passwordFileNotFound(path: String)
case keyExpiredOrIncompatible
case wrongPassphrase
case wrongPasswordFilename
case decryption
case encryption
case encoding
- case unknown
+ case other(message: String)
+}
+
+public enum YubiKeyError: Error, Equatable {
+ case connection(message: String)
+ case selectApplication(message: String)
+ case verify(message: String)
+ case decipher(message: String)
+}
+
+extension YubiKeyError: LocalizedError {
+ public var errorDescription: String? {
+ switch self {
+ case let .connection(message), let .decipher(message), let .selectApplication(message), let .verify(message):
+ return message
+ }
+ }
}
extension AppError: LocalizedError {
@@ -36,6 +56,8 @@ extension AppError: LocalizedError {
return localizationKey.localize(name)
case let .pgpPrivateKeyNotFound(keyID), let .pgpPublicKeyNotFound(keyID):
return localizationKey.localize(keyID)
+ case let .other(message):
+ return message.localize()
default:
return localizationKey.localize()
}
diff --git a/passKit/Helpers/DefaultsKeys.swift b/passKit/Helpers/DefaultsKeys.swift
index a0bbf81a..a96b2066 100644
--- a/passKit/Helpers/DefaultsKeys.swift
+++ b/passKit/Helpers/DefaultsKeys.swift
@@ -26,6 +26,7 @@ public extension DefaultsKeys {
var pgpKeySource: DefaultsKey { .init("pgpKeySource") }
var pgpPublicKeyURL: DefaultsKey { .init("pgpPublicKeyURL") }
var pgpPrivateKeyURL: DefaultsKey { .init("pgpPrivateKeyURL") }
+ var isYubiKeyEnabled: DefaultsKey { .init("isYubiKeyEnabled", defaultValue: false) }
// Keep them for legacy reasons.
var pgpPublicKeyArmor: DefaultsKey { .init("pgpPublicKeyArmor") }
diff --git a/passKit/Helpers/YubiKeyAPDU.swift b/passKit/Helpers/YubiKeyAPDU.swift
new file mode 100644
index 00000000..70821114
--- /dev/null
+++ b/passKit/Helpers/YubiKeyAPDU.swift
@@ -0,0 +1,54 @@
+//
+// YubiKeyAPDU.swift
+// passKit
+//
+// Copyright © 2022 Bob Sun. All rights reserved.
+//
+
+import YubiKit
+
+public enum YubiKeyAPDU {
+ public static func selectOpenPGPApplication() -> YKFSelectApplicationAPDU {
+ let selectOpenPGPAPDU = YKFSelectApplicationAPDU(data: Data([0xD2, 0x76, 0x00, 0x01, 0x24, 0x01]))!
+ return selectOpenPGPAPDU
+ }
+
+ public static func verify(password: String) -> YKFAPDU {
+ let pw1: [UInt8] = Array(password.utf8)
+ var apdu: [UInt8] = []
+ apdu += [0x00] // CLA
+ apdu += [0x20] // INS: VERIFY
+ apdu += [0x00] // P1
+ apdu += [0x82] // P2: PW1
+ apdu += withUnsafeBytes(of: UInt8(pw1.count).bigEndian, Array.init)
+ apdu += pw1
+ let verifyApdu = YKFAPDU(data: Data(apdu))!
+ return verifyApdu
+ }
+
+ public static func decipher(data: Data) -> YKFAPDU {
+ var apdu: [UInt8] = []
+ apdu += [0x00] // CLA
+ apdu += [0x2A, 0x80, 0x86] // INS, P1, P2: PSO.DECIPHER
+ // Lc, An extended Lc field consists of three bytes:
+ // one byte set to '00' followed by two bytes not set to '0000' (1 to 65535 dec.).
+ apdu += [0x00] + withUnsafeBytes(of: UInt16(data.count + 1).bigEndian, Array.init)
+ // Padding indicator byte (00) for RSA or (02) for AES followed by cryptogram Cipher DO 'A6' for ECDH
+ apdu += [0x00]
+ apdu += data
+ apdu += [0x02, 0x00]
+ let decipherApdu = YKFAPDU(data: Data(apdu))!
+
+ return decipherApdu
+ }
+
+ public static func get_application_related_data() -> YKFAPDU {
+ var apdu: [UInt8] = []
+ apdu += [0x00] // CLA
+ apdu += [0xCA] // INS: GET DATA
+ apdu += [0x00]
+ apdu += [0x6E] // P2: application related data
+ apdu += [0x00]
+ return YKFAPDU(data: Data(apdu))!
+ }
+}
diff --git a/passKit/Helpers/YubiKeyConnection.swift b/passKit/Helpers/YubiKeyConnection.swift
new file mode 100644
index 00000000..fe759407
--- /dev/null
+++ b/passKit/Helpers/YubiKeyConnection.swift
@@ -0,0 +1,63 @@
+//
+// YubiKeyConnection.swift
+// passKit
+//
+// Copyright © 2022 Bob Sun. All rights reserved.
+//
+
+import Foundation
+import YubiKit
+
+public class YubiKeyConnection: NSObject {
+ public static let shared = YubiKeyConnection()
+
+ var accessoryConnection: YKFAccessoryConnection?
+ var nfcConnection: YKFNFCConnection?
+ var connectionCallback: ((_ connection: YKFConnectionProtocol) -> Void)?
+ var cancellationCallback: ((_ error: Error) -> Void)?
+
+ override init() {
+ super.init()
+ YubiKitManager.shared.delegate = self
+ YubiKitManager.shared.startAccessoryConnection()
+ }
+
+ public func connection(cancellation: @escaping (_ error: Error) -> Void, completion: @escaping (_ connection: YKFConnectionProtocol) -> Void) {
+ if let connection = accessoryConnection {
+ completion(connection)
+ } else {
+ connectionCallback = completion
+ if #available(iOSApplicationExtension 13.0, *) {
+ YubiKitManager.shared.startNFCConnection()
+ }
+ }
+ cancellationCallback = cancellation
+ }
+}
+
+extension YubiKeyConnection: YKFManagerDelegate {
+ public func didConnectNFC(_ connection: YKFNFCConnection) {
+ nfcConnection = connection
+ if let callback = connectionCallback {
+ callback(connection)
+ }
+ }
+
+ public func didDisconnectNFC(_: YKFNFCConnection, error _: Error?) {
+ nfcConnection = nil
+ }
+
+ public func didConnectAccessory(_ connection: YKFAccessoryConnection) {
+ accessoryConnection = connection
+ }
+
+ public func didDisconnectAccessory(_: YKFAccessoryConnection, error _: Error?) {
+ accessoryConnection = nil
+ }
+
+ public func didFailConnectingNFC(_ error: Error) {
+ if let callback = cancellationCallback {
+ callback(error)
+ }
+ }
+}
diff --git a/passKit/Models/PasswordEntity.swift b/passKit/Models/PasswordEntity.swift
index 84792b87..bbeb8616 100644
--- a/passKit/Models/PasswordEntity.swift
+++ b/passKit/Models/PasswordEntity.swift
@@ -39,7 +39,7 @@ public extension PasswordEntity {
if let path = getPath().stringByAddingPercentEncodingForRFC3986(), let url = URL(string: path) {
return url
}
- throw AppError.unknown
+ throw AppError.other(message: "cannot decode URL")
}
// XXX: define some getters to get core data, we need to consider
diff --git a/passKit/Protocols/AlertPresenting.swift b/passKit/Protocols/AlertPresenting.swift
new file mode 100644
index 00000000..ec745da5
--- /dev/null
+++ b/passKit/Protocols/AlertPresenting.swift
@@ -0,0 +1,55 @@
+//
+// AlertPresenting.swift
+// pass
+//
+// Copyright © 2022 Bob Sun. All rights reserved.
+//
+
+import UIKit
+
+public typealias AlertAction = (UIAlertAction) -> Void
+
+public protocol AlertPresenting {
+ func presentAlert(title: String, message: String)
+ func presentFailureAlert(title: String?, message: String, action: AlertAction?)
+ func presentAlertWithAction(title: String, message: String, action: AlertAction?)
+}
+
+public extension AlertPresenting where Self: UIViewController {
+ func presentAlert(title: String, message: String) {
+ presentAlert(
+ title: title,
+ message: message,
+ actions: [UIAlertAction(title: "OK", style: .cancel, handler: nil)]
+ )
+ }
+
+ // swiftlint:disable function_default_parameter_at_end
+ func presentFailureAlert(title: String? = nil, message: String, action: AlertAction? = nil) {
+ let title = title ?? "Error"
+ presentAlert(
+ title: title,
+ message: message,
+ actions: [UIAlertAction(title: "OK", style: .cancel, handler: action)]
+ )
+ }
+
+ func presentAlertWithAction(title: String, message: String, action: AlertAction?) {
+ presentAlert(
+ title: title,
+ message: message,
+ actions: [
+ UIAlertAction(title: "Yes", style: .default, handler: action),
+ UIAlertAction(title: "No", style: .cancel, handler: nil),
+ ]
+ )
+ }
+
+ private func presentAlert(title: String, message: String, actions: [UIAlertAction] = []) {
+ let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
+ actions.forEach { action in
+ alertController.addAction(action)
+ }
+ present(alertController, animated: true, completion: nil)
+ }
+}
diff --git a/scripts/gopenpgp_build.sh b/scripts/gopenpgp_build.sh
index f1997e3c..f1bac2a9 100755
--- a/scripts/gopenpgp_build.sh
+++ b/scripts/gopenpgp_build.sh
@@ -2,7 +2,7 @@
set -euox pipefail
-GOPENPGP_VERSION="v2.1.10"
+GOPENPGP_VERSION="passforios"
export GOPATH="$(pwd)/go"
export PATH="$PATH:$GOPATH/bin"
@@ -18,13 +18,11 @@ go env -w GO111MODULE=auto
go get golang.org/x/mobile/cmd/gomobile
gomobile init
-git clone --depth 1 --branch "$GOPENPGP_VERSION" https://github.com/ProtonMail/gopenpgp.git "$GOPENPGP_PATH"
-
-git apply patch/gnu-dummy.patch --directory "$GOPENPGP_PATH"
+git clone --depth 1 --branch "$GOPENPGP_VERSION" https://github.com/mssun/gopenpgp.git "$GOPENPGP_PATH"
sed -i '' 's/build android/echo "Skipping Android build."/g' "$GOPENPGP_PATH/build.sh"
(cd "$GOPENPGP_PATH" && ./build.sh)
-cp -R "$GOPENPGP_PATH/dist/Gopenpgp.xcframework" "$OUTPUT_PATH"
+cp -r "$GOPENPGP_PATH/dist/Gopenpgp.xcframework" "$OUTPUT_PATH"
From 6d1b271af6bcca94d9ba2d39da744fe32090988d Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Sun, 9 Jan 2022 22:12:41 -0800
Subject: [PATCH 003/103] Fix building issue in CI
---
pass/Controllers/PasswordDetailTableViewController.swift | 2 +-
pass/Helpers/Objective-CBridgingHeader.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/pass/Controllers/PasswordDetailTableViewController.swift b/pass/Controllers/PasswordDetailTableViewController.swift
index cd1e4d48..e39b5c61 100644
--- a/pass/Controllers/PasswordDetailTableViewController.swift
+++ b/pass/Controllers/PasswordDetailTableViewController.swift
@@ -576,7 +576,7 @@ extension PasswordDetailTableViewController {
handleError(error: AppError.other(message: "PasswordDoesNotExist"))
return
}
- Pass.yubiKeyDecrypt(passwordEntity: passwordEntity, requestPIN: requestYubiKeyPIN, errorHandler: handleError, cancellation: handleCancellation) { password in
+ yubiKeyDecrypt(passwordEntity: passwordEntity, requestPIN: requestYubiKeyPIN, errorHandler: handleError, cancellation: handleCancellation) { password in
self.password = password
self.showPassword()
}
diff --git a/pass/Helpers/Objective-CBridgingHeader.h b/pass/Helpers/Objective-CBridgingHeader.h
index 3a71b73d..5a7c3e46 100644
--- a/pass/Helpers/Objective-CBridgingHeader.h
+++ b/pass/Helpers/Objective-CBridgingHeader.h
@@ -10,6 +10,6 @@
#define Objective_CBridgingHeader_h
@import ObjectiveGit;
-#import
+#import "YubiKit.h"
#endif /* Objective_CBridgingHeader_h */
From 11282928318f3887026b461f5f66f36bdfb8adf7 Mon Sep 17 00:00:00 2001
From: Danny Moesch
Date: Tue, 25 Jan 2022 07:52:12 +0100
Subject: [PATCH 004/103] Update SwiftLint to version 0.46.x (#541)
---
scripts/swiftlint.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/swiftlint.sh b/scripts/swiftlint.sh
index e5888c3d..716aac5a 100755
--- a/scripts/swiftlint.sh
+++ b/scripts/swiftlint.sh
@@ -1,4 +1,4 @@
-SWIFTLINT_VERSION="0.45.*"
+SWIFTLINT_VERSION="0.46.*"
if [[ "${CI}" == "true" ]]; then
echo "Running in a Continuous Integration environment. Linting is skipped."
From 71260f52aa82b791e68a28870e629859c1803885 Mon Sep 17 00:00:00 2001
From: Danny Moesch
Date: Sat, 5 Feb 2022 05:54:36 +0100
Subject: [PATCH 005/103] Update ObjectivePGP to version 0.99.2 (#544)
---
pass.xcodeproj/project.pbxproj | 2 +-
.../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj
index 0139052e..aab2aeb5 100644
--- a/pass.xcodeproj/project.pbxproj
+++ b/pass.xcodeproj/project.pbxproj
@@ -2811,7 +2811,7 @@
repositoryURL = "https://github.com/krzyzanowskim/ObjectivePGP";
requirement = {
kind = upToNextMajorVersion;
- minimumVersion = 0.17.0;
+ minimumVersion = 0.99.0;
};
};
30A3000C26DA62F4002A734E /* XCRemoteSwiftPackageReference "Base32" */ = {
diff --git a/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 253dc27a..2ad0c23c 100644
--- a/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -42,8 +42,8 @@
"repositoryURL": "https://github.com/krzyzanowskim/ObjectivePGP",
"state": {
"branch": null,
- "revision": "a1ed56c067245fe5b818cbb722d70f3dd74ba213",
- "version": "0.99.0"
+ "revision": "0dc7ca7ffe193095dc37456b0c75be167a2026f4",
+ "version": "0.99.2"
}
},
{
From 2e951497adf1763d04649033990c8f966d07fbb2 Mon Sep 17 00:00:00 2001
From: Danny Moesch
Date: Sat, 5 Feb 2022 20:01:39 +0100
Subject: [PATCH 006/103] Update ObjectiveGit to version 0.17-passforios (#545)
---
pass.xcodeproj/project.pbxproj | 2 +-
.../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj
index aab2aeb5..87a00b6a 100644
--- a/pass.xcodeproj/project.pbxproj
+++ b/pass.xcodeproj/project.pbxproj
@@ -2826,7 +2826,7 @@
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/SimplyDanny/objective-git-swift-package";
requirement = {
- branch = "0.16-passforios";
+ branch = "0.17-passforios";
kind = branch;
};
};
diff --git a/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index 2ad0c23c..b3dc414f 100644
--- a/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -32,8 +32,8 @@
"package": "ObjectiveGit",
"repositoryURL": "https://github.com/SimplyDanny/objective-git-swift-package",
"state": {
- "branch": "0.16-passforios",
- "revision": "01c4fe0c410f51484119c087f9bb4a6d3837543b",
+ "branch": "0.17-passforios",
+ "revision": "553f09c836b4f90e447e0fe26633acc11c37cece",
"version": null
}
},
From 90f1f54a21fe3f6d04d8e06682b52a5d549b7d99 Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Sun, 22 May 2022 16:26:00 -0700
Subject: [PATCH 007/103] Fix building issue
---
Cartfile | 2 +-
Cartfile.resolved | 2 +-
README.md | 2 +-
fastlane/Fastfile | 1 +
pass.xcodeproj/project.pbxproj | 4 +-
.../xcshareddata/swiftpm/Package.resolved | 149 +++++++++---------
passKit/Helpers/DefaultsKeys.swift | 68 ++++++++
scripts/gopenpgp_build.sh | 16 +-
8 files changed, 158 insertions(+), 86 deletions(-)
diff --git a/Cartfile b/Cartfile
index 6a338049..93393ac2 100644
--- a/Cartfile
+++ b/Cartfile
@@ -1 +1 @@
-github "SVProgressHUD/SVProgressHUD"
+github "SVProgressHUD/SVProgressHUD" "master"
diff --git a/Cartfile.resolved b/Cartfile.resolved
index b60baa2c..46eb4064 100644
--- a/Cartfile.resolved
+++ b/Cartfile.resolved
@@ -1 +1 @@
-github "SVProgressHUD/SVProgressHUD" "2.2.5"
+github "SVProgressHUD/SVProgressHUD" "de1d4dba816a19454329031156b8788692bcfa2c"
diff --git a/README.md b/README.md
index 9af54373..ce94bd10 100644
--- a/README.md
+++ b/README.md
@@ -47,7 +47,7 @@ For more, please read the [wiki page](https://github.com/mssun/passforios/wiki).
## Building Pass for iOS
1. Install Carthage, Go, SwiftLint, and SwiftFormat: `brew install carthage go swiftlint swiftformat`.
-2. Install dependencies via Carthage. Therefore, execute `carthage update` and `carthage bootstrap --platform iOS --use-xcframeworks` in the root directory of the project.
+2. Install dependencies via Carthage. Therefore, execute `carthage bootstrap --platform iOS --use-xcframeworks` in the root directory of the project.
3. Run `./scripts/gopenpgp_build.sh` to build GopenPGP.
5. Open the `pass.xcodeproj` file in Xcode.
6. Build & Run.
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
index 06fdcbbb..2ebe5273 100644
--- a/fastlane/Fastfile
+++ b/fastlane/Fastfile
@@ -94,6 +94,7 @@ platform :ios do
scheme: "pass",
configuration: "Beta",
skip_profile_detection: true,
+ export_method: "app-store",
export_options: {
method: "app-store",
provisioningProfiles: {
diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj
index 87a00b6a..c663c283 100644
--- a/pass.xcodeproj/project.pbxproj
+++ b/pass.xcodeproj/project.pbxproj
@@ -1116,9 +1116,9 @@
isa = PBXNativeTarget;
buildConfigurationList = A260758F1EEC6F34005DB03E /* Build configuration list for PBXNativeTarget "passKit" */;
buildPhases = (
+ A26075751EEC6F34005DB03E /* Headers */,
A26075731EEC6F34005DB03E /* Sources */,
A26075741EEC6F34005DB03E /* Frameworks */,
- A26075751EEC6F34005DB03E /* Headers */,
A26075761EEC6F34005DB03E /* Resources */,
);
buildRules = (
@@ -2811,7 +2811,7 @@
repositoryURL = "https://github.com/krzyzanowskim/ObjectivePGP";
requirement = {
kind = upToNextMajorVersion;
- minimumVersion = 0.99.0;
+ minimumVersion = 0.99.2;
};
};
30A3000C26DA62F4002A734E /* XCRemoteSwiftPackageReference "Base32" */ = {
diff --git a/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index b3dc414f..f3e4dfa3 100644
--- a/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -1,79 +1,76 @@
{
- "object": {
- "pins": [
- {
- "package": "Base32",
- "repositoryURL": "https://github.com/mattrubin/Base32",
- "state": {
- "branch": "1.1.2+spm",
- "revision": "d185e44c8b355d34d5c6c6ad502c60cba4599f69",
- "version": null
- }
- },
- {
- "package": "FavIcon",
- "repositoryURL": "https://github.com/leonbreedt/FavIcon",
- "state": {
- "branch": null,
- "revision": "5bf16aad3ea543891eaef7e8da2aa2f6bb29e6e4",
- "version": "3.1.0"
- }
- },
- {
- "package": "KeychainAccess",
- "repositoryURL": "https://github.com/kishikawakatsumi/KeychainAccess",
- "state": {
- "branch": null,
- "revision": "84e546727d66f1adc5439debad16270d0fdd04e7",
- "version": "4.2.2"
- }
- },
- {
- "package": "ObjectiveGit",
- "repositoryURL": "https://github.com/SimplyDanny/objective-git-swift-package",
- "state": {
- "branch": "0.17-passforios",
- "revision": "553f09c836b4f90e447e0fe26633acc11c37cece",
- "version": null
- }
- },
- {
- "package": "ObjectivePGP",
- "repositoryURL": "https://github.com/krzyzanowskim/ObjectivePGP",
- "state": {
- "branch": null,
- "revision": "0dc7ca7ffe193095dc37456b0c75be167a2026f4",
- "version": "0.99.2"
- }
- },
- {
- "package": "OneTimePassword",
- "repositoryURL": "https://github.com/mssun/OneTimePassword",
- "state": {
- "branch": null,
- "revision": "8d59e4abba762d0f1e9aed161081f7b3fe21daa0",
- "version": null
- }
- },
- {
- "package": "SwiftyUserDefaults",
- "repositoryURL": "https://github.com/sunshinejr/SwiftyUserDefaults",
- "state": {
- "branch": null,
- "revision": "f66bcd04088582c8fbb5cb8554d577e303bae396",
- "version": "5.3.0"
- }
- },
- {
- "package": "YubiKit",
- "repositoryURL": "https://github.com/Yubico/yubikit-ios",
- "state": {
- "branch": null,
- "revision": "7e75fe8f057acf9bf7ac134d375783a1d409f79e",
- "version": "4.1.0"
- }
+ "pins" : [
+ {
+ "identity" : "base32",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/mattrubin/Base32",
+ "state" : {
+ "branch" : "1.1.2+spm",
+ "revision" : "d185e44c8b355d34d5c6c6ad502c60cba4599f69"
}
- ]
- },
- "version": 1
+ },
+ {
+ "identity" : "favicon",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/leonbreedt/FavIcon",
+ "state" : {
+ "revision" : "5bf16aad3ea543891eaef7e8da2aa2f6bb29e6e4",
+ "version" : "3.1.0"
+ }
+ },
+ {
+ "identity" : "keychainaccess",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/kishikawakatsumi/KeychainAccess",
+ "state" : {
+ "revision" : "84e546727d66f1adc5439debad16270d0fdd04e7",
+ "version" : "4.2.2"
+ }
+ },
+ {
+ "identity" : "objective-git-swift-package",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/SimplyDanny/objective-git-swift-package",
+ "state" : {
+ "branch" : "0.17-passforios",
+ "revision" : "553f09c836b4f90e447e0fe26633acc11c37cece"
+ }
+ },
+ {
+ "identity" : "objectivepgp",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/krzyzanowskim/ObjectivePGP",
+ "state" : {
+ "revision" : "0dc7ca7ffe193095dc37456b0c75be167a2026f4",
+ "version" : "0.99.2"
+ }
+ },
+ {
+ "identity" : "onetimepassword",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/mssun/OneTimePassword",
+ "state" : {
+ "revision" : "8d59e4abba762d0f1e9aed161081f7b3fe21daa0"
+ }
+ },
+ {
+ "identity" : "swiftyuserdefaults",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/sunshinejr/SwiftyUserDefaults",
+ "state" : {
+ "revision" : "f66bcd04088582c8fbb5cb8554d577e303bae396",
+ "version" : "5.3.0"
+ }
+ },
+ {
+ "identity" : "yubikit-ios",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/Yubico/yubikit-ios",
+ "state" : {
+ "revision" : "7b19be11a362d9e52eac0d76b5d904560b9e5ea7",
+ "version" : "4.2.0"
+ }
+ }
+ ],
+ "version" : 2
}
diff --git a/passKit/Helpers/DefaultsKeys.swift b/passKit/Helpers/DefaultsKeys.swift
index a96b2066..30594226 100644
--- a/passKit/Helpers/DefaultsKeys.swift
+++ b/passKit/Helpers/DefaultsKeys.swift
@@ -9,6 +9,74 @@
import Foundation
import SwiftyUserDefaults
+// Workaround for Xcode 13: https://github.com/sunshinejr/SwiftyUserDefaults/issues/285
+
+extension DefaultsSerializable {
+ public static var _defaultsArray: DefaultsArrayBridge<[T]> { return DefaultsArrayBridge() }
+}
+extension Date: DefaultsSerializable {
+ public static var _defaults: DefaultsObjectBridge { return DefaultsObjectBridge() }
+}
+extension String: DefaultsSerializable {
+ public static var _defaults: DefaultsStringBridge { return DefaultsStringBridge() }
+}
+extension Int: DefaultsSerializable {
+ public static var _defaults: DefaultsIntBridge { return DefaultsIntBridge() }
+}
+extension Double: DefaultsSerializable {
+ public static var _defaults: DefaultsDoubleBridge { return DefaultsDoubleBridge() }
+}
+extension Bool: DefaultsSerializable {
+ public static var _defaults: DefaultsBoolBridge { return DefaultsBoolBridge() }
+}
+extension Data: DefaultsSerializable {
+ public static var _defaults: DefaultsDataBridge { return DefaultsDataBridge() }
+}
+
+extension URL: DefaultsSerializable {
+ #if os(Linux)
+ public static var _defaults: DefaultsKeyedArchiverBridge { return DefaultsKeyedArchiverBridge() }
+ #else
+ public static var _defaults: DefaultsUrlBridge { return DefaultsUrlBridge() }
+ #endif
+ public static var _defaultsArray: DefaultsKeyedArchiverBridge<[URL]> { return DefaultsKeyedArchiverBridge() }
+}
+
+extension DefaultsSerializable where Self: Codable {
+ public static var _defaults: DefaultsCodableBridge { return DefaultsCodableBridge() }
+ public static var _defaultsArray: DefaultsCodableBridge<[Self]> { return DefaultsCodableBridge() }
+}
+
+extension DefaultsSerializable where Self: RawRepresentable {
+ public static var _defaults: DefaultsRawRepresentableBridge { return DefaultsRawRepresentableBridge() }
+ public static var _defaultsArray: DefaultsRawRepresentableArrayBridge<[Self]> { return DefaultsRawRepresentableArrayBridge() }
+}
+
+extension DefaultsSerializable where Self: NSCoding {
+ public static var _defaults: DefaultsKeyedArchiverBridge { return DefaultsKeyedArchiverBridge() }
+ public static var _defaultsArray: DefaultsKeyedArchiverBridge<[Self]> { return DefaultsKeyedArchiverBridge() }
+}
+
+extension Dictionary: DefaultsSerializable where Key == String {
+ public typealias T = [Key: Value]
+ public typealias Bridge = DefaultsObjectBridge
+ public typealias ArrayBridge = DefaultsArrayBridge<[T]>
+ public static var _defaults: Bridge { return Bridge() }
+ public static var _defaultsArray: ArrayBridge { return ArrayBridge() }
+}
+extension Array: DefaultsSerializable where Element: DefaultsSerializable {
+ public typealias T = [Element.T]
+ public typealias Bridge = Element.ArrayBridge
+ public typealias ArrayBridge = DefaultsObjectBridge<[T]>
+ public static var _defaults: Bridge {
+ return Element._defaultsArray
+ }
+ public static var _defaultsArray: ArrayBridge {
+ fatalError("Multidimensional arrays are not supported yet")
+ }
+}
+
+
public var Defaults = DefaultsAdapter(defaults: UserDefaults(suiteName: Globals.groupIdentifier)!, keyStore: DefaultsKeys())
public enum KeySource: String, DefaultsSerializable {
diff --git a/scripts/gopenpgp_build.sh b/scripts/gopenpgp_build.sh
index f1bac2a9..6e531195 100755
--- a/scripts/gopenpgp_build.sh
+++ b/scripts/gopenpgp_build.sh
@@ -14,15 +14,21 @@ GOPENPGP_PATH="$CHECKOUT_PATH/gopenpgp"
mkdir -p "$OUTPUT_PATH"
mkdir -p "$CHECKOUT_PATH"
-go env -w GO111MODULE=auto
-go get golang.org/x/mobile/cmd/gomobile
+go install golang.org/x/mobile/cmd/gomobile@latest
gomobile init
git clone --depth 1 --branch "$GOPENPGP_VERSION" https://github.com/mssun/gopenpgp.git "$GOPENPGP_PATH"
-sed -i '' 's/build android/echo "Skipping Android build."/g' "$GOPENPGP_PATH/build.sh"
-
-(cd "$GOPENPGP_PATH" && ./build.sh)
+pushd "$GOPENPGP_PATH"
+mkdir -p dist
+go mod download github.com/ProtonMail/go-crypto
+gomobile bind -tags mobile -target ios -iosversion 12.0 -v -x -ldflags="-s -w" -o dist/Gopenpgp.xcframework \
+ github.com/ProtonMail/gopenpgp/v2/crypto \
+ github.com/ProtonMail/gopenpgp/v2/armor \
+ github.com/ProtonMail/gopenpgp/v2/constants \
+ github.com/ProtonMail/gopenpgp/v2/models \
+ github.com/ProtonMail/gopenpgp/v2/subtle github.com/ProtonMail/gopenpgp/v2/helper
+popd
cp -r "$GOPENPGP_PATH/dist/Gopenpgp.xcframework" "$OUTPUT_PATH"
From 687b67a6a29982d1c37346cafd88a7a69990370c Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Sun, 22 May 2022 21:57:33 -0700
Subject: [PATCH 008/103] Fix GitHub Actions
---
.github/workflows/deploying.yml | 6 +++---
.github/workflows/linting.yml | 4 ++--
.github/workflows/testing.yml | 6 +++---
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/deploying.yml b/.github/workflows/deploying.yml
index 4134da1b..c4c0d363 100644
--- a/.github/workflows/deploying.yml
+++ b/.github/workflows/deploying.yml
@@ -7,7 +7,7 @@ on:
jobs:
build:
- runs-on: macos-11
+ runs-on: macos-12
strategy:
matrix:
channel: ['beta', 'release']
@@ -39,11 +39,11 @@ jobs:
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3
- name: Carthage
- if: steps.carthage-cache.outputs.cache-hit != 'true'
+ if: ${{ steps.carthage-cache.outputs.cache-hit == false }}
run: |
carthage bootstrap --no-use-binaries --cache-builds --use-xcframeworks
- name: GopenPGP
- if: steps.gopenpgp-cache.outputs.cache-hit != 'true'
+ if: ${{ steps.gopenpgp-cache.outputs.cache-hit == false }}
run: |
export PATH="/usr/local/opt/go/bin:$PATH"
./scripts/gopenpgp_build.sh
diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml
index 067ea35f..ffa853b3 100644
--- a/.github/workflows/linting.yml
+++ b/.github/workflows/linting.yml
@@ -4,7 +4,7 @@ on: pull_request
jobs:
swiftformat:
- runs-on: macos-latest
+ runs-on: macos-12
steps:
- uses: actions/checkout@v2
- name: Installing packages
@@ -20,7 +20,7 @@ jobs:
swiftformat --lint .
swiftlint:
- runs-on: macos-latest
+ runs-on: macos-12
steps:
- uses: actions/checkout@v2
- name: Installing packages
diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml
index 26f41237..dc518ca9 100644
--- a/.github/workflows/testing.yml
+++ b/.github/workflows/testing.yml
@@ -4,7 +4,7 @@ on: [push, pull_request]
jobs:
testing:
- runs-on: macos-11
+ runs-on: macos-12
steps:
- uses: actions/checkout@v2
- name: Installing packages
@@ -33,11 +33,11 @@ jobs:
bundle config path vendor/bundle
bundle install --jobs 4 --retry 3
- name: Carthage
- if: steps.carthage-cache.outputs.cache-hit != 'true'
+ if: ${{ steps.carthage-cache.outputs.cache-hit == false }}
run: |
carthage bootstrap --no-use-binaries --cache-builds --use-xcframeworks
- name: GopenPGP
- if: steps.gopenpgp-cache.outputs.cache-hit != 'true'
+ if: ${{ steps.gopenpgp-cache.outputs.cache-hit == false }}
run: ./scripts/gopenpgp_build.sh
- name: Testing
run: bundle exec fastlane test
From a0a08073bc98831075d7711a57e6a4d676847d14 Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Sun, 22 May 2022 22:03:39 -0700
Subject: [PATCH 009/103] Fix GitHub Actions
---
.github/workflows/deploying.yml | 4 ++++
.github/workflows/linting.yml | 8 ++++++++
.github/workflows/testing.yml | 4 ++++
3 files changed, 16 insertions(+)
diff --git a/.github/workflows/deploying.yml b/.github/workflows/deploying.yml
index c4c0d363..f24ae202 100644
--- a/.github/workflows/deploying.yml
+++ b/.github/workflows/deploying.yml
@@ -13,6 +13,10 @@ jobs:
channel: ['beta', 'release']
steps:
- uses: actions/checkout@v2
+ - uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: '2.7'
+ bundler-cache: true
- name: Installing packages
run: |
brew update
diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml
index ffa853b3..96031ca9 100644
--- a/.github/workflows/linting.yml
+++ b/.github/workflows/linting.yml
@@ -7,6 +7,10 @@ jobs:
runs-on: macos-12
steps:
- uses: actions/checkout@v2
+ - uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: '2.7'
+ bundler-cache: true
- name: Installing packages
run: |
brew update
@@ -23,6 +27,10 @@ jobs:
runs-on: macos-12
steps:
- uses: actions/checkout@v2
+ - uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: '2.7'
+ bundler-cache: true
- name: Installing packages
run: |
brew update
diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml
index dc518ca9..53366e60 100644
--- a/.github/workflows/testing.yml
+++ b/.github/workflows/testing.yml
@@ -7,6 +7,10 @@ jobs:
runs-on: macos-12
steps:
- uses: actions/checkout@v2
+ - uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: '2.7'
+ bundler-cache: true
- name: Installing packages
run: |
brew update
From e5d3b068969295f977856d5d6bf822b4a2b30a16 Mon Sep 17 00:00:00 2001
From: Tony Wang
Date: Mon, 23 May 2022 13:23:25 +0800
Subject: [PATCH 010/103] fix error when importing key using http (#556)
http url was not saved so it always failed
---
pass/Controllers/SSHKeyURLImportTableViewController..swift | 1 +
1 file changed, 1 insertion(+)
diff --git a/pass/Controllers/SSHKeyURLImportTableViewController..swift b/pass/Controllers/SSHKeyURLImportTableViewController..swift
index e3bf6c76..d1cc1088 100644
--- a/pass/Controllers/SSHKeyURLImportTableViewController..swift
+++ b/pass/Controllers/SSHKeyURLImportTableViewController..swift
@@ -32,6 +32,7 @@ class SSHKeyURLImportTableViewController: AutoCellHeightUITableViewController {
savePassphraseAlert.addAction(UIAlertAction(title: "No".localize(), style: .default) { _ in })
savePassphraseAlert.addAction(
UIAlertAction(title: "Yes".localize(), style: .destructive) { _ in
+ self.sshPrivateKeyURL = privateKeyURL
self.performSegue(withIdentifier: "importSSHKeySegue", sender: self)
}
)
From 6f5385fe4ac64bff6a3dd226f1d13eb397ea42f5 Mon Sep 17 00:00:00 2001
From: Bradley Walters
Date: Sun, 22 May 2022 23:35:53 -0600
Subject: [PATCH 011/103] Force weak linking of CryptoTokenKit (#543)
Apple's CryptoTokenKit is only present in iOS 13.0+ however it exports
symbols with availability annotations going back to iOS 10.0.
In the Pass app we have a deployment target of iOS 12.0. Apple's
automatic weak linking system apparently only looks at the
symbol-level availability annotations so it assumes the symbols
we use will always be present (even though they won't pre-iOS-13).
We can work around this issue by forcing weak linking using the
"Optional" framework setting. (Note that this workaround would not
work if CryptoTokenKit was used from a third-party swift package.)
This is necessary to restore iOS 12 support after #533.
For further history see https://github.com/mssun/passforios/issues/539
---
pass.xcodeproj/project.pbxproj | 8 ++++++++
pass/Services/PasswordDecryptor.swift | 19 ++++++++++++-------
2 files changed, 20 insertions(+), 7 deletions(-)
diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj
index c663c283..e07195c2 100644
--- a/pass.xcodeproj/project.pbxproj
+++ b/pass.xcodeproj/project.pbxproj
@@ -109,6 +109,9 @@
556EC3D922335D2800934F9C /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = 30BF5ED521ED2434000E4154 /* Localizable.stringsdict */; };
556EC3DA22335D3400934F9C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30C25DBF21F3599E00BB27BB /* InfoPlist.strings */; };
556EC3DB22335D3D00934F9C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30C25DBF21F3599E00BB27BB /* InfoPlist.strings */; };
+ 5F9D7B0D27AF6F7500A8AB22 /* CryptoTokenKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F9D7B0C27AF6F7300A8AB22 /* CryptoTokenKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ 5F9D7B0E27AF6FCA00A8AB22 /* CryptoTokenKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F9D7B0C27AF6F7300A8AB22 /* CryptoTokenKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+ 5F9D7B0F27AF6FD200A8AB22 /* CryptoTokenKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F9D7B0C27AF6F7300A8AB22 /* CryptoTokenKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
9A1D1CE526E5D1CE0052028E /* OneTimePassword in Frameworks */ = {isa = PBXBuildFile; productRef = 9A1D1CE426E5D1CE0052028E /* OneTimePassword */; };
9A1D1CE726E5D2230052028E /* OneTimePassword in Frameworks */ = {isa = PBXBuildFile; productRef = 9A1D1CE626E5D2230052028E /* OneTimePassword */; };
9A1F47FA26E5CF4B000C0E01 /* OneTimePassword in Frameworks */ = {isa = PBXBuildFile; productRef = 9A1F47F926E5CF4B000C0E01 /* OneTimePassword */; };
@@ -413,6 +416,7 @@
30EE3A1B241E98C6009FBB61 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Intents.strings; sourceTree = ""; };
30F6C1B327664C7200BE5AB2 /* SVProgressHUD.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = SVProgressHUD.xcframework; path = Carthage/Build/SVProgressHUD.xcframework; sourceTree = ""; };
30FD2F77214D9E0E005E0A92 /* ParserTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParserTest.swift; sourceTree = ""; };
+ 5F9D7B0C27AF6F7300A8AB22 /* CryptoTokenKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CryptoTokenKit.framework; path = System/Library/Frameworks/CryptoTokenKit.framework; sourceTree = SDKROOT; };
9A1EF0B324C50DD80074FEAC /* passBeta.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = passBeta.entitlements; sourceTree = ""; };
9A1EF0B424C50E780074FEAC /* passBetaAutoFillExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = passBetaAutoFillExtension.entitlements; sourceTree = ""; };
9A1EF0B524C50EE00074FEAC /* passBetaExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = passBetaExtension.entitlements; sourceTree = ""; };
@@ -519,6 +523,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 5F9D7B0E27AF6FCA00A8AB22 /* CryptoTokenKit.framework in Frameworks */,
9A5C6EF92786CE170003F340 /* YubiKit in Frameworks */,
9A996C6E26DEB99200A4485D /* passKit.framework in Frameworks */,
30A3001A26DA697C002A734E /* SwiftyUserDefaults in Frameworks */,
@@ -555,6 +560,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 5F9D7B0F27AF6FD200A8AB22 /* CryptoTokenKit.framework in Frameworks */,
9A5C6F022787F09A0003F340 /* passKit.framework in Frameworks */,
9A5C6EFB2786CE5E0003F340 /* YubiKit in Frameworks */,
9A5C6EFF2787F0980003F340 /* Gopenpgp.xcframework in Frameworks */,
@@ -573,6 +579,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 5F9D7B0D27AF6F7500A8AB22 /* CryptoTokenKit.framework in Frameworks */,
3010CB6026DA4F87008964D2 /* SwiftyUserDefaults in Frameworks */,
3010CB6326DA4FE9008964D2 /* FavIcon in Frameworks */,
9A1F47FA26E5CF4B000C0E01 /* OneTimePassword in Frameworks */,
@@ -772,6 +779,7 @@
9ADAB21926DDA4F600900F10 /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 5F9D7B0C27AF6F7300A8AB22 /* CryptoTokenKit.framework */,
30F6C1B327664C7200BE5AB2 /* SVProgressHUD.xcframework */,
9ADAB21C26DDA52400900F10 /* Gopenpgp.xcframework */,
);
diff --git a/pass/Services/PasswordDecryptor.swift b/pass/Services/PasswordDecryptor.swift
index 0b6d0679..0e0675a1 100644
--- a/pass/Services/PasswordDecryptor.swift
+++ b/pass/Services/PasswordDecryptor.swift
@@ -66,15 +66,20 @@ let symmetricKeyIDNameDict: [UInt8: String] = [
]
private func isEncryptKeyAlgoRSA(_ applicationRelatedData: Data) -> Bool {
- let tlv = TKBERTLVRecord.sequenceOfRecords(from: applicationRelatedData)!
- // 0x73: Discretionary data objects
- for record in TKBERTLVRecord.sequenceOfRecords(from: tlv.first!.value)! where record.tag == 0x73 {
- // 0xC2: Algorithm attributes decryption, 0x01: RSA
- for record2 in TKBERTLVRecord.sequenceOfRecords(from: record.value)! where record2.tag == 0xC2 && record2.value.first! == 0x01 {
- return true
+ if #available(iOS 13.0, *) {
+ let tlv = TKBERTLVRecord.sequenceOfRecords(from: applicationRelatedData)!
+ // 0x73: Discretionary data objects
+ for record in TKBERTLVRecord.sequenceOfRecords(from: tlv.first!.value)! where record.tag == 0x73 {
+ // 0xC2: Algorithm attributes decryption, 0x01: RSA
+ for record2 in TKBERTLVRecord.sequenceOfRecords(from: record.value)! where record2.tag == 0xC2 && record2.value.first! == 0x01 {
+ return true
+ }
}
+ return false
+ } else {
+ // We need CryptoTokenKit (iOS 13.0+) to check if data is RSA, so fail open here.
+ return true
}
- return false
}
// swiftlint:disable cyclomatic_complexity
From 440b0123f2a75d4276143c3dc23053994d49fa6e Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Mon, 23 May 2022 10:54:11 -0700
Subject: [PATCH 012/103] Fix building issues with XCode
---
pass.xcodeproj/project.pbxproj | 4 +-
.../PasswordDetailTableViewController.swift | 1 +
pass/Helpers/Objective-CBridgingHeader.h | 1 -
passKit/Helpers/DefaultsKeys.swift | 68 ++-----------------
passKit/Helpers/SearchBarScope.swift | 2 -
scripts/swiftformat.sh | 1 +
scripts/swiftlint.sh | 4 +-
7 files changed, 13 insertions(+), 68 deletions(-)
diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj
index e07195c2..d090c396 100644
--- a/pass.xcodeproj/project.pbxproj
+++ b/pass.xcodeproj/project.pbxproj
@@ -150,7 +150,6 @@
9A996C5726DDF65900A4485D /* Base32 in Frameworks */ = {isa = PBXBuildFile; productRef = 9A996C5626DDF65900A4485D /* Base32 */; };
9A996C5826DEB0D100A4485D /* passKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A26075781EEC6F34005DB03E /* passKit.framework */; };
9A996C5926DEB0D200A4485D /* passKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = A26075781EEC6F34005DB03E /* passKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
- 9A996C5E26DEB79E00A4485D /* passKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A26075781EEC6F34005DB03E /* passKit.framework */; };
9A996C6426DEB93F00A4485D /* passAutoFillExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = A239F5952158C08B00576CBF /* passAutoFillExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
9A996C6826DEB96B00A4485D /* passShortcuts.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 30A69945240EED5E00B7D967 /* passShortcuts.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
9A996C6B26DEB97600A4485D /* passExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = A26700241EEC466A00176B8A /* passExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
@@ -192,6 +191,7 @@
DC037CBC1E4DD47B00609409 /* TextFieldTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DC037CBA1E4DD47B00609409 /* TextFieldTableViewCell.xib */; };
DC037CBF1E4ED4E100609409 /* TextViewTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC037CBD1E4ED4E100609409 /* TextViewTableViewCell.swift */; };
DC037CC01E4ED4E100609409 /* TextViewTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DC037CBE1E4ED4E100609409 /* TextViewTableViewCell.xib */; };
+ DC0F7692283C00220042DA74 /* passKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A26075781EEC6F34005DB03E /* passKit.framework */; };
DC193FFA1E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC193FF91E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift */; };
DC3E64E61E656F11009A83DE /* CommitLogsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC3E64E51E656F11009A83DE /* CommitLogsTableViewController.swift */; };
DC4914961E434301007FF592 /* LabelTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC4914941E434301007FF592 /* LabelTableViewCell.swift */; };
@@ -514,7 +514,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 9A996C5E26DEB79E00A4485D /* passKit.framework in Frameworks */,
+ DC0F7692283C00220042DA74 /* passKit.framework in Frameworks */,
30A3001826DA6974002A734E /* SwiftyUserDefaults in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
diff --git a/pass/Controllers/PasswordDetailTableViewController.swift b/pass/Controllers/PasswordDetailTableViewController.swift
index e39b5c61..3e7ad0f8 100644
--- a/pass/Controllers/PasswordDetailTableViewController.swift
+++ b/pass/Controllers/PasswordDetailTableViewController.swift
@@ -12,6 +12,7 @@ import passAutoFillExtension
import passKit
import SVProgressHUD
import UIKit
+import YubiKit
class PasswordDetailTableViewController: UITableViewController, UIGestureRecognizerDelegate, AlertPresenting {
var passwordEntity: PasswordEntity?
diff --git a/pass/Helpers/Objective-CBridgingHeader.h b/pass/Helpers/Objective-CBridgingHeader.h
index 5a7c3e46..ff807e53 100644
--- a/pass/Helpers/Objective-CBridgingHeader.h
+++ b/pass/Helpers/Objective-CBridgingHeader.h
@@ -10,6 +10,5 @@
#define Objective_CBridgingHeader_h
@import ObjectiveGit;
-#import "YubiKit.h"
#endif /* Objective_CBridgingHeader_h */
diff --git a/passKit/Helpers/DefaultsKeys.swift b/passKit/Helpers/DefaultsKeys.swift
index 30594226..1f31d3d4 100644
--- a/passKit/Helpers/DefaultsKeys.swift
+++ b/passKit/Helpers/DefaultsKeys.swift
@@ -11,72 +11,16 @@ import SwiftyUserDefaults
// Workaround for Xcode 13: https://github.com/sunshinejr/SwiftyUserDefaults/issues/285
-extension DefaultsSerializable {
- public static var _defaultsArray: DefaultsArrayBridge<[T]> { return DefaultsArrayBridge() }
-}
-extension Date: DefaultsSerializable {
- public static var _defaults: DefaultsObjectBridge { return DefaultsObjectBridge() }
-}
-extension String: DefaultsSerializable {
- public static var _defaults: DefaultsStringBridge { return DefaultsStringBridge() }
-}
-extension Int: DefaultsSerializable {
- public static var _defaults: DefaultsIntBridge { return DefaultsIntBridge() }
-}
-extension Double: DefaultsSerializable {
- public static var _defaults: DefaultsDoubleBridge { return DefaultsDoubleBridge() }
-}
-extension Bool: DefaultsSerializable {
- public static var _defaults: DefaultsBoolBridge { return DefaultsBoolBridge() }
-}
-extension Data: DefaultsSerializable {
- public static var _defaults: DefaultsDataBridge { return DefaultsDataBridge() }
-}
-
-extension URL: DefaultsSerializable {
- #if os(Linux)
- public static var _defaults: DefaultsKeyedArchiverBridge { return DefaultsKeyedArchiverBridge() }
- #else
- public static var _defaults: DefaultsUrlBridge { return DefaultsUrlBridge() }
- #endif
- public static var _defaultsArray: DefaultsKeyedArchiverBridge<[URL]> { return DefaultsKeyedArchiverBridge() }
+public extension DefaultsSerializable where Self: Codable {
+ typealias Bridge = DefaultsCodableBridge
+ typealias ArrayBridge = DefaultsCodableBridge<[Self]>
}
-extension DefaultsSerializable where Self: Codable {
- public static var _defaults: DefaultsCodableBridge { return DefaultsCodableBridge() }
- public static var _defaultsArray: DefaultsCodableBridge<[Self]> { return DefaultsCodableBridge() }
+public extension DefaultsSerializable where Self: RawRepresentable {
+ typealias Bridge = DefaultsRawRepresentableBridge
+ typealias ArrayBridge = DefaultsRawRepresentableArrayBridge<[Self]>
}
-extension DefaultsSerializable where Self: RawRepresentable {
- public static var _defaults: DefaultsRawRepresentableBridge { return DefaultsRawRepresentableBridge() }
- public static var _defaultsArray: DefaultsRawRepresentableArrayBridge<[Self]> { return DefaultsRawRepresentableArrayBridge() }
-}
-
-extension DefaultsSerializable where Self: NSCoding {
- public static var _defaults: DefaultsKeyedArchiverBridge { return DefaultsKeyedArchiverBridge() }
- public static var _defaultsArray: DefaultsKeyedArchiverBridge<[Self]> { return DefaultsKeyedArchiverBridge() }
-}
-
-extension Dictionary: DefaultsSerializable where Key == String {
- public typealias T = [Key: Value]
- public typealias Bridge = DefaultsObjectBridge
- public typealias ArrayBridge = DefaultsArrayBridge<[T]>
- public static var _defaults: Bridge { return Bridge() }
- public static var _defaultsArray: ArrayBridge { return ArrayBridge() }
-}
-extension Array: DefaultsSerializable where Element: DefaultsSerializable {
- public typealias T = [Element.T]
- public typealias Bridge = Element.ArrayBridge
- public typealias ArrayBridge = DefaultsObjectBridge<[T]>
- public static var _defaults: Bridge {
- return Element._defaultsArray
- }
- public static var _defaultsArray: ArrayBridge {
- fatalError("Multidimensional arrays are not supported yet")
- }
-}
-
-
public var Defaults = DefaultsAdapter(defaults: UserDefaults(suiteName: Globals.groupIdentifier)!, keyStore: DefaultsKeys())
public enum KeySource: String, DefaultsSerializable {
diff --git a/passKit/Helpers/SearchBarScope.swift b/passKit/Helpers/SearchBarScope.swift
index b679f0f7..180e8666 100644
--- a/passKit/Helpers/SearchBarScope.swift
+++ b/passKit/Helpers/SearchBarScope.swift
@@ -6,8 +6,6 @@
// Copyright © 2019 Bob Sun. All rights reserved.
//
-import SwiftyUserDefaults
-
public enum SearchBarScope: Int {
case current
case all
diff --git a/scripts/swiftformat.sh b/scripts/swiftformat.sh
index 8c82e269..065354a6 100755
--- a/scripts/swiftformat.sh
+++ b/scripts/swiftformat.sh
@@ -1,3 +1,4 @@
+export PATH="/opt/homebrew/bin:/opt/homebrew/sbin${PATH+:$PATH}"
SWIFTFORMAT_VERSION="0.49.*"
if [[ "${CI}" == "true" ]]; then
diff --git a/scripts/swiftlint.sh b/scripts/swiftlint.sh
index 716aac5a..4ef7412b 100755
--- a/scripts/swiftlint.sh
+++ b/scripts/swiftlint.sh
@@ -1,4 +1,6 @@
-SWIFTLINT_VERSION="0.46.*"
+export PATH="/opt/homebrew/bin:/opt/homebrew/sbin${PATH+:$PATH}"
+
+SWIFTLINT_VERSION="0.47.*"
if [[ "${CI}" == "true" ]]; then
echo "Running in a Continuous Integration environment. Linting is skipped."
From 9b5b0eff1f02629305ac94ae6d693241aaf68f9e Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Mon, 23 May 2022 15:27:58 -0700
Subject: [PATCH 013/103] Exclude the vendor dir for swiftformat and swiftlint
(#562)
---
.swiftformat | 3 ++-
.swiftlint.yml | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/.swiftformat b/.swiftformat
index f3feea4b..11ffe6e7 100644
--- a/.swiftformat
+++ b/.swiftformat
@@ -5,7 +5,8 @@
--exclude \
Carthage, \
go, \
- Pods
+ Pods, \
+ vendor
## Enabled rules
diff --git a/.swiftlint.yml b/.swiftlint.yml
index 2abbdd2b..ede56bca 100644
--- a/.swiftlint.yml
+++ b/.swiftlint.yml
@@ -6,6 +6,7 @@ excluded:
- Carthage
- go
- Pods
+ - vendor
## Active rules
From 0f98569d54b99982bdfe0c92e145fe7f358b3d81 Mon Sep 17 00:00:00 2001
From: Bradley Walters
Date: Mon, 23 May 2022 16:28:09 -0600
Subject: [PATCH 014/103] Update ObjectiveGit to 0.18-passforios (#561)
This should resolve an incompatibility with older iOS versions.
---
pass.xcodeproj/project.pbxproj | 2 +-
.../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj
index d090c396..db16c080 100644
--- a/pass.xcodeproj/project.pbxproj
+++ b/pass.xcodeproj/project.pbxproj
@@ -2834,7 +2834,7 @@
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/SimplyDanny/objective-git-swift-package";
requirement = {
- branch = "0.17-passforios";
+ branch = "0.18-passforios";
kind = branch;
};
};
diff --git a/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
index f3e4dfa3..e5fc5559 100644
--- a/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
+++ b/pass.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
@@ -32,8 +32,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/SimplyDanny/objective-git-swift-package",
"state" : {
- "branch" : "0.17-passforios",
- "revision" : "553f09c836b4f90e447e0fe26633acc11c37cece"
+ "branch" : "0.18-passforios",
+ "revision" : "752ea5689a1c0c0f9a8442df039e842a452cfcf0"
}
},
{
From 01f808b7786ca534e0dd117d64e5054b1e05fec0 Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Tue, 24 May 2022 18:05:51 -0700
Subject: [PATCH 015/103] Add footnote of using TestFlight for iOS 12 users.
---
README.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index ce94bd10..f3adfa4d 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,9 @@ Pass for iOS is available in App Store with the name "Pass - Password Store", an
-You can also help us test beta versions through [TestFlight](https://testflight.apple.com/join/whK4zUFG).
+You can also help us test beta versions through [TestFlight](https://testflight.apple.com/join/whK4zUFG) [^1].
+
+[^1]: For iOS 12 users, you can download the TestFlight app by first "purchasing it" on a Mac using your Apple ID, then going to the purchased section of the App Store on your iOS device and downloading it from there.
## Features
From 972cf20d34e9aeb1c7ac6b08415f7c082e3c70f7 Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Tue, 31 May 2022 10:33:54 -0700
Subject: [PATCH 016/103] Fix umbrella header warnings (#563)
---
pass.xcodeproj/project.pbxproj | 2 ++
1 file changed, 2 insertions(+)
diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj
index db16c080..1cef924e 100644
--- a/pass.xcodeproj/project.pbxproj
+++ b/pass.xcodeproj/project.pbxproj
@@ -206,6 +206,7 @@
DCA0499A1E335CC800522E8F /* GitRepositorySettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCA049991E335CC800522E8F /* GitRepositorySettingsTableViewController.swift */; };
DCA0499C1E3362F400522E8F /* PGPKeyURLImportTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCA0499B1E3362F400522E8F /* PGPKeyURLImportTableViewController.swift */; };
DCAAF7451E2FA66800AB94BC /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCAAF7441E2FA66800AB94BC /* SettingsTableViewController.swift */; };
+ DCB0EC272846857E00EFEE10 /* Objective-CBridgingHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = A2BC54C71EEE5669001FAFBD /* Objective-CBridgingHeader.h */; };
DCC441521E8F6C06008A90C4 /* RawPasswordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC441511E8F6C06008A90C4 /* RawPasswordViewController.swift */; };
DCC441541E916382008A90C4 /* SSHKeyArmorImportTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC441531E916382008A90C4 /* SSHKeyArmorImportTableViewController.swift */; };
DCD3C65E1EFB9BB400CBE842 /* SettingsSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCD3C65D1EFB9BB400CBE842 /* SettingsSplitViewController.swift */; };
@@ -1072,6 +1073,7 @@
buildActionMask = 2147483647;
files = (
A260758A1EEC6F34005DB03E /* passKit.h in Headers */,
+ DCB0EC272846857E00EFEE10 /* Objective-CBridgingHeader.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
From 4da22b0a80fc7ec84098d067f25128cba386ef20 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 7 Jun 2022 18:59:51 -0700
Subject: [PATCH 017/103] Bump jmespath from 1.4.0 to 1.6.1 (#564)
Bumps [jmespath](https://github.com/trevorrowe/jmespath.rb) from 1.4.0 to 1.6.1.
- [Release notes](https://github.com/trevorrowe/jmespath.rb/releases)
- [Changelog](https://github.com/jmespath/jmespath.rb/blob/main/CHANGELOG.md)
- [Commits](https://github.com/trevorrowe/jmespath.rb/compare/v1.4.0...v1.6.1)
---
updated-dependencies:
- dependency-name: jmespath
dependency-type: indirect
...
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
Gemfile.lock | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Gemfile.lock b/Gemfile.lock
index 26cba895..de4e4d59 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -114,7 +114,7 @@ GEM
http-cookie (1.0.3)
domain_name (~> 0.5)
httpclient (2.8.3)
- jmespath (1.4.0)
+ jmespath (1.6.1)
json (2.3.1)
jwt (2.2.1)
memoist (0.16.2)
From ad105b3df1b76b7a7c7b24d5cd1403ea98a3d5bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?=
Date: Thu, 16 Jun 2022 04:55:02 +0200
Subject: [PATCH 018/103] Enable some more SwitfLint rules (#565)
---
.swiftlint.yml | 5 +++++
pass/Controllers/PasswordDetailTableViewController.swift | 3 ++-
pass/Controllers/QRScannerController.swift | 9 ++++++---
.../SSHKeyURLImportTableViewController..swift | 3 ++-
4 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/.swiftlint.yml b/.swiftlint.yml
index ede56bca..61d2a402 100644
--- a/.swiftlint.yml
+++ b/.swiftlint.yml
@@ -11,6 +11,7 @@ excluded:
## Active rules
only_rules:
+ - accessibility_label_for_image
# - anonymous_argument_in_multiline_closure
- anyobject_protocol
- array_init
@@ -27,6 +28,7 @@ only_rules:
- collection_alignment
- colon
- comma
+ - comma_inheritance
- comment_spacing
- compiler_protocol_init
- computed_accessors_order
@@ -141,6 +143,7 @@ only_rules:
- override_in_extension
- pattern_matching_keywords
# - prefer_nimble
+ - prefer_self_in_static_references
- prefer_self_type_over_type_of_self
- prefer_zero_over_explicit_init
# - prefixed_toplevel_constant # Violations are mostly in test code.
@@ -169,6 +172,7 @@ only_rules:
# - required_deinit
- required_enum_case
- return_arrow_whitespace
+ - return_value_from_void_function
- self_in_property_initialization
- shorthand_operator
- single_test_class
@@ -193,6 +197,7 @@ only_rules:
# - type_body_length
# - type_contents_order
- type_name
+ - unavailable_condition
- unavailable_function
- unneeded_break_in_switch
- unneeded_parentheses_in_closure_argument
diff --git a/pass/Controllers/PasswordDetailTableViewController.swift b/pass/Controllers/PasswordDetailTableViewController.swift
index 3e7ad0f8..90fdf8a3 100644
--- a/pass/Controllers/PasswordDetailTableViewController.swift
+++ b/pass/Controllers/PasswordDetailTableViewController.swift
@@ -386,9 +386,10 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
func openLink(to address: String?) {
guard address != nil, let url = URL(string: formActualWebAddress(from: address!)) else {
- return DispatchQueue.main.async {
+ DispatchQueue.main.async {
Utils.alert(title: "Error".localize(), message: "CannotFindValidUrl".localize(), controller: self, completion: nil)
}
+ return
}
SecurePasteboard.shared.copy(textToCopy: password?.password)
UIApplication.shared.open(url, options: [:], completionHandler: nil)
diff --git a/pass/Controllers/QRScannerController.swift b/pass/Controllers/QRScannerController.swift
index 9e0f05e4..4693d663 100644
--- a/pass/Controllers/QRScannerController.swift
+++ b/pass/Controllers/QRScannerController.swift
@@ -90,13 +90,16 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg
func metadataOutput(_: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from _: AVCaptureConnection) {
guard let metadataObj = metadataObjects.first as? AVMetadataMachineReadableCodeObject else {
- return setNotDetected()
+ setNotDetected()
+ return
}
guard supportedCodeTypes.contains(metadataObj.type) else {
- return setNotDetected()
+ setNotDetected()
+ return
}
guard let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj) else {
- return setNotDetected()
+ setNotDetected()
+ return
}
// draw a bounds on the found QR code
diff --git a/pass/Controllers/SSHKeyURLImportTableViewController..swift b/pass/Controllers/SSHKeyURLImportTableViewController..swift
index d1cc1088..f219f64d 100644
--- a/pass/Controllers/SSHKeyURLImportTableViewController..swift
+++ b/pass/Controllers/SSHKeyURLImportTableViewController..swift
@@ -36,7 +36,8 @@ class SSHKeyURLImportTableViewController: AutoCellHeightUITableViewController {
self.performSegue(withIdentifier: "importSSHKeySegue", sender: self)
}
)
- return present(savePassphraseAlert, animated: true)
+ present(savePassphraseAlert, animated: true)
+ return
}
sshPrivateKeyURL = privateKeyURL
performSegue(withIdentifier: "importSSHKeySegue", sender: self)
From a6b05d20e058221fdd1b6db7d489c73c91611b05 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?=
Date: Sat, 30 Jul 2022 20:20:08 +0200
Subject: [PATCH 019/103] Store password repository details only if we are sure
to clone/overwrite it (#571)
---
...itRepositorySettingsTableViewController.swift | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/pass/Controllers/GitRepositorySettingsTableViewController.swift b/pass/Controllers/GitRepositorySettingsTableViewController.swift
index f50e9112..e37c7c48 100644
--- a/pass/Controllers/GitRepositorySettingsTableViewController.swift
+++ b/pass/Controllers/GitRepositorySettingsTableViewController.swift
@@ -122,7 +122,7 @@ class GitRepositorySettingsTableViewController: UITableViewController, PasswordA
return
}
- guard let branchName = branchNameTextField.text, !branchName.trimmed.isEmpty else {
+ guard let branchName = branchNameTextField.text?.trimmed, !branchName.isEmpty else {
Utils.alert(title: "CannotSave".localize(), message: "SpecifyBranchName.".localize(), controller: self)
return
}
@@ -146,16 +146,14 @@ class GitRepositorySettingsTableViewController: UITableViewController, PasswordA
}
}
- self.gitURL = gitURL
- gitBranchName = branchName.trimmed
- gitUsername = (gitURL.user ?? usernameTextField.text ?? "git").trimmed
+ let username = (gitURL.user ?? usernameTextField.text ?? "git").trimmed
if passwordStore.repositoryExists() {
let overwriteAlert: UIAlertController = {
let alert = UIAlertController(title: "Overwrite?".localize(), message: "OperationWillOverwriteData.".localize(), preferredStyle: .alert)
alert.addAction(
UIAlertAction(title: "Overwrite".localize(), style: .destructive) { _ in
- self.cloneAndSegueIfSuccess()
+ self.cloneAndSegueIfSuccess(url: gitURL, branch: branchName, username: username)
}
)
alert.addAction(UIAlertAction.cancel())
@@ -163,11 +161,15 @@ class GitRepositorySettingsTableViewController: UITableViewController, PasswordA
}()
present(overwriteAlert, animated: true)
} else {
- cloneAndSegueIfSuccess()
+ cloneAndSegueIfSuccess(url: gitURL, branch: branchName, username: username)
}
}
- private func cloneAndSegueIfSuccess() {
+ private func cloneAndSegueIfSuccess(url: URL, branch: String, username: String) {
+ gitURL = url
+ gitBranchName = branch
+ gitUsername = username
+
// Remember git credential password/passphrase temporarily, ask whether users want this after a successful clone.
Defaults.isRememberGitCredentialPassphraseOn = true
DispatchQueue.global(qos: .userInitiated).async {
From 5c62d4a3e33ec912bb700b9578730b15bb61800f Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Sat, 30 Jul 2022 11:46:40 -0700
Subject: [PATCH 020/103] Update gem dependencies
---
Gemfile.lock | 194 +++++++++++++++++++++++++++++++--------------------
1 file changed, 117 insertions(+), 77 deletions(-)
diff --git a/Gemfile.lock b/Gemfile.lock
index de4e4d59..294cd73f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,57 +1,80 @@
GEM
remote: https://rubygems.org/
specs:
- CFPropertyList (3.0.2)
+ CFPropertyList (3.0.5)
+ rexml
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
+ artifactory (3.0.15)
atomos (0.1.3)
- aws-eventstream (1.1.0)
- aws-partitions (1.345.0)
- aws-sdk-core (3.104.3)
+ aws-eventstream (1.2.0)
+ aws-partitions (1.613.0)
+ aws-sdk-core (3.131.5)
aws-eventstream (~> 1, >= 1.0.2)
- aws-partitions (~> 1, >= 1.239.0)
+ aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
- jmespath (~> 1.0)
- aws-sdk-kms (1.36.0)
- aws-sdk-core (~> 3, >= 3.99.0)
+ jmespath (~> 1, >= 1.6.1)
+ aws-sdk-kms (1.58.0)
+ aws-sdk-core (~> 3, >= 3.127.0)
aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.75.0)
- aws-sdk-core (~> 3, >= 3.104.1)
+ aws-sdk-s3 (1.114.0)
+ aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-kms (~> 1)
- aws-sigv4 (~> 1.1)
- aws-sigv4 (1.2.1)
+ aws-sigv4 (~> 1.4)
+ aws-sigv4 (1.5.1)
aws-eventstream (~> 1, >= 1.0.2)
- babosa (1.0.3)
- claide (1.0.3)
+ babosa (1.0.4)
+ claide (1.1.0)
colored (1.2)
colored2 (3.1.2)
- commander-fastlane (4.4.6)
- highline (~> 1.7.2)
+ commander (4.6.0)
+ highline (~> 2.0.0)
declarative (0.0.20)
- declarative-option (0.1.0)
- digest-crc (0.6.1)
- rake (~> 13.0)
+ digest-crc (0.6.4)
+ rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
- dotenv (2.7.6)
- emoji_regex (3.0.0)
- excon (0.75.0)
- faraday (1.0.1)
- multipart-post (>= 1.2, < 3)
- faraday-cookie_jar (0.0.6)
- faraday (>= 0.7.4)
+ dotenv (2.8.1)
+ emoji_regex (3.2.3)
+ excon (0.92.4)
+ faraday (1.10.0)
+ faraday-em_http (~> 1.0)
+ faraday-em_synchrony (~> 1.0)
+ faraday-excon (~> 1.1)
+ faraday-httpclient (~> 1.0)
+ faraday-multipart (~> 1.0)
+ faraday-net_http (~> 1.0)
+ faraday-net_http_persistent (~> 1.0)
+ faraday-patron (~> 1.0)
+ faraday-rack (~> 1.0)
+ faraday-retry (~> 1.0)
+ ruby2_keywords (>= 0.0.4)
+ faraday-cookie_jar (0.0.7)
+ faraday (>= 0.8.0)
http-cookie (~> 1.0.0)
- faraday_middleware (1.0.0)
+ faraday-em_http (1.0.0)
+ faraday-em_synchrony (1.0.0)
+ faraday-excon (1.1.0)
+ faraday-httpclient (1.0.1)
+ faraday-multipart (1.0.4)
+ multipart-post (~> 2)
+ faraday-net_http (1.0.1)
+ faraday-net_http_persistent (1.2.0)
+ faraday-patron (1.0.0)
+ faraday-rack (1.0.0)
+ faraday-retry (1.0.3)
+ faraday_middleware (1.2.0)
faraday (~> 1.0)
- fastimage (2.2.0)
- fastlane (2.153.1)
+ fastimage (2.2.6)
+ fastlane (2.208.0)
CFPropertyList (>= 2.3, < 4.0.0)
- addressable (>= 2.3, < 3.0.0)
+ addressable (>= 2.8, < 3.0.0)
+ artifactory (~> 3.0)
aws-sdk-s3 (~> 1.0)
babosa (>= 1.0.3, < 2.0.0)
bundler (>= 1.12.0, < 3.0.0)
colored
- commander-fastlane (>= 4.4.6, < 5.0.0)
+ commander (~> 4.6)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 4.0)
excon (>= 0.71.0, < 1.0.0)
@@ -60,18 +83,20 @@ GEM
faraday_middleware (~> 1.0)
fastimage (>= 2.1.0, < 3.0.0)
gh_inspector (>= 1.1.2, < 2.0.0)
- google-api-client (>= 0.37.0, < 0.39.0)
- google-cloud-storage (>= 1.15.0, < 2.0.0)
- highline (>= 1.7.2, < 2.0.0)
+ google-apis-androidpublisher_v3 (~> 0.3)
+ google-apis-playcustomapp_v1 (~> 0.1)
+ google-cloud-storage (~> 1.31)
+ highline (~> 2.0)
json (< 3.0.0)
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
multipart-post (~> 2.0.0)
+ naturally (~> 2.2)
+ optparse (~> 0.1.1)
plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0)
security (= 0.1.3)
simctl (~> 1.6.3)
- slack-notifier (>= 2.0.0, < 3.0.0)
terminal-notifier (>= 2.0.0, < 3.0.0)
terminal-table (>= 1.4.5, < 2.0.0)
tty-screen (>= 0.6.3, < 1.0.0)
@@ -81,60 +106,71 @@ GEM
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
gh_inspector (1.1.3)
- google-api-client (0.38.0)
+ google-apis-androidpublisher_v3 (0.25.0)
+ google-apis-core (>= 0.7, < 2.a)
+ google-apis-core (0.7.0)
addressable (~> 2.5, >= 2.5.1)
- googleauth (~> 0.9)
- httpclient (>= 2.8.1, < 3.0)
+ googleauth (>= 0.16.2, < 2.a)
+ httpclient (>= 2.8.1, < 3.a)
mini_mime (~> 1.0)
representable (~> 3.0)
- retriable (>= 2.0, < 4.0)
- signet (~> 0.12)
- google-cloud-core (1.5.0)
+ retriable (>= 2.0, < 4.a)
+ rexml
+ webrick
+ google-apis-iamcredentials_v1 (0.13.0)
+ google-apis-core (>= 0.7, < 2.a)
+ google-apis-playcustomapp_v1 (0.10.0)
+ google-apis-core (>= 0.7, < 2.a)
+ google-apis-storage_v1 (0.18.0)
+ google-apis-core (>= 0.7, < 2.a)
+ google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
- google-cloud-env (1.3.3)
- faraday (>= 0.17.3, < 2.0)
- google-cloud-errors (1.0.1)
- google-cloud-storage (1.26.2)
- addressable (~> 2.5)
+ google-cloud-env (1.6.0)
+ faraday (>= 0.17.3, < 3.0)
+ google-cloud-errors (1.2.0)
+ google-cloud-storage (1.37.0)
+ addressable (~> 2.8)
digest-crc (~> 0.4)
- google-api-client (~> 0.33)
- google-cloud-core (~> 1.2)
- googleauth (~> 0.9)
+ google-apis-iamcredentials_v1 (~> 0.1)
+ google-apis-storage_v1 (~> 0.1)
+ google-cloud-core (~> 1.6)
+ googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
- googleauth (0.13.0)
- faraday (>= 0.17.3, < 2.0)
+ googleauth (1.2.0)
+ faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
- signet (~> 0.14)
- highline (1.7.10)
+ signet (>= 0.16, < 2.a)
+ highline (2.0.3)
http-accept (1.7.0)
- http-cookie (1.0.3)
+ http-cookie (1.0.5)
domain_name (~> 0.5)
httpclient (2.8.3)
jmespath (1.6.1)
- json (2.3.1)
- jwt (2.2.1)
+ json (2.6.2)
+ jwt (2.4.1)
memoist (0.16.2)
- mime-types (3.3.1)
+ mime-types (3.4.1)
mime-types-data (~> 3.2015)
- mime-types-data (3.2020.0512)
- mini_magick (4.10.1)
- mini_mime (1.0.2)
+ mime-types-data (3.2022.0105)
+ mini_magick (4.11.0)
+ mini_mime (1.1.2)
multi_json (1.15.0)
multipart-post (2.0.0)
nanaimo (0.3.0)
- naturally (2.2.0)
+ naturally (2.2.1)
netrc (0.11.0)
- os (1.1.0)
- plist (3.5.0)
- public_suffix (4.0.6)
- rake (13.0.1)
- representable (3.0.4)
+ optparse (0.1.1)
+ os (1.1.4)
+ plist (3.6.0)
+ public_suffix (4.0.7)
+ rake (13.0.6)
+ representable (3.2.0)
declarative (< 0.1.0)
- declarative-option (< 0.2.0)
+ trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0)
@@ -142,21 +178,23 @@ GEM
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
retriable (3.1.2)
+ rexml (3.2.5)
rouge (2.0.7)
- rubyzip (2.3.0)
+ ruby2_keywords (0.0.5)
+ rubyzip (2.3.2)
security (0.1.3)
- signet (0.14.0)
- addressable (~> 2.3)
- faraday (>= 0.17.3, < 2.0)
+ signet (0.17.0)
+ addressable (~> 2.8)
+ faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simctl (1.6.8)
CFPropertyList
naturally
- slack-notifier (2.3.2)
terminal-notifier (2.0.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
+ trailblazer-option (0.1.2)
tty-cursor (0.7.1)
tty-screen (0.8.1)
tty-spinner (0.9.3)
@@ -164,18 +202,20 @@ GEM
uber (0.1.0)
unf (0.1.4)
unf_ext
- unf_ext (0.0.7.7)
- unicode-display_width (1.7.0)
+ unf_ext (0.0.8.2)
+ unicode-display_width (1.8.0)
+ webrick (1.7.0)
word_wrap (1.0.0)
- xcodeproj (1.17.1)
+ xcodeproj (1.22.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.3.0)
+ rexml (~> 3.2.4)
xcpretty (0.3.0)
rouge (~> 2.0.7)
- xcpretty-travis-formatter (1.0.0)
+ xcpretty-travis-formatter (1.0.1)
xcpretty (~> 0.2, >= 0.0.7)
PLATFORMS
@@ -187,4 +227,4 @@ DEPENDENCIES
xcodeproj
BUNDLED WITH
- 2.2.25
+ 2.3.19
From b6be91301722024bdfe76a598003550d0e3ab700 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?=
Date: Tue, 1 Nov 2022 04:29:42 +0100
Subject: [PATCH 021/103] Update SwiftFormat to version 0.50.x (#577)
---
.swiftformat | 9 +++++++++
scripts/swiftformat.sh | 2 +-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/.swiftformat b/.swiftformat
index 11ffe6e7..8d02852b 100644
--- a/.swiftformat
+++ b/.swiftformat
@@ -15,6 +15,7 @@
andOperator, \
anyObjectProtocol, \
assertionFailures, \
+ blankLineAfterImports, \
blankLinesAroundMark, \
blankLinesAtEndOfScope, \
blankLinesAtStartOfScope, \
@@ -30,6 +31,7 @@
enumNamespaces, \
extensionAccessControl, \
fileHeader, \
+# genericExtensions, \
hoistPatternLet, \
indent, \
initCoderUnavailable, \
@@ -40,6 +42,7 @@
modifierOrder, \
# markTypes, \
numberFormatting, \
+# opaqueGenericParameters, \
# organizeDeclarations, \
preferDouble, \
preferKeyPath, \
@@ -54,6 +57,7 @@
redundantLetError, \
redundantNilInit, \
redundantObjc, \
+# redundantOptionalBinding, \
redundantParens, \
redundantPattern, \
redundantRawValues, \
@@ -91,6 +95,7 @@
wrapConditionalBodies, \
# wrapEnumCases, \
# wrapMultilineStatementBraces, \
+ wrapSingleLineComments, \
# wrapSwitchCases, \
yodaConditions
@@ -132,6 +137,10 @@
--emptybraces no-space
+### Enum namespaces: "always" (default) or "structs-only"
+
+--enumnamespaces always
+
### Case of 'e' in numbers: "lowercase" or "uppercase" (default)
--exponentcase lowercase
diff --git a/scripts/swiftformat.sh b/scripts/swiftformat.sh
index 065354a6..021720bf 100755
--- a/scripts/swiftformat.sh
+++ b/scripts/swiftformat.sh
@@ -1,5 +1,5 @@
export PATH="/opt/homebrew/bin:/opt/homebrew/sbin${PATH+:$PATH}"
-SWIFTFORMAT_VERSION="0.49.*"
+SWIFTFORMAT_VERSION="0.50.*"
if [[ "${CI}" == "true" ]]; then
echo "Running in a Continuous Integration environment. Formatting is skipped."
From 1307dc77c5a32fbf69ead5499c63cb4dba28cae3 Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Mon, 31 Oct 2022 21:31:35 -0700
Subject: [PATCH 022/103] Fix CI building issue
---
Gemfile.lock | 58 ++++++++++++++++++++++++++--------------------------
1 file changed, 29 insertions(+), 29 deletions(-)
diff --git a/Gemfile.lock b/Gemfile.lock
index 294cd73f..0f3009fb 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -3,25 +3,25 @@ GEM
specs:
CFPropertyList (3.0.5)
rexml
- addressable (2.8.0)
- public_suffix (>= 2.0.2, < 5.0)
+ addressable (2.8.1)
+ public_suffix (>= 2.0.2, < 6.0)
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
- aws-partitions (1.613.0)
- aws-sdk-core (3.131.5)
+ aws-partitions (1.654.0)
+ aws-sdk-core (3.166.0)
aws-eventstream (~> 1, >= 1.0.2)
- aws-partitions (~> 1, >= 1.525.0)
- aws-sigv4 (~> 1.1)
+ aws-partitions (~> 1, >= 1.651.0)
+ aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
- aws-sdk-kms (1.58.0)
- aws-sdk-core (~> 3, >= 3.127.0)
+ aws-sdk-kms (1.59.0)
+ aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.114.0)
- aws-sdk-core (~> 3, >= 3.127.0)
+ aws-sdk-s3 (1.117.1)
+ aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
- aws-sigv4 (1.5.1)
+ aws-sigv4 (1.5.2)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.1.0)
@@ -36,8 +36,8 @@ GEM
unf (>= 0.0.5, < 1.0.0)
dotenv (2.8.1)
emoji_regex (3.2.3)
- excon (0.92.4)
- faraday (1.10.0)
+ excon (0.93.1)
+ faraday (1.10.2)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
@@ -66,7 +66,7 @@ GEM
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.6)
- fastlane (2.208.0)
+ fastlane (2.210.1)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
@@ -106,9 +106,9 @@ GEM
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
gh_inspector (1.1.3)
- google-apis-androidpublisher_v3 (0.25.0)
- google-apis-core (>= 0.7, < 2.a)
- google-apis-core (0.7.0)
+ google-apis-androidpublisher_v3 (0.30.0)
+ google-apis-core (>= 0.9.1, < 2.a)
+ google-apis-core (0.9.1)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@@ -117,27 +117,27 @@ GEM
retriable (>= 2.0, < 4.a)
rexml
webrick
- google-apis-iamcredentials_v1 (0.13.0)
- google-apis-core (>= 0.7, < 2.a)
- google-apis-playcustomapp_v1 (0.10.0)
- google-apis-core (>= 0.7, < 2.a)
- google-apis-storage_v1 (0.18.0)
- google-apis-core (>= 0.7, < 2.a)
+ google-apis-iamcredentials_v1 (0.16.0)
+ google-apis-core (>= 0.9.1, < 2.a)
+ google-apis-playcustomapp_v1 (0.12.0)
+ google-apis-core (>= 0.9.1, < 2.a)
+ google-apis-storage_v1 (0.19.0)
+ google-apis-core (>= 0.9.0, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
- google-cloud-errors (1.2.0)
- google-cloud-storage (1.37.0)
+ google-cloud-errors (1.3.0)
+ google-cloud-storage (1.43.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
- google-apis-storage_v1 (~> 0.1)
+ google-apis-storage_v1 (~> 0.19.0)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
- googleauth (1.2.0)
+ googleauth (1.3.0)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
@@ -151,7 +151,7 @@ GEM
httpclient (2.8.3)
jmespath (1.6.1)
json (2.6.2)
- jwt (2.4.1)
+ jwt (2.5.0)
memoist (0.16.2)
mime-types (3.4.1)
mime-types-data (~> 3.2015)
@@ -166,7 +166,7 @@ GEM
optparse (0.1.1)
os (1.1.4)
plist (3.6.0)
- public_suffix (4.0.7)
+ public_suffix (5.0.0)
rake (13.0.6)
representable (3.2.0)
declarative (< 0.1.0)
From 32fdea0206f29f1b790a02cb05dbfb1954bc24c2 Mon Sep 17 00:00:00 2001
From: Mike
Date: Mon, 31 Oct 2022 22:09:24 -0700
Subject: [PATCH 023/103] fix(extension) fires JS event upon editing input
fields (#575)
---
passExtension/passProcessor.js | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/passExtension/passProcessor.js b/passExtension/passProcessor.js
index 5f9c7461..56da5f74 100644
--- a/passExtension/passProcessor.js
+++ b/passExtension/passProcessor.js
@@ -1,5 +1,16 @@
var PassProcessor = function() {};
+/**
+ * Dispatches a synthetic event of a given type on a given element.
+ * @param {string} type the event type to dispatch
+ * @param {Element} el the element upon which to dispatch it
+ */
+var dispatchEvent = function(type, el) {
+ var evt = document.createEvent('Event');
+ evt.initEvent(type, true, true);
+ el.dispatchEvent(evt);
+};
+
PassProcessor.prototype = {
run: function(arguments) {
var url
@@ -19,6 +30,8 @@ finalize: function(arguments) {
if (passwordElement) {
passwordElement.setAttribute('value', arguments["password"])
passwordElement.value = arguments["password"]
+ dispatchEvent("input", passwordElement)
+ dispatchEvent("change", passwordElement)
}
}
@@ -27,6 +40,8 @@ finalize: function(arguments) {
if (usernameElement) {
usernameElement.setAttribute('value', arguments["username"])
usernameElement.value = arguments["username"]
+ dispatchEvent("input", usernameElement)
+ dispatchEvent("change", usernameElement)
}
}
}
From e2ba21587c37fd0bc354ede3f21254347995d0ec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Danny=20M=C3=B6sch?=
Date: Tue, 1 Nov 2022 19:47:26 +0100
Subject: [PATCH 024/103] Update SwiftLint to version 0.49.x (#576)
---
scripts/swiftlint.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/swiftlint.sh b/scripts/swiftlint.sh
index 4ef7412b..aefdf847 100755
--- a/scripts/swiftlint.sh
+++ b/scripts/swiftlint.sh
@@ -1,6 +1,6 @@
export PATH="/opt/homebrew/bin:/opt/homebrew/sbin${PATH+:$PATH}"
-SWIFTLINT_VERSION="0.47.*"
+SWIFTLINT_VERSION="0.49.*"
if [[ "${CI}" == "true" ]]; then
echo "Running in a Continuous Integration environment. Linting is skipped."
From 31c6541f9e66251a5384da25cc2a9458db6e65b1 Mon Sep 17 00:00:00 2001
From: Mattia Borda
Date: Mon, 12 Dec 2022 07:08:18 +0100
Subject: [PATCH 025/103] Add Italian translation (#589)
- Translate InfoPlist.strings, Intents.strings, and Localizable.stringsdict
- Translate Main.strings
- Translate Localizable.strings
---
pass/it.lproj/InfoPlist.strings | 10 +
pass/it.lproj/Intents.strings | 30 +++
pass/it.lproj/Localizable.strings | 348 ++++++++++++++++++++++++++
pass/it.lproj/Localizable.stringsdict | 78 ++++++
pass/it.lproj/Main.strings | 261 +++++++++++++++++++
5 files changed, 727 insertions(+)
create mode 100644 pass/it.lproj/InfoPlist.strings
create mode 100644 pass/it.lproj/Intents.strings
create mode 100644 pass/it.lproj/Localizable.strings
create mode 100644 pass/it.lproj/Localizable.stringsdict
create mode 100644 pass/it.lproj/Main.strings
diff --git a/pass/it.lproj/InfoPlist.strings b/pass/it.lproj/InfoPlist.strings
new file mode 100644
index 00000000..7e575311
--- /dev/null
+++ b/pass/it.lproj/InfoPlist.strings
@@ -0,0 +1,10 @@
+/*
+ Localizable.strings
+ pass
+
+ Created by Danny Moesch on 19.01.19.
+ Copyright © 2019 Bob Sun. All rights reserved.
+ */
+
+"NSCameraUsageDescription" = "L'accesso alla fotocamera è richiesto per scansionare codici QR.";
+"NSFaceIDUsageDescription" = "Attiva l'accesso al Face ID per sbloccare Pass.";
diff --git a/pass/it.lproj/Intents.strings b/pass/it.lproj/Intents.strings
new file mode 100644
index 00000000..47657278
--- /dev/null
+++ b/pass/it.lproj/Intents.strings
@@ -0,0 +1,30 @@
+"0r0NKK" = "Impossibile eseguire il push dei cambiamenti al repository remoto.";
+
+"2jFDLY" = "Sincronizzazione del repository con il server.";
+
+"H2uxch" = "Nessuna password è salvata per comunicare al repository remoto.";
+
+"HO0DF8" = "Nessuna password è salvata per comunicare al repository remoto.";
+
+"IhvhFk" = "Sincronizzazione completata.";
+
+"JthclV" = "Nessun repository locale.";
+
+"KFGEkd" = "Sincronizza repository";
+
+"O9MV3m" = "La sincronizzazione è fallita.";
+
+"URQN5E" = "Sincronizzazione completata.";
+
+"k4AscG" = "Impossibile eseguire il pull dei cambiamenti dal repository remoto.";
+
+"kbRWJu" = "Impossibile eseguire il pull dei cambiamenti dal repository remoto.";
+
+"nuN5Fq" = "Sincronizza il repository.";
+
+"qr6SIW" = "Nessun repository locale.";
+
+"wB7FJn" = "La sincronizzazione è fallita.";
+
+"z8bZQR" = "Impossibile eseguire il push dei cambiamenti al repository remoto.";
+
diff --git a/pass/it.lproj/Localizable.strings b/pass/it.lproj/Localizable.strings
new file mode 100644
index 00000000..a1416656
--- /dev/null
+++ b/pass/it.lproj/Localizable.strings
@@ -0,0 +1,348 @@
+/*
+ Localizable.strings
+ pass
+
+ Created by Danny Moesch on 12.01.19.
+ Copyright © 2019 Bob Sun. All rights reserved.
+*/
+
+// General
+"PassForIos" = "Pass per iOS";
+"PasswordStore" = "Password Store";
+"Passphrase" = "Password";
+"Password" = "Password";
+"Passwords" = "Password";
+"Passcode" = "Codice";
+"Apple" = "Apple";
+"Settings" = "Impostazioni";
+"Contributors" = "Collaboratori";
+
+// OTP related
+"TimeBased" = "A tempo";
+"HmacBased" = "Basato su HMAC";
+"None" = "Nessuno";
+"ExpiresIn" = "(scade tra %ds)";
+"OTPForPassword" = "One-time password per %@";
+"OTPHasBeenCopied" = "... copiata negli appunti";
+"CopyToPasteboard" = "Copia negli appunti";
+"AutoCopyOTP" = "Copia automaticamente OTP";
+"AutoCopyOTPExplanation." = "Dopo che nome utente e password sono stati riempiti automaticamente da Pass, viene mostrata una notifica con la one-time password, che può essere copiata negli appunti. Con questa opzione attiva la one-time password sarà copiata automaticamente.";
+
+// General (error) messages
+"Error" = "Errore";
+"CannotSave" = "Impossibile salvare";
+"UnresolvedError" = "Errore non risolto %@";
+"MigrationError" = "Errore nella migrazione: %@";
+"UnderlyingError" = "Errore di base: %@";
+"ErrorSaving" = "Errore nel salvataggio: %@";
+"CannotCopyPassword" = "Impossibile copiare la password";
+"CannotAddPassword" = "Impossibile aggiungere la password";
+"WrongPassphrase" = "Password errata";
+"MakeSurePgpAndGitProperlySet." = "Assicurarsi che la chiave PGP e il server Git siano configurati correttamente.";
+"RecoverySuggestion." = "Suggerimento: è stata rimossa la password errata, riprovare.";
+"NSURLFileAllocatedSizeKeyShouldAlwaysReturnValue." = "Cosa? NSURLFileAllocatedSizeKey Dovrebbe sempre restituire un valore.";
+"NoProperPassRepo." = "Il repository non contiene un file .gpg-id. Impostarlo correttamente eseguendo 'pass init', poi riprovare a caricarlo nell'app.";
+
+// Settings
+"PasswordGeneratorFlavor" = "Stile";
+"RememberPgpKeyPassphrase" = "Ricorda la password di PGP";
+"RememberGitCredentialPassphrase" = "Ricorda la password di Git";
+"EnableGPGID" = "Attiva .gpg-id (Sperimentale)";
+"ShowFolders" = "Mostra cartelle";
+"HidePasswordImages" = "Nascondi immagini password";
+"HidePasswordImagesExplanation." = "Le immagini delle password sono caricate e mostrate in base all'URL associato. Attivando questa opzione tali icone non saranno caricate.";
+"HideUnknownFields" = "Nascondi campi sconosciuti";
+"HideUnknownFieldsExplanation." = "È supportato solo il formato \"chiave: valore\" per i campi. Ai campi non supportati verrà assegnata la chiave \"Sconosciuto\". Attivando questa opzione non saranno mostrati i campi non supportati.";
+"HideOtpFields" = "Nascondi campi OTP";
+"HideOtpFieldsExplanation." = "Attivando questa opzione saranno nascosti i campi relativi alle one time password (cioè %@).";
+"Random" = "Casuale";
+"RandomString" = "Stringa casuale";
+"ApplesKeychainStyle" = "Stile Apple Keychain";
+"XKCD" = "XKCD";
+
+// Git
+"FailedToFetchPasswords" = "Impossibile raccogliere le password";
+"FailedToFetchPasswordEntities" = "Impossibile raccogliere le password: %@";
+"FailedToInsertPasswordEntity" = "Impossibile aggiungere password: %@";
+"FailedToDeletePasswordEntity" = "Impossibile eliminare password: %@";
+"FailedToSavePasswordEntity" = "Impossibile salvare password: %@";
+"FailureToSaveContext" = "Impossibile salvare contesto: %@";
+"RepositoryRemoteBranchNotFoundError." = "Impossibile trovare il branch remoto %@.";
+"RepositoryBranchNotFoundError." = "Il branch %@ non è stato trovato in questo repository.";
+"KeyImportError." = "Impossibile importare la chiave.";
+"FileNotFoundError." = "Impossibile leggere il file '%@'.";
+"PasswordDuplicatedError." = "Impossibile aggiungere la password; la password è duplocata.";
+"GitResetError." = "Impossibile identificare l'ultimo commit sincronizzato.";
+"GitCreateSignatureError." = "Impossibile creare un autore/committer valido.";
+"GitPushNotSuccessfulError." = "Impossibile eseguire il push delle modifiche locali. Assicurarsi che non ci siano modifiche senza commit nel repository remoto.";
+"WrongPasswordFilenameError." = "Impossibile scrivere il file della password.";
+"DecryptionError." = "Impossibile decriptare la password.";
+"EncodingError." = "La chiave non ha una codifica ASCII.";
+"UnknownError." = "Errore sconosciuto.";
+"PrepareRepository" = "Preparazione del repository";
+"CheckingOutBranch" = "Controllo del branch '%@'";
+"WantToSaveGitCredential?" = "Salvare la password di Git?";
+
+// Repository
+"RepositoryNotSetError." = "Il repository Git non è impostato.";
+"SetGitRepositoryUrl" = "Impostare l'URL del repository Git.";
+"CannotFindUsername." = "Impossibile trovare il nome utente nell'URL del repository Git. Esempio di URL: ssh://git@server/path/to/repo.git.";
+"CheckEnteredUsername." = "Controllare il nome utente inserito e il nome utente dell'URL del repository Git. Dovrebbero essere uguali.";
+"UseEitherHttpsOrHttp." = "Usare HTTPS (consigliato) o HTTP.";
+"SpecifySchema." = "Specificare lo schema del'URL del repository Git (HTTPS o SSH).";
+"Overwrite?" = "Sovrascrivere?";
+"Overwrite" = "Sovrascrivi";
+"OperationWillOverwriteData." = "Gli attuali dati di Password Store saranno sovrascritti. I dati del server remoto non subiranno modifiche.";
+"DownloadFromUrl" = "Scarica da URL";
+"AsciiArmorEncryptedKey" = "Chiave con armatura ASCII";
+"ITunesFileSharing" = "Condivisione file iTunes";
+"Import" = "Importa";
+"Imported" = "Importata";
+"Tips" = "Consigli";
+"FillInGitAccountPassword." = "Inserire la password dell'account Git.";
+"NoPasswordStore." = "Attualmente non c'è alcun dato di Password Store.";
+"SyncingPasswordStore" = "Sincronizzazione Password Store";
+"PullingFromRemoteRepository" = "Esecuzione del pull dal repository remoto";
+"PushingToRemoteRepository" = "Esecuzione del push al repository remoto";
+"SpecifyBranchName." = "Specificare il nome del branch da usare.";
+
+// SSH
+"FillInSshKeyPassphrase." = "Inserire la password della chiave SSH.";
+"CannotSelectSshKey" = "Impossibile selezionare la chiave SSH";
+"PleaseSetupSshKeyFirst." = "Impostare la chiave SSH.";
+"RemoveSShKeys" = "Rimuovi chiavi SSH di Git";
+"SetPrivateKeyUrl." = "Selezionare un URL per la chiave privata.";
+"SshCopyPrivateKeyToPass." = "Copiare la chiave privata con armatura ASCII in Pass con il nome \"ssh_key\" (senza virgolette) con iTunes. Poi tornare qui e selezionare \"Condivisione file iTunes\" per completare.";
+
+// QR code scanning
+"LookingForStartingFrame." = "Ricerca del frame iniziale.";
+"TooManyQrCodes" = "Troppi codici QR";
+"ScanPrivateKeyQrCodes" = "Scansiona i codici QR della chiave privata";
+"CannotSaveSshKey" = "Impossibile salvare chiave SSH";
+"ScanPublicKey." = "Impossibile scansionare la chiave pubblica.";
+"ScanPrivateKey." = "Impossibile scansionare la chiave privata.";
+"ScanPrivateKeyQrCodes" = "Scansiona i codici QR della chiave privata";
+"ScanPublicKeyQrCodes" = "Scansiona i codici QR della chiave publica";
+"SetPrivateKey." = "Impostare prima la chiave privata.";
+"SetPublicKey." = "Impostare prima la chiave pubblica.";
+"NoQrCodeDetected." = "Nessun codice QR rilevato.";
+"NoStringValue" = "Nessuna stringa";
+"CameraAccessDenied." = "L'accesso alla fotocamera è bloccato.";
+"WarningToggleCameraPermissionsResetsApp." = "ATTENZIONE: Cambiare il permesso della fotocamera reimposta l'app! Salva le modifiche.";
+
+// PGP
+"Decrypting" = "Decriptazione";
+"PgpKeyNotSet." = "La chiave PGP non è impostata. Impostare la chiave PGP.";
+"FillInPgpPassphrase." = "Inserire la password della chiave PGP privata.";
+"WantToSavePassphrase?" = "Salvare la password?";
+"CannotSavePgpKey" = "Impossibile salvare la chiave PGP";
+"SetPgpKeyUrlsFirst." = "Impostare URL validi per le chiavi PGP.";
+"FetchingPgpKey" = "Caricamento della chiave PGP";
+"RememberToRemoveKey" = "Ricorda di eliminare le chiavi";
+"RememberToRemoveKeyFromServer." = "Ricorda di eliminare le chiavi dal server.";
+"RemovePgpKeys" = "Elimina chiavi PGP";
+"PgpCopyPublicAndPrivateKeyToPass." = "Copiare la chiave pubblica e quella privata con armatura ASCII in Pass con i nomi \"gpg_key.pub\" e \"gpg_key\" (senza virgolette) con iTunes. Poi tornare qui e selezionare \"Condivisione file iTunes\" per completare.";
+"KeyExpiredOrIncompatibleError." = "La chiave PGP pubblica potrebbe essere scaduta o non corrispondente alla chiave privata.";
+"WrongPassphraseError." = "La password della chiave PGP segreta è errata.";
+"PgpPublicKeyNotFoundError." = "Impossibile trovare la chiave PGP pubblica (%@).";
+"PgpPrivateKeyNotFoundError." = "Impossibile trovare la chiave PGP privata (%@).";
+"CannotImportFile" = "Impossibile importare il file";
+"LoadFromFiles" = "Carica da File";
+"FileCannotBeImported." = "Impossibile importare il file '%@'. Assicurarsi che si abbiano i permessi necessari per leggere la sua posizione.";
+"RememberToRemoveKeyFromLocation." = "Ricorda di eliminare i file delle chiavi dalle loro posizioni esterne.";
+"KeyFileNotSet." = "Per uno o più tipi di chiavi non è stato selezionato un file.";
+"HttpNotSecure" = "HTTP non è sicuro";
+"ReallyUseHttp?" = "Il protocollo HTTP non è sicuro. Usarlo comunque per trasferire il file della chiave privata?";
+
+// App passcode
+"RemovePasscode" = "Disattiva codice";
+"ChangePasscode" = "Cambia codice";
+"SetPasscode" = "Imposta codice";
+"PasswordConfirmation" = "Conferma con la password";
+"FillInAppPasscode." = "Inserire il codice di Pass (almeno 4 caratteri).";
+
+// Git signature
+"NotSet" = "Non impostata";
+"InvalidNameOrEmail" = "Nome o email non validi";
+
+// Erase password store
+"ErasePasswordStoreData?" = "Eliminare i dati di Password Store?";
+"ErasePasswordStoreData" = "Elimina i dati di Password Store";
+"EraseExplanation." = "Verranno eliminati tutti i dati e le impostazioni locali. I dati nel server remoto non saranno modificati.";
+"Erasing..." = "Eliminazione ...";
+
+// Discard local changes
+"DiscardAllLocalChanges?" = "Scartare le modifiche locali?";
+"DiscardAllLocalChanges" = "Scarta le modifiche locali";
+"DiscardExplanation." = "Scartare permanentemente tutte le modifiche effettuate alla copia locale dei dati di Password Store? L'azione è irreversibile.";
+"Resetting..." = "Reimpostazione ...";
+
+// Forget passcode
+"ForgotYourPasscode?" = "Codice dimenticato?";
+"ResetPass" = "Reimposta Pass";
+"ResetPassExplanation." = "L'unica cosa che si può fare è reimpostare l'app. Verranno eliminati tutti i dati e le impostazioni locali. I dati di Password Store nel server remoto non saranno modificati.";
+
+// Time related
+"Unknown" = "Sconosciuto";
+"JustNow" = "Adesso";
+
+// Commit messages
+"AddPassword." = "Aggiunta password per %@ con Pass per iOS.";
+"RemovePassword." = "Rimossa password per %@ con Pass per iOS.";
+"EditPassword." = "Modificata password per %@ con Pass per iOS.";
+"RenamePassword." = "Rinominato %@ a %@ con Pass per iOS.";
+
+// Menu buttons
+"Ok" = "OK";
+"Cancel" = "Annulla";
+"Dismiss" = "Ignora";
+"Done" = "Fatto";
+"Yes" = "Si";
+"No" = "No";
+"TryAgain" = "Riprova";
+"Delete" = "Elimina";
+"Back" = "Indietro";
+"Current" = "Attuale";
+"All" = "Tutti";
+"On" = "Attivo";
+"Off" = "Disattivato";
+"Save" = "Salva";
+"Remove" = "Elimina";
+
+// Lock screen
+"EnterPasscode" = "Inserire il codice di Pass";
+"Passcode" = "Codice";
+"TouchId" = "Touch ID";
+"FaceId" = "Face ID";
+"AuthenticationNeeded." = "È necessaria l'autenticazione per accedere a Pass.";
+
+// About repository
+"AboutRepository" = "Informazioni sul repository";
+"ValueNotAvailable" = "Valore non disponibile";
+"Size" = "Dimensione";
+"LocalCommits" = "Commit locali";
+"LastSynced" = "Sincronizzato l'ultima volta";
+"Commits" = "Commit";
+"CommitLogs" = "Registri dei sommit";
+"SyncAgain?" = "Sincronizzare ancora?";
+
+// About app
+"Website" = "Sito web";
+"Help" = "Aiuto";
+"ContactDeveloper" = "Contatta lo sviluppatore";
+"OpenSourceComponents" = "Componenti open source";
+"SpecialThanks" = "Ringraziamenti speciali";
+"Acknowledgements" = "Riconoscimenti";
+"ValueNotAvailable" = "Valore non disponibile";
+
+// External applications
+"CannotOpenMail" = "Impossibile aprire l'app Mail";
+"CopiedEmail" = "Email %@ copiata";
+"HttpNotSupported." = "La connessione HTTP non è supportata.";
+
+// Password view
+"Name" = "Nome";
+"Additions" = "Altro";
+"Notice" = "Avviso";
+"PreviousChangesDiscarded." = "Tutte le modifiche precedenti sono state scartate. Verranno mostrate le password attuali.";
+"CannotShowPassword" = "Impossibile mostrare la password";
+"PasswordDoesNotExist" = "La password non esiste.";
+"Saving" = "Salvataggio";
+"Success" = "Successo";
+"OneTimePassword" = "One-time password";
+"ShowRaw" = "Mostra in originale";
+"Reveal" = "Rivela";
+"Conceal" = "Nascondi";
+"NextPassword" = "Password successiva";
+"CopyAndOpen" = "Copia password e apri link";
+"GetNextPasswordOfNonHotp." = "Ottieni la password successiva per un campo non HOTP.";
+"PasswordCopied" = "Password copiata";
+"CounterUpdated" = "Contatore aggiornato";
+"CannotFindValidUrl" = "Impossibile trovare un URL valido";
+"LastUpdated" = "Ultimo aggiornamento: %@";
+"PasswordCopiedToPasteboard." = "Password copiata. Gli appunti saranno cancellati tra 45 secondi.";
+
+// Password editor
+"UseKeyValueFormat." = "Usare il formato \"chiave: valore\" per gli altri campi.";
+"DeletePassword" = "Elimina password";
+"AddOneTimePassword" = "Aggiungi one-time password";
+"Length" = "Lunghezza";
+"VaryCases" = "Maiuscole casuali";
+"Digits" = "Cifre";
+"SpecialSymbols" = "Simboli speciali";
+"Groups" = "Organizza in gruppi";
+"DeletePassword?" = "Eliminare la password?";
+"OverwriteOtpConfiguration?" = "Sovrascrivere la configurazione della one-time password?";
+"ValidTokenUrl" = "Token dell'URL valido";
+"InvalidTokenUrl" = "Token dell'URL non valido";
+"FillInName." = "Inserire il nome.";
+"RemovePrefix." = "La password non può cominciare con \"/\".";
+"PasswordNameInvalid." = "Il nome della password non è valido.";
+"CannotParseFilename." = "Impossibile validare il nome del file. Controllare e semplificare il nome della password.";
+"WannaUseIt?" = "Usarlo?";
+"SeemsLikeYouHaveCopiedSomething." = "Sembra che tu abbia copiato qualcosa.";
+"FirstStringIs:" = "La prima stringa è:";
+
+// Multiline strings
+"SshAsciiArmorCopyExplanation." = "Il formato della chiave con armatura ASCII è simile a documenti non codificati e non al formato binario. Usare
+
+ $ cat ~/.ssh/id_rsa
+
+per ottenere la chiave in questo formato. Gli appunti saranno cancellati 45s dopo aver incollato la chiave.";
+
+"SshAsciiArmorServerExplanation." = "Il formato della chiave con armatura ASCII è simile a documenti non codificati e non al formato binario. Usare
+
+ $ cat ~/.ssh/id_rsa
+
+per ottenere la chiave in questo formato. Dopodiché, copiarla nel server delle chiavi sicuro.";
+
+"SshAsciiArmorFileExplanation." = "Il formato della chiave con armatura ASCII è simile a documenti non codificati e non al formato binario. Usare
+
+ $ cat ~/.ssh/id_rsa
+
+per ottenere la chiave in questo formato. Dopodiché, copiarla in una posizione a cui File abbia accesso.";
+
+"GpgAsciiArmorCopyExplanation." = "GnuPG supporta l'opzione da riga di comando \"-a\" per generare le chiavi in un formato con armatura ASCII, simile a documenti non codificati e non al formato binario. Usare
+
+ $ gpg --list-keys
+
+per identificare il KEY_ID della sottochiave di criptazione (E), poi usare
+
+ $ gpg --export -a KEY_ID! > subkey.pub
+ $ gpg --export-secret-subkeys -a KEY_ID! > subkey
+
+per ottenere la sottochiave pubblica e quella privata di criptazione in questo formato. Verificare che nessuna sottochiave di autenticazione sia stata esportata per errore:
+
+ $ gpg --show-key subkey
+
+Gli appunti saranno cancellati 45s dopo aver incollato.";
+
+"GpgAsciiArmorServerExplanation." = "GnuPG supporta l'opzione da riga di comando \"-a\" per generare le chiavi in un formato con armatura ASCII, simile a documenti non codificati e non al formato binario. Usare
+
+ $ gpg --list-keys
+
+per identificare il KEY_ID della sottochiave di criptazione (E), poi usare
+
+ $ gpg --export -a KEY_ID! > subkey.pub
+ $ gpg --export-secret-subkeys -a KEY_ID! > subkey
+
+per ottenere la sottochiave pubblica e quella privata di criptazione in questo formato. Verificare che nessuna sottochiave di autenticazione sia stata esportata per errore:
+
+ $ gpg --show-key subkey
+
+Infine, copiarle nel server HTTP(S) (che può essere locale).";
+
+"GpgAsciiArmorFileExplanation." = "GnuPG supporta l'opzione da riga di comando \"-a\" per generare le chiavi in un formato con armatura ASCII, simile a documenti non codificati e non al formato binario. Usare
+
+ $ gpg --list-keys
+
+per identificare il KEY_ID della sottochiave di criptazione (E), poi usare
+
+ $ gpg --export -a KEY_ID! > subkey.pub
+ $ gpg --export-secret-subkeys -a KEY_ID! > subkey
+
+per ottenere la sottochiave pubblica e quella privata di criptazione in questo formato. Verificare che nessuna sottochiave di autenticazione sia stata esportata per errore:
+
+ $ gpg --show-key subkey
+
+Infine, copiarla in una posizione a cui File abbia accesso.";
diff --git a/pass/it.lproj/Localizable.stringsdict b/pass/it.lproj/Localizable.stringsdict
new file mode 100644
index 00000000..58659bb8
--- /dev/null
+++ b/pass/it.lproj/Localizable.stringsdict
@@ -0,0 +1,78 @@
+
+
+
+
+ ScannedQrCodes(%d)
+
+ NSStringLocalizedFormatKey
+ %#@codes@
+ codes
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ d
+ zero
+ Nessun codice QR scansionato
+ one
+ Un codice QR scansionato
+ other
+ %d codici QR scansionati
+
+
+ DiscardedCommits(%d)
+
+ NSStringLocalizedFormatKey
+ %#@commits@
+ commits
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ d
+ zero
+ Nessun commit locale
+ one
+ Un commit scartato
+ other
+ %d commit scartati
+
+
+ HiddenFields(%d)
+
+ NSStringLocalizedFormatKey
+ %#@fields@
+ fields
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ d
+ zero
+ Nessun campo nascosto
+ one
+ Un campo nascosto
+ other
+ %d campi nascosti
+
+
+ WrongAttempts(%d)
+
+ NSStringLocalizedFormatKey
+ %#@attempts@
+ attempts
+
+ NSStringFormatSpecTypeKey
+ NSStringPluralRuleType
+ NSStringFormatValueTypeKey
+ d
+ zero
+ Nessun tentativo errato
+ one
+ Un tentativo errato
+ other
+ %d tentativi errati
+
+
+
+
diff --git a/pass/it.lproj/Main.strings b/pass/it.lproj/Main.strings
new file mode 100644
index 00000000..b577f667
--- /dev/null
+++ b/pass/it.lproj/Main.strings
@@ -0,0 +1,261 @@
+
+/* Class = "UITableViewSection"; headerTitle = "ASCII-ARMOR PRIVATE KEY"; ObjectID = "0RP-Jn-j5G"; */
+"0RP-Jn-j5G.headerTitle" = "CHIAVE PRIVATA ARMATURA ASCII";
+
+/* Class = "UILabel"; text = "Not Set"; ObjectID = "2qr-d7-0SK"; */
+"2qr-d7-0SK.text" = "Non impostata";
+
+/* Class = "UITextField"; placeholder = "Private Key URL"; ObjectID = "4iJ-oB-R1f"; */
+"4iJ-oB-R1f.placeholder" = "URL chiave privata";
+
+/* Class = "UITabBarItem"; title = "Settings"; ObjectID = "6Xa-be-Z8g"; */
+"6Xa-be-Z8g.title" = "Impostazioni";
+
+/* Class = "UILabel"; text = "Not Set"; ObjectID = "7lc-Vh-G9W"; */
+"7lc-Vh-G9W.text" = "Non impostato";
+
+/* Class = "UILabel"; text = "Git Signature"; ObjectID = "87a-xY-AbR"; */
+"87a-xY-AbR.text" = "Firma Git";
+
+/* Class = "UILabel"; text = "Bob Sun"; ObjectID = "8Dc-U9-AVf"; */
+"8Dc-U9-AVf.text" = "Bob Sun";
+
+/* Class = "UIBarButtonItem"; title = "Back"; ObjectID = "9yM-Mg-Cg8"; */
+"9yM-Mg-Cg8.title" = "Indietro";
+
+/* Class = "UILabel"; text = "Select file ..."; ObjectID = "9KE-VA-cx2"; */
+"9KE-VA-cx2.text" = "Scegli file ...";
+
+/* Class = "UILabel"; text = "Private Key URL"; ObjectID = "C2w-dd-roS"; */
+"C2w-dd-roS.text" = "URL chiave privata";
+
+/* Class = "UINavigationItem"; title = "Password Store"; ObjectID = "Cio-ZG-zCS"; */
+"Cio-ZG-zCS.title" = "Password Store";
+
+/* Class = "UITableViewSection"; headerTitle = "SECURITY"; ObjectID = "Cx7-e4-wCO"; */
+"Cx7-e4-wCO.headerTitle" = "SICUREZZA";
+
+/* Class = "UINavigationItem"; title = "SSH Key"; ObjectID = "DrT-Wk-L5K"; */
+"DrT-Wk-L5K.title" = "Chiave SSH";
+
+/* Class = "UITextField"; placeholder = "Git Repository URL"; ObjectID = "EVT-VU-sCi"; */
+"EVT-VU-sCi.placeholder" = "URL repository Git";
+
+/* Class = "UILabel"; text = "Title"; ObjectID = "Eu3-i0-M5v"; */
+"Eu3-i0-M5v.text" = "Titolo";
+
+/* Class = "UILabel"; text = "SSH Key"; ObjectID = "Ezz-76-a53"; */
+"Ezz-76-a53.text" = "Chiave SSH";
+
+/* Class = "UILabel"; text = "2017/04/04"; ObjectID = "GLC-qL-55P"; */
+"GLC-qL-55P.text" = "04/04/2017";
+
+/* Class = "UILabel"; text = "Off"; ObjectID = "HXb-ZX-HUv"; */
+"HXb-ZX-HUv.text" = "Disattivato";
+
+/* Class = "UIBarButtonItem"; title = "About"; ObjectID = "HhH-eq-XdK"; */
+"HhH-eq-XdK.title" = "Informazioni";
+
+/* Class = "UINavigationItem"; title = "Edit Password"; ObjectID = "Hj9-Iq-kId"; */
+"Hj9-Iq-kId.title" = "Modifica password";
+
+/* Class = "UINavigationItem"; title = "Scan OTP QR Codes"; ObjectID = "Hlb-5I-bfE"; */
+"Hlb-5I-bfE.title" = "Scannerizza codici QR OTP";
+
+/* Class = "UILabel"; text = "Name"; ObjectID = "Hlb-Zh-ega"; */
+"Hlb-Zh-ega.text" = "Nome";
+
+/* Class = "UINavigationItem"; title = "Scan QR Code"; ObjectID = "JIs-3z-Tmr"; */
+"JIs-3z-Tmr.title" = "Scannerizza codice QR";
+
+/* Class = "UILabel"; text = "Encrypt in ASCII-Armored"; ObjectID = "Jwg-mt-woS"; */
+"Jwg-mt-woS.text" = "Cripta con armatura ASCII";
+
+/* Class = "UILabel"; text = "Erase All Password Store Data"; ObjectID = "K2K-Bx-g7Z"; */
+"K2K-Bx-g7Z.text" = "Elimina tutti i dati di Password Store";
+
+/* Class = "UINavigationItem"; title = "Add Password"; ObjectID = "KOg-Gn-Buk"; */
+"KOg-Gn-Buk.title" = "Aggiungi password";
+
+/* Class = "UILabel"; text = "Select file ..."; ObjectID = "Ka2-8Z-fwx"; */
+"Ka2-8Z-fwx.text" = "Scegli file ...";
+
+/* Class = "UILabel"; text = "Edit password for baidu.com using Pass for iOS."; ObjectID = "L1p-Dm-Mnh"; */
+"L1p-Dm-Mnh.text" = "Modifica password per baidu.com con Pass per iOS.";
+
+/* Class = "UILabel"; text = "Password"; ObjectID = "LfQ-Af-j2O"; */
+"LfQ-Af-j2O.text" = "Password";
+
+/* Class = "UILabel"; text = "ASCII-Armor Keys"; ObjectID = "M32-yr-IfE"; */
+"M32-yr-IfE.text" = "Chiavi armatura ASCII";
+
+/* Class = "UILabel"; text = "Advanced"; ObjectID = "MKj-d0-8q3"; */
+"MKj-d0-8q3.text" = "Avanzate";
+
+/* Class = "UITableViewSection"; headerTitle = "ASCII-Armor Public Key"; ObjectID = "MZz-mp-v5N"; */
+"MZz-mp-v5N.headerTitle" = "Chiave pubblica armatura ASCII";
+
+/* Class = "UILabel"; text = "Not Set"; ObjectID = "Myq-fV-riz"; */
+"Myq-fV-riz.text" = "Non impostata";
+
+/* Class = "UIBarButtonItem"; title = "Back"; ObjectID = "New-sD-9Z1"; */
+"New-sD-9Z1.title" = "Indietro";
+
+/* Class = "UINavigationItem"; title = "About"; ObjectID = "Pel-JD-Z5x"; */
+"Pel-JD-Z5x.title" = "Informazioni";
+
+/* Class = "UILabel"; text = "Private Key URL"; ObjectID = "Qht-RC-Yeg"; */
+"Qht-RC-Yeg.text" = "URL chiave privata";
+
+/* Class = "UITableViewSection"; headerTitle = "PRIVATE KEY"; ObjectID = "RFc-J6-hAe"; */
+"RFc-J6-hAe.headerTitle" = "CHIAVE PRIVATA";
+
+/* Class = "UILabel"; text = "PGP Key"; ObjectID = "RR9-xr-9ko"; */
+"RR9-xr-9ko.text" = "Chiave PGP";
+
+/* Class = "UILabel"; text = "Passcode Lock"; ObjectID = "RaZ-6t-0CU"; */
+"RaZ-6t-0CU.text" = "Codice di blocco";
+
+/* Class = "UITextField"; placeholder = "Public Key URL"; ObjectID = "Rb8-zs-TGa"; */
+"Rb8-zs-TGa.placeholder" = "URL chiave pubblica";
+
+/* Class = "UILabel"; text = "✓"; ObjectID = "Scc-5J-bu1"; */
+"Scc-5J-bu1.text" = "✓";
+
+/* Class = "UITextField"; placeholder = "Username"; ObjectID = "TMg-Gk-7nG"; */
+"TMg-Gk-7nG.placeholder" = "Nome utente";
+
+/* Class = "UILabel"; text = "scanner output"; ObjectID = "U8O-Md-w8e"; */
+"U8O-Md-w8e.text" = "Uscita dello scanner";
+
+/* Class = "UITableViewSection"; headerTitle = "Branch Name"; ObjectID = "Uoy-58-5ug"; */
+"Uoy-58-5ug.headerTitle" = "Nome branch";
+
+/* Class = "UINavigationItem"; title = "PGP Key"; ObjectID = "V4w-cf-d9g"; */
+"V4w-cf-d9g.title" = "Chiave PGP";
+
+/* Class = "UITextField"; placeholder = "Branch Name"; ObjectID = "VVI-gJ-e37"; */
+"VVI-gJ-e37.placeholder" = "Nome branch";
+
+/* Class = "UINavigationItem"; title = "Settings"; ObjectID = "WH4-7R-4TQ"; */
+"WH4-7R-4TQ.title" = "Impostazioni";
+
+/* Class = "UILabel"; text = "Import Keys From Files"; ObjectID = "XU8-Io-n0h"; */
+"XU8-Io-n0h.text" = "Importa chiavi da File";
+
+/* Class = "UILabel"; text = "Select file ..."; ObjectID = "XVY-Dj-6Mx"; */
+"XVY-Dj-6Mx.text" = "Scegli file ...";
+
+/* Class = "UITableViewSection"; headerTitle = "PUBLIC KEY"; ObjectID = "Y8H-cb-G2j"; */
+"Y8H-cb-G2j.headerTitle" = "CHIAVE PUBBLICA";
+
+/* Class = "UITabBarItem"; title = "Settings"; ObjectID = "YLZ-cr-akY"; */
+"YLZ-cr-akY.title" = "Impostazioni";
+
+/* Class = "UITextField"; placeholder = "email"; ObjectID = "YY9-za-MNV"; */
+"YY9-za-MNV.placeholder" = "email";
+
+/* Class = "UINavigationItem"; title = "General"; ObjectID = "aAM-Iw-iBA"; */
+"aAM-Iw-iBA.title" = "Generali";
+
+/* Class = "UINavigationItem"; title = "Recent Commit Log"; ObjectID = "aRM-mj-MAt"; */
+"aRM-mj-MAt.title" = "Log dei commit recenti";
+
+/* Class = "UITableViewSection"; headerTitle = "Password Store Data"; ObjectID = "aVR-FE-jMg"; */
+"aVR-FE-jMg.headerTitle" = "Dati di Password Store";
+
+/* Class = "UINavigationItem"; title = "Raw Password"; ObjectID = "c13-zM-tLf"; */
+"c13-zM-tLf.title" = "Password in originale";
+
+/* Class = "UITextField"; placeholder = "Private Key URL"; ObjectID = "cGJ-1g-Ztc"; */
+"cGJ-1g-Ztc.placeholder" = "URL chiave privata";
+
+/* Class = "UILabel"; text = "ASCII-Armor Keys"; ObjectID = "cMp-Iy-NUj"; */
+"cMp-Iy-NUj.text" = "Chiavi armatura ASCII";
+
+/* Class = "UILabel"; text = "ASCII-Armor Keys"; ObjectID = "cd7-0l-AZW"; */
+"cd7-0l-AZW.text" = "Chiavi armatura ASCII";
+
+/* Class = "UINavigationItem"; title = "About Repository"; ObjectID = "cjL-hB-P6y"; */
+"cjL-hB-P6y.title" = "Informazioni sul repository";
+
+/* Class = "UILabel"; text = "General"; ObjectID = "dOt-Rj-vWD"; */
+"dOt-Rj-vWD.text" = "Generali";
+
+/* Class = "UILabel"; text = "Public Key URL"; ObjectID = "dWi-eh-7Eq"; */
+"dWi-eh-7Eq.text" = "URL chiave pubblica";
+
+/* Class = "UINavigationItem"; title = "Open Source Components"; ObjectID = "duN-f7-Rak"; */
+"duN-f7-Rak.title" = "Componenti open source";
+
+/* Class = "UINavigationItem"; title = "PGP Key"; ObjectID = "eK3-bb-419"; */
+"eK3-bb-419.title" = "Chiave PGP";
+
+/* Class = "UITableViewSection"; headerTitle = "Username"; ObjectID = "fRu-A2-SCk"; */
+"fRu-A2-SCk.headerTitle" = "Nome utente";
+
+/* Class = "UITextField"; placeholder = "name"; ObjectID = "fa8-Vc-w8F"; */
+"fa8-Vc-w8F.placeholder" = "Nome";
+
+/* Class = "UITabBarItem"; title = "Passwords"; ObjectID = "gNg-YT-cGW"; */
+"gNg-YT-cGW.title" = "Password";
+
+/* Class = "UINavigationItem"; title = "SSH Key"; ObjectID = "gNq-BH-pj8"; */
+"gNq-BH-pj8.title" = "Chiave SSH";
+
+/* Class = "UILabel"; text = "Password Repository"; ObjectID = "gWn-ib-STb"; */
+"gWn-ib-STb.text" = "Repository di Password";
+
+/* Class = "UINavigationItem"; title = "Git Server"; ObjectID = "gXX-yl-9oj"; */
+"gXX-yl-9oj.title" = "Server Git";
+
+/* Class = "UITableViewSection"; headerTitle = "Authentication Method"; ObjectID = "h0N-tI-shZ"; */
+"h0N-tI-shZ.headerTitle" = "Metodo di autenticazione";
+
+/* Class = "UILabel"; text = "ASCII-Armor Keys"; ObjectID = "i78-t7-fP9"; */
+"i78-t7-fP9.text" = "Chiavi armatura ASCII";
+
+/* Class = "UITableViewSection"; headerTitle = "Git Configuration"; ObjectID = "ihT-OG-HTv"; */
+"ihT-OG-HTv.headerTitle" = "Configurazione Git";
+
+/* Class = "UILabel"; text = "scanner output"; ObjectID = "lOI-p4-BGb"; */
+"lOI-p4-BGb.text" = "Uscita dello scanner";
+
+/* Class = "UILabel"; text = "Email"; ObjectID = "m25-Qy-XwU"; */
+"m25-Qy-XwU.text" = "Email";
+
+/* Class = "UIViewController"; title = "Raw Password"; ObjectID = "mlB-OK-hLo"; */
+"mlB-OK-hLo.title" = "Password in originale";
+
+/* Class = "UINavigationItem"; title = "Special Thanks"; ObjectID = "oKe-r8-1EF"; */
+"oKe-r8-1EF.title" = "Ringraziamenti speciali";
+
+/* Class = "UILabel"; text = "About"; ObjectID = "oqz-Hr-RAl"; */
+"oqz-Hr-RAl.text" = "Informazioni";
+
+/* Class = "UINavigationItem"; title = "Git Signature"; ObjectID = "pPi-jd-x5U"; */
+"pPi-jd-x5U.title" = "Firma Git";
+
+/* Class = "UITableViewSection"; headerTitle = "Git Repository URL"; ObjectID = "pbe-W6-w4V"; */
+"pbe-W6-w4V.headerTitle" = "URL repository Git";
+
+/* Class = "UIBarButtonItem"; title = "Clone"; ObjectID = "sgQ-zB-rxv"; */
+"sgQ-zB-rxv.title" = "Clona";
+
+/* Class = "UITableViewSection"; headerTitle = "ASCII-ARMOR PRIVATE KEY"; ObjectID = "sxk-Yb-Y3x"; */
+"sxk-Yb-Y3x.headerTitle" = "CHIAVE PRIVATA ARMATURA ASCII";
+
+/* Class = "UINavigationItem"; title = "Advanced"; ObjectID = "tc7-wf-hG7"; */
+"tc7-wf-hG7.title" = "Avanzate";
+
+/* Class = "UITableViewSection"; headerTitle = "GPG Configuration"; ObjectID = "ugP-R2-9M7"; */
+"ugP-R2-9M7.headerTitle" = "Configurazione GPG";
+
+/* Class = "UINavigationItem"; title = "PGP Key"; ObjectID = "waZ-gh-rQt"; */
+"waZ-gh-rQt.title" = "Chiave PGP";
+
+/* Class = "UILabel"; text = "✓"; ObjectID = "wbx-rk-i8H"; */
+"wbx-rk-i8H.text" = "✓";
+
+/* Class = "UILabel"; text = "Discard All Local Changes"; ObjectID = "zrl-v3-fxg"; */
+"zrl-v3-fxg.text" = "Scarta tutte le modifiche locali";
From 51ad0c2920098beca328d3a033fc7156c3d8bee8 Mon Sep 17 00:00:00 2001
From: Tony Wang
Date: Fri, 20 Jan 2023 03:39:05 +0800
Subject: [PATCH 026/103] fix #540, duplicate entries in auto fill extension
(#593)
* fix #540, duplicate entries in auto fill extension
`prepareCredentialList` is called twice, once before unlock and once
after. If the lists are already prepared, i.e. not empty, skip this
step.
* fix format and lint
---
.../GitRepositorySettingsTableViewController.swift | 1 +
pass/Controllers/QRScannerController.swift | 9 +++++----
pass/Services/PasswordDecryptor.swift | 2 +-
.../Services/PasswordsTableDataSource.swift | 4 ++++
4 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/pass/Controllers/GitRepositorySettingsTableViewController.swift b/pass/Controllers/GitRepositorySettingsTableViewController.swift
index e37c7c48..25411165 100644
--- a/pass/Controllers/GitRepositorySettingsTableViewController.swift
+++ b/pass/Controllers/GitRepositorySettingsTableViewController.swift
@@ -172,6 +172,7 @@ class GitRepositorySettingsTableViewController: UITableViewController, PasswordA
// Remember git credential password/passphrase temporarily, ask whether users want this after a successful clone.
Defaults.isRememberGitCredentialPassphraseOn = true
+ // swiftlint:disable:next closure_body_length
DispatchQueue.global(qos: .userInitiated).async {
do {
let transferProgressBlock: (UnsafePointer, UnsafeMutablePointer) -> Void = { git_transfer_progress, _ in
diff --git a/pass/Controllers/QRScannerController.swift b/pass/Controllers/QRScannerController.swift
index 4693d663..cd9bc1b0 100644
--- a/pass/Controllers/QRScannerController.swift
+++ b/pass/Controllers/QRScannerController.swift
@@ -140,11 +140,12 @@ class QRScannerController: UIViewController, AVCaptureMetadataOutputObjectsDeleg
preferredStyle: .alert
)
alertController.addAction(UIAlertAction(title: "Cancel".localize(), style: .default))
- alertController.addAction(UIAlertAction(title: "Settings".localize(), style: .cancel) { _ in
- if let url = URL(string: UIApplication.openSettingsURLString) {
- UIApplication.shared.open(url)
+ alertController.addAction(
+ UIAlertAction(title: "Settings".localize(), style: .cancel) { _ in
+ if let url = URL(string: UIApplication.openSettingsURLString) {
+ UIApplication.shared.open(url)
+ }
}
- }
)
present(alertController, animated: true)
}
diff --git a/pass/Services/PasswordDecryptor.swift b/pass/Services/PasswordDecryptor.swift
index 0e0675a1..c97a7c22 100644
--- a/pass/Services/PasswordDecryptor.swift
+++ b/pass/Services/PasswordDecryptor.swift
@@ -192,7 +192,7 @@ public func yubiKeyDecrypt(
extension Data {
struct HexEncodingOptions: OptionSet {
let rawValue: Int
- static let upperCase = HexEncodingOptions(rawValue: 1 << 0)
+ static let upperCase = Self(rawValue: 1 << 0)
}
func hexEncodedString(options: HexEncodingOptions = []) -> String {
diff --git a/passAutoFillExtension/Services/PasswordsTableDataSource.swift b/passAutoFillExtension/Services/PasswordsTableDataSource.swift
index f59bde49..ab4525b4 100644
--- a/passAutoFillExtension/Services/PasswordsTableDataSource.swift
+++ b/passAutoFillExtension/Services/PasswordsTableDataSource.swift
@@ -72,6 +72,10 @@ class PasswordsTableDataSource: NSObject, UITableViewDataSource {
return
}
+ guard suggestedPasswordsTableEntries.isEmpty, otherPasswordsTableEntries.isEmpty else {
+ return
+ }
+
for entry in passwordTableEntries {
if entry.matches(text) {
suggestedPasswordsTableEntries.append(entry)
From 3ab334dd00401d087d9f6618c9bfce8570f54ea7 Mon Sep 17 00:00:00 2001
From: Martin Nowak
Date: Sat, 21 Jan 2023 16:52:46 +0100
Subject: [PATCH 027/103] fix #488 - support user field for completion
- a few other backends use `user` instead of `username` or `login`
(e.g. gopass-jsonapi, keepass2csv importer, fpm2 importer)
- shorter to type when extracting field separately (e.g. CLI/clipboard) tools
---
pass/Controllers/PasswordDetailTableViewController.swift | 3 +++
passKit/Models/Password.swift | 7 ++++++-
passKit/Parser/Constants.swift | 1 +
passKitTests/Models/PasswordTest.swift | 5 ++++-
passKitTests/Testbase/TestBase.swift | 1 +
5 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/pass/Controllers/PasswordDetailTableViewController.swift b/pass/Controllers/PasswordDetailTableViewController.swift
index 90fdf8a3..804c614e 100644
--- a/pass/Controllers/PasswordDetailTableViewController.swift
+++ b/pass/Controllers/PasswordDetailTableViewController.swift
@@ -250,6 +250,9 @@ class PasswordDetailTableViewController: UITableViewController, UIGestureRecogni
if let username = password.username {
section.item.append(Constants.USERNAME_KEYWORD => username)
}
+ if let user = password.username {
+ section.item.append(Constants.USER_KEYWORD => user)
+ }
if let login = password.login {
section.item.append(Constants.LOGIN_KEYWORD => login)
}
diff --git a/passKit/Models/Password.swift b/passKit/Models/Password.swift
index 9a2b03f2..a9dab8c8 100644
--- a/passKit/Models/Password.swift
+++ b/passKit/Models/Password.swift
@@ -51,6 +51,10 @@ public class Password {
getAdditionValue(withKey: Constants.USERNAME_KEYWORD)
}
+ public var user: String? {
+ getAdditionValue(withKey: Constants.USER_KEYWORD)
+ }
+
public var login: String? {
getAdditionValue(withKey: Constants.LOGIN_KEYWORD)
}
@@ -121,6 +125,7 @@ public class Password {
additions.filter { field in
let title = field.title.lowercased()
return title != Constants.USERNAME_KEYWORD
+ && title != Constants.USER_KEYWORD
&& title != Constants.LOGIN_KEYWORD
&& title != Constants.PASSWORD_KEYWORD
&& (!Constants.isUnknown(title) || !Defaults.isHideUnknownOn)
@@ -215,6 +220,6 @@ public class Password {
}
public func getUsernameForCompletion() -> String {
- username ?? login ?? nameFromPath ?? ""
+ username ?? user ?? login ?? nameFromPath ?? ""
}
}
diff --git a/passKit/Parser/Constants.swift b/passKit/Parser/Constants.swift
index 81f8bffe..42d99dd1 100644
--- a/passKit/Parser/Constants.swift
+++ b/passKit/Parser/Constants.swift
@@ -48,6 +48,7 @@ public enum Constants {
public static let PASSWORD_KEYWORD = "password"
public static let USERNAME_KEYWORD = "username"
+ public static let USER_KEYWORD = "user"
public static let LOGIN_KEYWORD = "login"
public static let URL_KEYWORD = "url"
public static let UNKNOWN = "unknown"
diff --git a/passKitTests/Models/PasswordTest.swift b/passKitTests/Models/PasswordTest.swift
index dddc5825..6ee05a03 100644
--- a/passKitTests/Models/PasswordTest.swift
+++ b/passKitTests/Models/PasswordTest.swift
@@ -32,6 +32,7 @@ class PasswordTest: XCTestCase {
XCTAssertEqual(password.numberOfUnknowns, 0)
XCTAssertNil(password.username)
+ XCTAssertNil(password.user)
XCTAssertNil(password.urlString)
XCTAssertNil(password.login)
@@ -53,7 +54,7 @@ class PasswordTest: XCTestCase {
}
func testSimplePasswordFile() {
- let additions = SECURE_URL_FIELD | LOGIN_FIELD | USERNAME_FIELD | NOTE_FIELD
+ let additions = SECURE_URL_FIELD | LOGIN_FIELD | USERNAME_FIELD | USER_FIELD | NOTE_FIELD
let fileContent = PASSWORD_STRING | additions
let password = getPasswordObjectWith(content: fileContent)
@@ -62,11 +63,13 @@ class PasswordTest: XCTestCase {
XCTAssert(SECURE_URL_FIELD ∈ password)
XCTAssert(LOGIN_FIELD ∉ password)
XCTAssert(USERNAME_FIELD ∉ password)
+ XCTAssert(USER_FIELD ∉ password)
XCTAssert(NOTE_FIELD ∈ password)
XCTAssertEqual(password.urlString, SECURE_URL_FIELD.content)
XCTAssertEqual(password.login, LOGIN_FIELD.content)
XCTAssertEqual(password.username, USERNAME_FIELD.content)
+ XCTAssertEqual(password.user, USER_FIELD.content)
}
func testTwoPasswords() {
diff --git a/passKitTests/Testbase/TestBase.swift b/passKitTests/Testbase/TestBase.swift
index 5c816cb0..cae542d6 100644
--- a/passKitTests/Testbase/TestBase.swift
+++ b/passKitTests/Testbase/TestBase.swift
@@ -22,6 +22,7 @@ let SECURE_URL_FIELD = "url" => "https://secure.com"
let INSECURE_URL_FIELD = "url" => "http://insecure.com"
let LOGIN_FIELD = "login" => "login name"
let USERNAME_FIELD = "username" => "微 分 方 程"
+let USER_FIELD = "user" => "积 分 方 程"
let NOTE_FIELD = "note" => "A NOTE"
let HINT_FIELD = "some hints" => "äöüß // €³ %% −° && @²` | [{\\}],.<>"
let TOTP_URL_FIELD = "otpauth" => "//totp/email@email.com?secret=abcd1234"
From f6f862a6b06ef2970d5a8ea5db6e1f2740654f9f Mon Sep 17 00:00:00 2001
From: Tony Wang
Date: Thu, 26 Jan 2023 23:00:32 +0800
Subject: [PATCH 028/103] refs #584, add operation to clear QuickType
suggestion in settings
---
pass/Base.lproj/Main.storyboard | 26 +++++++++++++++++--
.../AdvancedSettingsTableViewController.swift | 12 +++++++++
pass/en.lproj/Localizable.strings | 5 +++-
3 files changed, 40 insertions(+), 3 deletions(-)
diff --git a/pass/Base.lproj/Main.storyboard b/pass/Base.lproj/Main.storyboard
index 3a7afc73..8e140fd2 100644
--- a/pass/Base.lproj/Main.storyboard
+++ b/pass/Base.lproj/Main.storyboard
@@ -1141,17 +1141,38 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
@@ -127,21 +127,21 @@
-
+
-
+
-
+
-
+
@@ -155,21 +155,21 @@
-
+
-
+
-
+
-
+
@@ -183,14 +183,14 @@
-
+
-
+
-
+
@@ -207,14 +207,14 @@
-
+
-
+
-
+
@@ -252,13 +252,13 @@
-
+
-
+
@@ -313,7 +313,7 @@
-
+
@@ -321,14 +321,14 @@
-
+
-
+
-
+
@@ -350,14 +350,14 @@
-
+
-
+
-
+
@@ -378,14 +378,14 @@
-
+
-
+
-
+
@@ -406,20 +406,20 @@
-
+
-
+
-
+
-
+
@@ -438,20 +438,20 @@
-
+
-
+
-
+
-
+
@@ -507,7 +507,7 @@
-
+
@@ -515,21 +515,21 @@
-
+
-
+
-
+
-
+
@@ -543,7 +543,7 @@
-
+
@@ -556,7 +556,7 @@
-
+
@@ -576,7 +576,7 @@
-
+
@@ -589,7 +589,7 @@
-
+
@@ -637,7 +637,7 @@
-
+
@@ -711,7 +711,7 @@
-
+
@@ -737,7 +737,7 @@
-
+
@@ -789,7 +789,7 @@
-
+
@@ -805,7 +805,7 @@
-
+
@@ -846,11 +846,11 @@
-
+
-
+
@@ -904,7 +904,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -931,7 +931,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -947,7 +947,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -955,21 +955,21 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
-
+
-
+
@@ -983,7 +983,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1043,7 +1043,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1068,7 +1068,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1084,7 +1084,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1092,14 +1092,14 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
-
+
@@ -1113,21 +1113,21 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
-
+
-
+
@@ -1144,14 +1144,14 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
-
+
@@ -1165,14 +1165,14 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
-
+
@@ -1182,14 +1182,14 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
-
+
@@ -1223,7 +1223,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1247,7 +1247,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1267,7 +1267,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1290,7 +1290,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1308,7 +1308,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1324,7 +1324,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1332,21 +1332,21 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
-
+
-
+
@@ -1360,7 +1360,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1385,10 +1385,10 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
@@ -1397,7 +1397,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1422,10 +1422,10 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
@@ -1464,7 +1464,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1498,7 +1498,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1506,21 +1506,21 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
-
+
-
+
@@ -1534,7 +1534,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1556,10 +1556,10 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
@@ -1594,7 +1594,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1602,7 +1602,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1615,7 +1615,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1634,7 +1634,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1647,7 +1647,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1735,7 +1735,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1753,7 +1753,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1771,7 +1771,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1787,7 +1787,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1795,21 +1795,21 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
-
+
-
+
@@ -1823,14 +1823,14 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
-
+
@@ -1844,14 +1844,14 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
-
+
@@ -1888,7 +1888,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1904,7 +1904,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1912,21 +1912,21 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
-
+
-
+
@@ -1940,14 +1940,14 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
-
+
diff --git a/passAutoFillExtension/Base.lproj/MainInterface.storyboard b/passAutoFillExtension/Base.lproj/MainInterface.storyboard
index dad9add2..0cd598b0 100644
--- a/passAutoFillExtension/Base.lproj/MainInterface.storyboard
+++ b/passAutoFillExtension/Base.lproj/MainInterface.storyboard
@@ -1,9 +1,9 @@
-
+
-
+
@@ -18,7 +18,7 @@
-
+
@@ -46,7 +46,6 @@
-
@@ -59,6 +58,7 @@
+
diff --git a/passAutoFillExtension/SearchPassword.storyboard b/passAutoFillExtension/SearchPassword.storyboard
index d38c66c9..608c90b2 100644
--- a/passAutoFillExtension/SearchPassword.storyboard
+++ b/passAutoFillExtension/SearchPassword.storyboard
@@ -1,9 +1,9 @@
-
+
-
+
@@ -17,7 +17,7 @@
-
+
diff --git a/passExtension/Base.lproj/MainInterface.storyboard b/passExtension/Base.lproj/MainInterface.storyboard
index b8f602d4..a84bd218 100644
--- a/passExtension/Base.lproj/MainInterface.storyboard
+++ b/passExtension/Base.lproj/MainInterface.storyboard
@@ -1,9 +1,9 @@
-
+
-
+
@@ -36,7 +36,7 @@
-
+
From 788adee1a7b6a862170dfeaf5745a5afc8582d1d Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Sun, 12 Mar 2023 21:30:31 -0700
Subject: [PATCH 049/103] Unify cell style for the password generator
---
pass.xcodeproj/project.pbxproj | 8 +++++
pass/Base.lproj/Main.storyboard | 10 +++----
.../PasswordEditorTableViewController.swift | 2 ++
pass/Views/PasswordGeneratorUISlider.swift | 11 +++++++
pass/Views/PasswordGeneratorUISwitch.swift | 11 +++++++
pass/Views/SliderTableViewCell.swift | 4 +++
pass/Views/SliderTableViewCell.xib | 30 ++++++++-----------
pass/Views/SwitchTableViewCell.swift | 4 +++
pass/Views/SwitchTableViewCell.xib | 25 +++++++++-------
passKit/Helpers/Globals.swift | 1 +
10 files changed, 72 insertions(+), 34 deletions(-)
create mode 100644 pass/Views/PasswordGeneratorUISlider.swift
create mode 100644 pass/Views/PasswordGeneratorUISwitch.swift
diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj
index 51e921fb..9d3a83de 100644
--- a/pass.xcodeproj/project.pbxproj
+++ b/pass.xcodeproj/project.pbxproj
@@ -193,6 +193,8 @@
DC037CC01E4ED4E100609409 /* TextViewTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DC037CBE1E4ED4E100609409 /* TextViewTableViewCell.xib */; };
DC0F7692283C00220042DA74 /* passKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A26075781EEC6F34005DB03E /* passKit.framework */; };
DC193FFA1E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC193FF91E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift */; };
+ DC30F83829BED4E2001EB12B /* PasswordGeneratorUISwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC30F83729BED4E2001EB12B /* PasswordGeneratorUISwitch.swift */; };
+ DC30F83A29BED611001EB12B /* PasswordGeneratorUISlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC30F83929BED611001EB12B /* PasswordGeneratorUISlider.swift */; };
DC3E64E61E656F11009A83DE /* CommitLogsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC3E64E51E656F11009A83DE /* CommitLogsTableViewController.swift */; };
DC4914961E434301007FF592 /* LabelTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC4914941E434301007FF592 /* LabelTableViewCell.swift */; };
DC4914991E434600007FF592 /* PasswordDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC4914981E434600007FF592 /* PasswordDetailTableViewController.swift */; };
@@ -484,6 +486,8 @@
DC13B1521E8640810097803F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
DC193FF91E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AdvancedSettingsTableViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
DC30F83629BAFD2E001EB12B /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Main.strings; sourceTree = ""; };
+ DC30F83729BED4E2001EB12B /* PasswordGeneratorUISwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordGeneratorUISwitch.swift; sourceTree = ""; };
+ DC30F83929BED611001EB12B /* PasswordGeneratorUISlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordGeneratorUISlider.swift; sourceTree = ""; };
DC3E64E51E656F11009A83DE /* CommitLogsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommitLogsTableViewController.swift; sourceTree = ""; };
DC4914941E434301007FF592 /* LabelTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LabelTableViewCell.swift; sourceTree = ""; };
DC4914981E434600007FF592 /* PasswordDetailTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordDetailTableViewController.swift; sourceTree = ""; };
@@ -1004,6 +1008,8 @@
A2802BF81E70813A00879216 /* SliderTableViewCell.xib */,
306D970D24091CDD006C0E2E /* SwitchTableViewCell.swift */,
306D971124091EE7006C0E2E /* SwitchTableViewCell.xib */,
+ DC30F83729BED4E2001EB12B /* PasswordGeneratorUISwitch.swift */,
+ DC30F83929BED611001EB12B /* PasswordGeneratorUISlider.swift */,
DC037CB91E4DD47B00609409 /* TextFieldTableViewCell.swift */,
DC037CBA1E4DD47B00609409 /* TextFieldTableViewCell.xib */,
DC037CBD1E4ED4E100609409 /* TextViewTableViewCell.swift */,
@@ -1652,6 +1658,7 @@
306D970E24091CDD006C0E2E /* SwitchTableViewCell.swift in Sources */,
A2A61C201EEFABAD00CFE063 /* UtilsExtension.swift in Sources */,
DC8963C01E38EEB900828B09 /* SSHKeyURLImportTableViewController..swift in Sources */,
+ DC30F83829BED4E2001EB12B /* PasswordGeneratorUISwitch.swift in Sources */,
9AFC87F025B514AD008D6060 /* PasswordDecryptor.swift in Sources */,
3066AD6823EE0D6500F65535 /* PGPKeyImporter.swift in Sources */,
9AFC87E225B3B5C6008D6060 /* PasswordNavigationDataSource.swift in Sources */,
@@ -1659,6 +1666,7 @@
DC193FFA1E49B4430077E0A3 /* AdvancedSettingsTableViewController.swift in Sources */,
9AFC880025B51EC3008D6060 /* PasswordEncryptor.swift in Sources */,
DCA0499C1E3362F400522E8F /* PGPKeyURLImportTableViewController.swift in Sources */,
+ DC30F83A29BED611001EB12B /* PasswordGeneratorUISlider.swift in Sources */,
DC4914961E434301007FF592 /* LabelTableViewCell.swift in Sources */,
DC5F385B1E56AADB00C69ACA /* PGPKeyArmorImportTableViewController.swift in Sources */,
DCAAF7451E2FA66800AB94BC /* SettingsTableViewController.swift in Sources */,
diff --git a/pass/Base.lproj/Main.storyboard b/pass/Base.lproj/Main.storyboard
index 99a1fdf5..3b3d8f44 100644
--- a/pass/Base.lproj/Main.storyboard
+++ b/pass/Base.lproj/Main.storyboard
@@ -21,7 +21,7 @@
-
+
@@ -1099,7 +1099,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1151,7 +1151,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1189,7 +1189,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1985,7 +1985,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
diff --git a/pass/Controllers/PasswordEditorTableViewController.swift b/pass/Controllers/PasswordEditorTableViewController.swift
index 375271cc..b7d7147d 100644
--- a/pass/Controllers/PasswordEditorTableViewController.swift
+++ b/pass/Controllers/PasswordEditorTableViewController.swift
@@ -82,6 +82,8 @@ class PasswordEditorTableViewController: UITableViewController {
passwordFlavorCell = UITableViewCell(style: .default, reuseIdentifier: "default")
passwordFlavorCell?.textLabel?.text = "PasswordGeneratorFlavor".localize()
+ passwordFlavorCell?.textLabel?.font = .preferredFont(forTextStyle: .footnote)
+ passwordFlavorCell!.layoutMargins.left = passKit.Globals.passwordGeneratorLeftLayoutMargin
passwordFlavorCell?.selectionStyle = .none
let passwordFlavorSelector = UISegmentedControl(items: PasswordGeneratorFlavor.allCases.map(\.localized))
diff --git a/pass/Views/PasswordGeneratorUISlider.swift b/pass/Views/PasswordGeneratorUISlider.swift
new file mode 100644
index 00000000..b0bfdb18
--- /dev/null
+++ b/pass/Views/PasswordGeneratorUISlider.swift
@@ -0,0 +1,11 @@
+//
+// PasswordGeneratorUISlider.swift
+//
+
+import UIKit
+
+class PasswordGeneratorUISlider: UISlider {
+ override func draw(_: CGRect) {
+ transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
+ }
+}
diff --git a/pass/Views/PasswordGeneratorUISwitch.swift b/pass/Views/PasswordGeneratorUISwitch.swift
new file mode 100644
index 00000000..995ceeec
--- /dev/null
+++ b/pass/Views/PasswordGeneratorUISwitch.swift
@@ -0,0 +1,11 @@
+//
+// PasswordGeneratorUISwitch.swift
+//
+
+import UIKit
+
+class PasswordGeneratorUISwitch: UISwitch {
+ override func draw(_: CGRect) {
+ transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
+ }
+}
diff --git a/pass/Views/SliderTableViewCell.swift b/pass/Views/SliderTableViewCell.swift
index 1310088e..3e227f18 100644
--- a/pass/Views/SliderTableViewCell.swift
+++ b/pass/Views/SliderTableViewCell.swift
@@ -33,6 +33,10 @@ class SliderTableViewCell: UITableViewCell {
delegate.generateAndCopyPassword()
}
+ override func layoutMarginsDidChange() {
+ layoutMargins.left = passKit.Globals.passwordGeneratorLeftLayoutMargin
+ }
+
func set(title: String) -> SliderTableViewCell {
titleLabel.text = title
return self
diff --git a/pass/Views/SliderTableViewCell.xib b/pass/Views/SliderTableViewCell.xib
index 260695c6..52938d73 100644
--- a/pass/Views/SliderTableViewCell.xib
+++ b/pass/Views/SliderTableViewCell.xib
@@ -1,32 +1,29 @@
-
-
-
-
+
+
-
-
+
-
+
-
+
-
-
+
+
-
+
@@ -35,22 +32,19 @@
-
-
-
-
-
+
+
-
+
-
+
diff --git a/pass/Views/SwitchTableViewCell.swift b/pass/Views/SwitchTableViewCell.swift
index a5fc5ea1..a595f182 100644
--- a/pass/Views/SwitchTableViewCell.swift
+++ b/pass/Views/SwitchTableViewCell.swift
@@ -28,6 +28,10 @@ class SwitchTableViewCell: UITableViewCell {
return self
}
+ override func layoutMarginsDidChange() {
+ layoutMargins.left = passKit.Globals.passwordGeneratorLeftLayoutMargin
+ }
+
func set(initialValue: Bool) -> SwitchTableViewCell {
controlSwitch.isOn = initialValue
return self
diff --git a/pass/Views/SwitchTableViewCell.xib b/pass/Views/SwitchTableViewCell.xib
index 9a9b4159..14024c37 100644
--- a/pass/Views/SwitchTableViewCell.xib
+++ b/pass/Views/SwitchTableViewCell.xib
@@ -1,15 +1,16 @@
-
+
-
+
+
-
+
@@ -17,17 +18,14 @@
-
-
-
-
-
+
+
-
-
-
+
+
+
@@ -48,4 +46,9 @@
+
+
+
+
+
diff --git a/passKit/Helpers/Globals.swift b/passKit/Helpers/Globals.swift
index 62dcbecc..8c79c708 100644
--- a/passKit/Helpers/Globals.swift
+++ b/passKit/Helpers/Globals.swift
@@ -52,6 +52,7 @@ public final class Globals {
// UI related
public static let tableCellButtonSize = CGFloat(20.0)
+ public static let passwordGeneratorLeftLayoutMargin = CGFloat(32)
private init() {}
}
From a2d3926b7a2a709a49778e0c01978eef6fdf2903 Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Sun, 12 Mar 2023 21:44:00 -0700
Subject: [PATCH 050/103] Fix no UIScene configuration dictionary warning
---
pass/Info.plist | 7 +++++++
passAutoFillExtension/Info.plist | 7 +++++++
passExtension/Info.plist | 13 ++++++++++---
3 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/pass/Info.plist b/pass/Info.plist
index eb292922..0476d432 100644
--- a/pass/Info.plist
+++ b/pass/Info.plist
@@ -2,6 +2,13 @@
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+ UISceneConfigurations
+
+
com.apple.developer.nfc.readersession.iso7816.select-identifiers
A000000527471117
diff --git a/passAutoFillExtension/Info.plist b/passAutoFillExtension/Info.plist
index d5967914..41f6c5d1 100644
--- a/passAutoFillExtension/Info.plist
+++ b/passAutoFillExtension/Info.plist
@@ -2,6 +2,13 @@
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+ UISceneConfigurations
+
+
CFBundleDevelopmentRegion
en
CFBundleDisplayName
diff --git a/passExtension/Info.plist b/passExtension/Info.plist
index 44236f66..65be6deb 100644
--- a/passExtension/Info.plist
+++ b/passExtension/Info.plist
@@ -2,6 +2,13 @@
+ UIApplicationSceneManifest
+
+ UISceneConfigurations
+
+ UIApplicationSupportsMultipleScenes
+
+
CFBundleDevelopmentRegion
en
CFBundleDisplayName
@@ -31,9 +38,9 @@
SUBQUERY (
$extensionItem.attachments,
$attachment,
- ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "org.appextension.find-login-action" ||
- ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url" ||
- ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.plain-text"
+ ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "org.appextension.find-login-action" ||
+ ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.url" ||
+ ANY $attachment.registeredTypeIdentifiers UTI-CONFORMS-TO "public.plain-text"
).@count == $extensionItem.attachments.@count
).@count == 1
NSExtensionJavaScriptPreprocessingFile
From 01a29333aecf21b208f59713437d9844d88cdb66 Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Mon, 13 Mar 2023 21:11:21 -0700
Subject: [PATCH 051/103] Fix black screen bug at startup
---
pass/Info.plist | 2 +-
passAutoFillExtension/Info.plist | 2 +-
passExtension/Info.plist | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/pass/Info.plist b/pass/Info.plist
index 0476d432..a9ce9ea8 100644
--- a/pass/Info.plist
+++ b/pass/Info.plist
@@ -5,7 +5,7 @@
UIApplicationSceneManifest
UIApplicationSupportsMultipleScenes
-
+
UISceneConfigurations
diff --git a/passAutoFillExtension/Info.plist b/passAutoFillExtension/Info.plist
index 41f6c5d1..68e7c785 100644
--- a/passAutoFillExtension/Info.plist
+++ b/passAutoFillExtension/Info.plist
@@ -5,7 +5,7 @@
UIApplicationSceneManifest
UIApplicationSupportsMultipleScenes
-
+
UISceneConfigurations
diff --git a/passExtension/Info.plist b/passExtension/Info.plist
index 65be6deb..11d61d59 100644
--- a/passExtension/Info.plist
+++ b/passExtension/Info.plist
@@ -7,7 +7,7 @@
UISceneConfigurations
UIApplicationSupportsMultipleScenes
-
+
CFBundleDevelopmentRegion
en
From 4904b81da07affad4b6eb06d2991aaae14150b30 Mon Sep 17 00:00:00 2001
From: Mingshen Sun
Date: Mon, 13 Mar 2023 21:33:54 -0700
Subject: [PATCH 052/103] UI improvements
---
pass/Base.lproj/Main.storyboard | 229 ++++++++----------
.../PasswordDetailTableViewController.swift | 9 +-
.../PasswordEditorTableViewController.swift | 30 ++-
.../PasswordNavigationViewController.swift | 10 +
4 files changed, 139 insertions(+), 139 deletions(-)
diff --git a/pass/Base.lproj/Main.storyboard b/pass/Base.lproj/Main.storyboard
index 3b3d8f44..ff1214e7 100644
--- a/pass/Base.lproj/Main.storyboard
+++ b/pass/Base.lproj/Main.storyboard
@@ -20,16 +20,15 @@
-
-
+
+
-
-
+
-
+
@@ -40,7 +39,7 @@
-
+
@@ -72,15 +71,14 @@
-
+
-
-
+
@@ -100,21 +98,21 @@
-
+
-
+
-
+
-
+
@@ -127,21 +125,21 @@
-
+
-
+
-
+
-
+
@@ -155,21 +153,21 @@
-
+
-
+
-
+
-
+
@@ -183,7 +181,7 @@
-
+
@@ -207,7 +205,7 @@
-
+
@@ -252,10 +250,9 @@
-
+
-
@@ -313,10 +310,9 @@
-
+
-
@@ -324,11 +320,11 @@
-
+
-
+
@@ -350,14 +346,14 @@
-
+
-
+
@@ -378,14 +374,14 @@
-
+
-
+
@@ -406,20 +402,20 @@
-
+
-
+
-
+
-
+
@@ -438,20 +434,20 @@
-
+
-
+
-
+
-
+
@@ -507,15 +503,14 @@
-
+
-
-
+
@@ -543,20 +538,20 @@
-
+
-
+
-
+
@@ -576,20 +571,20 @@
-
+
-
+
-
+
@@ -637,10 +632,9 @@
-
+
-
@@ -711,10 +705,9 @@
-
+
-
@@ -805,10 +798,9 @@
-
+
-
@@ -904,10 +896,9 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
@@ -947,18 +938,17 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
-
+
-
+
@@ -983,20 +973,20 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
-
+
-
+
@@ -1043,10 +1033,9 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
@@ -1084,10 +1073,9 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
@@ -1113,7 +1101,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1144,14 +1132,14 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
@@ -1165,7 +1153,7 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
@@ -1182,14 +1170,14 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
+
@@ -1223,10 +1211,9 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
@@ -1247,10 +1234,9 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
@@ -1267,10 +1253,9 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
@@ -1324,15 +1309,14 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-
+
-
-
+
@@ -1360,14 +1344,14 @@ Secret Question 1: What is your childhood best friend's most bizarre superhero f
-