2
0

Pearl & API update.

This commit is contained in:
Maarten Billemont 2020-01-14 13:59:32 -05:00
parent 22796663dc
commit 91b89aaf39
17 changed files with 575 additions and 561 deletions

@ -1 +1 @@
Subproject commit 3d04d775e01ab1a437bb42166e92662ffffeedd4 Subproject commit 4eb904f9b4c318da36b5071d57d137b63f8ef144

View File

@ -241,6 +241,11 @@
DAA1765419D8B82B0044227B /* choose_type.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763E19D8B82B0044227B /* choose_type.png */; }; DAA1765419D8B82B0044227B /* choose_type.png in Resources */ = {isa = PBXBuildFile; fileRef = DAA1763E19D8B82B0044227B /* choose_type.png */; };
DAA449D21EEC4B5800E7BDD5 /* mpw-marshal.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D01EEC4B5800E7BDD5 /* mpw-marshal.c */; }; DAA449D21EEC4B5800E7BDD5 /* mpw-marshal.c in Sources */ = {isa = PBXBuildFile; fileRef = DAA449D01EEC4B5800E7BDD5 /* mpw-marshal.c */; };
DAA7BC2720C4C27100101DC7 /* libsodium.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAA7BB8A20C4C10F00101DC7 /* libsodium.a */; }; DAA7BC2720C4C27100101DC7 /* libsodium.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAA7BB8A20C4C10F00101DC7 /* libsodium.a */; };
DAAA1D4123CD145000F3DF56 /* Storyboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DAAA1D4023CD145000F3DF56 /* Storyboard.storyboard */; };
DAAA1D4423CD161300F3DF56 /* UILayoutGuide+Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DAAA1D4223CD161300F3DF56 /* UILayoutGuide+Pearl.m */; };
DAAA1D4523CD161300F3DF56 /* UILayoutGuide+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DAAA1D4323CD161300F3DF56 /* UILayoutGuide+Pearl.h */; };
DAAA1D4823CD164500F3DF56 /* PearlRSAKey.m in Sources */ = {isa = PBXBuildFile; fileRef = DAAA1D4623CD164500F3DF56 /* PearlRSAKey.m */; };
DAAA1D4923CD164500F3DF56 /* PearlRSAKey.h in Headers */ = {isa = PBXBuildFile; fileRef = DAAA1D4723CD164500F3DF56 /* PearlRSAKey.h */; };
DAADBFE01A68763B00F7A756 /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = 93D3969393A3A46BD27D7078 /* mpw-algorithm.c */; }; DAADBFE01A68763B00F7A756 /* mpw-algorithm.c in Sources */ = {isa = PBXBuildFile; fileRef = 93D3969393A3A46BD27D7078 /* mpw-algorithm.c */; };
DAB07C9D1F7725C500CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9B1F7725C500CC6D43 /* aes.c */; }; DAB07C9D1F7725C500CC6D43 /* aes.c in Sources */ = {isa = PBXBuildFile; fileRef = DAB07C9B1F7725C500CC6D43 /* aes.c */; };
DAB4FBC4202FDDDD002768FB /* NSInvocation+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBC2202FDDDC002768FB /* NSInvocation+Pearl.h */; }; DAB4FBC4202FDDDD002768FB /* NSInvocation+Pearl.h in Headers */ = {isa = PBXBuildFile; fileRef = DAB4FBC2202FDDDC002768FB /* NSInvocation+Pearl.h */; };
@ -415,8 +420,6 @@
DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE460115039823003ABA7C /* PearlKeyChain.m */; }; DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE460115039823003ABA7C /* PearlKeyChain.m */; };
DAFE4A3C15039824003ABA7C /* Pearl-UIKit-Dependencies.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460815039823003ABA7C /* Pearl-UIKit-Dependencies.h */; }; DAFE4A3C15039824003ABA7C /* Pearl-UIKit-Dependencies.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460815039823003ABA7C /* Pearl-UIKit-Dependencies.h */; };
DAFE4A3D15039824003ABA7C /* Pearl-UIKit.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460915039823003ABA7C /* Pearl-UIKit.h */; }; DAFE4A3D15039824003ABA7C /* Pearl-UIKit.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460915039823003ABA7C /* Pearl-UIKit.h */; };
DAFE4A3E15039824003ABA7C /* PearlAlert.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460A15039823003ABA7C /* PearlAlert.h */; };
DAFE4A3F15039824003ABA7C /* PearlAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE460B15039823003ABA7C /* PearlAlert.m */; };
DAFE4A4015039824003ABA7C /* PearlArrayTVC.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460C15039823003ABA7C /* PearlArrayTVC.h */; }; DAFE4A4015039824003ABA7C /* PearlArrayTVC.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460C15039823003ABA7C /* PearlArrayTVC.h */; };
DAFE4A4115039824003ABA7C /* PearlArrayTVC.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE460D15039823003ABA7C /* PearlArrayTVC.m */; }; DAFE4A4115039824003ABA7C /* PearlArrayTVC.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE460D15039823003ABA7C /* PearlArrayTVC.m */; };
DAFE4A4215039824003ABA7C /* PearlBoxView.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460E15039823003ABA7C /* PearlBoxView.h */; }; DAFE4A4215039824003ABA7C /* PearlBoxView.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE460E15039823003ABA7C /* PearlBoxView.h */; };
@ -427,8 +430,6 @@
DAFE4A4B15039824003ABA7C /* PearlMessageView.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE461715039823003ABA7C /* PearlMessageView.m */; }; DAFE4A4B15039824003ABA7C /* PearlMessageView.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE461715039823003ABA7C /* PearlMessageView.m */; };
DAFE4A4C15039824003ABA7C /* PearlRootViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461815039823003ABA7C /* PearlRootViewController.h */; }; DAFE4A4C15039824003ABA7C /* PearlRootViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461815039823003ABA7C /* PearlRootViewController.h */; };
DAFE4A4D15039824003ABA7C /* PearlRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE461915039823003ABA7C /* PearlRootViewController.m */; }; DAFE4A4D15039824003ABA7C /* PearlRootViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE461915039823003ABA7C /* PearlRootViewController.m */; };
DAFE4A4E15039824003ABA7C /* PearlSheet.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461A15039823003ABA7C /* PearlSheet.h */; };
DAFE4A4F15039824003ABA7C /* PearlSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE461B15039823003ABA7C /* PearlSheet.m */; };
DAFE4A5015039824003ABA7C /* PearlUIDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461C15039823003ABA7C /* PearlUIDebug.h */; }; DAFE4A5015039824003ABA7C /* PearlUIDebug.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461C15039823003ABA7C /* PearlUIDebug.h */; };
DAFE4A5115039824003ABA7C /* PearlUIDebug.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE461D15039823003ABA7C /* PearlUIDebug.m */; }; DAFE4A5115039824003ABA7C /* PearlUIDebug.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE461D15039823003ABA7C /* PearlUIDebug.m */; };
DAFE4A5215039824003ABA7C /* PearlUIUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461E15039823003ABA7C /* PearlUIUtils.h */; }; DAFE4A5215039824003ABA7C /* PearlUIUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE461E15039823003ABA7C /* PearlUIUtils.h */; };
@ -896,6 +897,11 @@
DAA7BBC620C4C10F00101DC7 /* crypto_generichash_blake2b.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypto_generichash_blake2b.h; sourceTree = "<group>"; }; DAA7BBC620C4C10F00101DC7 /* crypto_generichash_blake2b.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypto_generichash_blake2b.h; sourceTree = "<group>"; };
DAA7BBC720C4C10F00101DC7 /* crypto_sign_edwards25519sha512batch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypto_sign_edwards25519sha512batch.h; sourceTree = "<group>"; }; DAA7BBC720C4C10F00101DC7 /* crypto_sign_edwards25519sha512batch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypto_sign_edwards25519sha512batch.h; sourceTree = "<group>"; };
DAA7BBC820C4C10F00101DC7 /* sodium.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sodium.h; sourceTree = "<group>"; }; DAA7BBC820C4C10F00101DC7 /* sodium.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sodium.h; sourceTree = "<group>"; };
DAAA1D4023CD145000F3DF56 /* Storyboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Storyboard.storyboard; sourceTree = "<group>"; };
DAAA1D4223CD161300F3DF56 /* UILayoutGuide+Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UILayoutGuide+Pearl.m"; sourceTree = "<group>"; };
DAAA1D4323CD161300F3DF56 /* UILayoutGuide+Pearl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UILayoutGuide+Pearl.h"; sourceTree = "<group>"; };
DAAA1D4623CD164500F3DF56 /* PearlRSAKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlRSAKey.m; sourceTree = "<group>"; };
DAAA1D4723CD164500F3DF56 /* PearlRSAKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlRSAKey.h; sourceTree = "<group>"; };
DAAC35DD156BD77D00C5FD93 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; DAAC35DD156BD77D00C5FD93 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; };
DAB07C9B1F7725C500CC6D43 /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aes.c; sourceTree = "<group>"; }; DAB07C9B1F7725C500CC6D43 /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = aes.c; sourceTree = "<group>"; };
DAB07C9C1F7725C500CC6D43 /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = "<group>"; }; DAB07C9C1F7725C500CC6D43 /* aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aes.h; sourceTree = "<group>"; };
@ -1640,8 +1646,6 @@
DAFE460615039823003ABA7C /* README */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = README; sourceTree = "<group>"; }; DAFE460615039823003ABA7C /* README */ = {isa = PBXFileReference; fileEncoding = 1; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
DAFE460815039823003ABA7C /* Pearl-UIKit-Dependencies.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Pearl-UIKit-Dependencies.h"; sourceTree = "<group>"; }; DAFE460815039823003ABA7C /* Pearl-UIKit-Dependencies.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Pearl-UIKit-Dependencies.h"; sourceTree = "<group>"; };
DAFE460915039823003ABA7C /* Pearl-UIKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Pearl-UIKit.h"; sourceTree = "<group>"; }; DAFE460915039823003ABA7C /* Pearl-UIKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Pearl-UIKit.h"; sourceTree = "<group>"; };
DAFE460A15039823003ABA7C /* PearlAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlAlert.h; sourceTree = "<group>"; };
DAFE460B15039823003ABA7C /* PearlAlert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlAlert.m; sourceTree = "<group>"; };
DAFE460C15039823003ABA7C /* PearlArrayTVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlArrayTVC.h; sourceTree = "<group>"; }; DAFE460C15039823003ABA7C /* PearlArrayTVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlArrayTVC.h; sourceTree = "<group>"; };
DAFE460D15039823003ABA7C /* PearlArrayTVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlArrayTVC.m; sourceTree = "<group>"; }; DAFE460D15039823003ABA7C /* PearlArrayTVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlArrayTVC.m; sourceTree = "<group>"; };
DAFE460E15039823003ABA7C /* PearlBoxView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlBoxView.h; sourceTree = "<group>"; }; DAFE460E15039823003ABA7C /* PearlBoxView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlBoxView.h; sourceTree = "<group>"; };
@ -1652,8 +1656,6 @@
DAFE461715039823003ABA7C /* PearlMessageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlMessageView.m; sourceTree = "<group>"; }; DAFE461715039823003ABA7C /* PearlMessageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlMessageView.m; sourceTree = "<group>"; };
DAFE461815039823003ABA7C /* PearlRootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlRootViewController.h; sourceTree = "<group>"; }; DAFE461815039823003ABA7C /* PearlRootViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlRootViewController.h; sourceTree = "<group>"; };
DAFE461915039823003ABA7C /* PearlRootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlRootViewController.m; sourceTree = "<group>"; }; DAFE461915039823003ABA7C /* PearlRootViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlRootViewController.m; sourceTree = "<group>"; };
DAFE461A15039823003ABA7C /* PearlSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlSheet.h; sourceTree = "<group>"; };
DAFE461B15039823003ABA7C /* PearlSheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlSheet.m; sourceTree = "<group>"; };
DAFE461C15039823003ABA7C /* PearlUIDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUIDebug.h; sourceTree = "<group>"; }; DAFE461C15039823003ABA7C /* PearlUIDebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUIDebug.h; sourceTree = "<group>"; };
DAFE461D15039823003ABA7C /* PearlUIDebug.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlUIDebug.m; sourceTree = "<group>"; }; DAFE461D15039823003ABA7C /* PearlUIDebug.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlUIDebug.m; sourceTree = "<group>"; };
DAFE461E15039823003ABA7C /* PearlUIUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUIUtils.h; sourceTree = "<group>"; }; DAFE461E15039823003ABA7C /* PearlUIUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlUIUtils.h; sourceTree = "<group>"; };
@ -2940,6 +2942,7 @@
DABD3BD71711E2DC00CF925C /* iOS */ = { DABD3BD71711E2DC00CF925C /* iOS */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
DAAA1D4023CD145000F3DF56 /* Storyboard.storyboard */,
DABD3BFA1711E2DC00CF925C /* InfoPlist.strings */, DABD3BFA1711E2DC00CF925C /* InfoPlist.strings */,
DABD3BFC1711E2DC00CF925C /* main.m */, DABD3BFC1711E2DC00CF925C /* main.m */,
DABD3BF31711E2DC00CF925C /* MasterPassword-Info.plist */, DABD3BF31711E2DC00CF925C /* MasterPassword-Info.plist */,
@ -3166,6 +3169,8 @@
DA45711B1F572F1E00D54152 /* PearlCryptUtils.m */, DA45711B1F572F1E00D54152 /* PearlCryptUtils.m */,
DAFE460015039823003ABA7C /* PearlKeyChain.h */, DAFE460015039823003ABA7C /* PearlKeyChain.h */,
DAFE460115039823003ABA7C /* PearlKeyChain.m */, DAFE460115039823003ABA7C /* PearlKeyChain.m */,
DAAA1D4723CD164500F3DF56 /* PearlRSAKey.h */,
DAAA1D4623CD164500F3DF56 /* PearlRSAKey.m */,
DAFE460615039823003ABA7C /* README */, DAFE460615039823003ABA7C /* README */,
); );
path = "Pearl-Crypto"; path = "Pearl-Crypto";
@ -3179,8 +3184,6 @@
DAFE460815039823003ABA7C /* Pearl-UIKit-Dependencies.h */, DAFE460815039823003ABA7C /* Pearl-UIKit-Dependencies.h */,
DAFE460915039823003ABA7C /* Pearl-UIKit.h */, DAFE460915039823003ABA7C /* Pearl-UIKit.h */,
DA30E9D315722EF400A68B4C /* Pearl-UIKit.m */, DA30E9D315722EF400A68B4C /* Pearl-UIKit.m */,
DAFE460A15039823003ABA7C /* PearlAlert.h */,
DAFE460B15039823003ABA7C /* PearlAlert.m */,
DAFE4A61150399FF003ABA7C /* PearlAppDelegate.h */, DAFE4A61150399FF003ABA7C /* PearlAppDelegate.h */,
DAFE4A60150399FF003ABA7C /* PearlAppDelegate.m */, DAFE4A60150399FF003ABA7C /* PearlAppDelegate.m */,
DAFE460C15039823003ABA7C /* PearlArrayTVC.h */, DAFE460C15039823003ABA7C /* PearlArrayTVC.h */,
@ -3205,8 +3208,6 @@
93D390FADEB325D8D54A957D /* PearlOverlay.m */, 93D390FADEB325D8D54A957D /* PearlOverlay.m */,
DAFE461815039823003ABA7C /* PearlRootViewController.h */, DAFE461815039823003ABA7C /* PearlRootViewController.h */,
DAFE461915039823003ABA7C /* PearlRootViewController.m */, DAFE461915039823003ABA7C /* PearlRootViewController.m */,
DAFE461A15039823003ABA7C /* PearlSheet.h */,
DAFE461B15039823003ABA7C /* PearlSheet.m */,
93D39A4759186F6D2D34AA6B /* PearlSizedTextView.h */, 93D39A4759186F6D2D34AA6B /* PearlSizedTextView.h */,
93D39156E806BB78E04F78B9 /* PearlSizedTextView.m */, 93D39156E806BB78E04F78B9 /* PearlSizedTextView.m */,
93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */, 93D39B1D8177A86C5B9EDDE3 /* PearlUICollectionView.h */,
@ -3231,6 +3232,8 @@
DAFE4A63150399FF003ABA89 /* UIControl+PearlSelect.m */, DAFE4A63150399FF003ABA89 /* UIControl+PearlSelect.m */,
DAFE4A1115039824003ABA7C /* UIImage+PearlScaling.h */, DAFE4A1115039824003ABA7C /* UIImage+PearlScaling.h */,
DAFE4A1215039824003ABA7C /* UIImage+PearlScaling.m */, DAFE4A1215039824003ABA7C /* UIImage+PearlScaling.m */,
DAAA1D4323CD161300F3DF56 /* UILayoutGuide+Pearl.h */,
DAAA1D4223CD161300F3DF56 /* UILayoutGuide+Pearl.m */,
93D394482BB07F90E8FD1314 /* UIResponder+PearlFirstResponder.h */, 93D394482BB07F90E8FD1314 /* UIResponder+PearlFirstResponder.h */,
93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */, 93D39A1DDFA09AE2E14D26DC /* UIResponder+PearlFirstResponder.m */,
93D39DE2CB351D4E3789462B /* UIScrollView+PearlAdjustInsets.h */, 93D39DE2CB351D4E3789462B /* UIScrollView+PearlAdjustInsets.h */,
@ -3296,6 +3299,7 @@
DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */, DAFE4A1515039824003ABA7C /* NSString+PearlNSArrayFormat.h in Headers */,
DAFE4A1715039824003ABA7C /* NSString+PearlSEL.h in Headers */, DAFE4A1715039824003ABA7C /* NSString+PearlSEL.h in Headers */,
DA250A1A195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.h in Headers */, DA250A1A195665A100AC23F1 /* UICollectionReusableView+PearlDequeue.h in Headers */,
DAAA1D4923CD164500F3DF56 /* PearlRSAKey.h in Headers */,
DAFE4A1915039824003ABA7C /* Pearl.h in Headers */, DAFE4A1915039824003ABA7C /* Pearl.h in Headers */,
DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */, DAFE4A1A15039824003ABA7C /* PearlAbstractStrings.h in Headers */,
DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */, DAFE4A1E15039824003ABA7C /* PearlCodeUtils.h in Headers */,
@ -3322,7 +3326,6 @@
DAB4FBD6202FDE48002768FB /* PearlLinks.h in Headers */, DAB4FBD6202FDE48002768FB /* PearlLinks.h in Headers */,
DAEC85B818E3DD9A007FC0DF /* UIView+Touches.h in Headers */, DAEC85B818E3DD9A007FC0DF /* UIView+Touches.h in Headers */,
DAFE4A3D15039824003ABA7C /* Pearl-UIKit.h in Headers */, DAFE4A3D15039824003ABA7C /* Pearl-UIKit.h in Headers */,
DAFE4A3E15039824003ABA7C /* PearlAlert.h in Headers */,
DAFE4A4015039824003ABA7C /* PearlArrayTVC.h in Headers */, DAFE4A4015039824003ABA7C /* PearlArrayTVC.h in Headers */,
DAFE4A4215039824003ABA7C /* PearlBoxView.h in Headers */, DAFE4A4215039824003ABA7C /* PearlBoxView.h in Headers */,
DAEFB01F19BCBD9E00525079 /* UIView+LayoutGone.h in Headers */, DAEFB01F19BCBD9E00525079 /* UIView+LayoutGone.h in Headers */,
@ -3332,7 +3335,6 @@
DACE2F6619BA6A0A0010F92E /* PearlProfiler.h in Headers */, DACE2F6619BA6A0A0010F92E /* PearlProfiler.h in Headers */,
DAFE4A4C15039824003ABA7C /* PearlRootViewController.h in Headers */, DAFE4A4C15039824003ABA7C /* PearlRootViewController.h in Headers */,
DAB4FBC9202FDE0F002768FB /* PearlCryptUtils.h in Headers */, DAB4FBC9202FDE0F002768FB /* PearlCryptUtils.h in Headers */,
DAFE4A4E15039824003ABA7C /* PearlSheet.h in Headers */,
DAFE4A5015039824003ABA7C /* PearlUIDebug.h in Headers */, DAFE4A5015039824003ABA7C /* PearlUIDebug.h in Headers */,
DAFE4A5215039824003ABA7C /* PearlUIUtils.h in Headers */, DAFE4A5215039824003ABA7C /* PearlUIUtils.h in Headers */,
DAFE4A5415039824003ABA7C /* PearlValidatingTextField.h in Headers */, DAFE4A5415039824003ABA7C /* PearlValidatingTextField.h in Headers */,
@ -3368,6 +3370,7 @@
93D399E4BC1E092A8C8B12AE /* NSOrderedSetOrArray.h in Headers */, 93D399E4BC1E092A8C8B12AE /* NSOrderedSetOrArray.h in Headers */,
93D39BFB5F5F9337F6565DE3 /* UIView+Visible.h in Headers */, 93D39BFB5F5F9337F6565DE3 /* UIView+Visible.h in Headers */,
DAB4FBD4202FDE48002768FB /* UIView+PearlLayout.h in Headers */, DAB4FBD4202FDE48002768FB /* UIView+PearlLayout.h in Headers */,
DAAA1D4523CD161300F3DF56 /* UILayoutGuide+Pearl.h in Headers */,
93D39359B0DF9823F6C56A05 /* PearlHangDetector.h in Headers */, 93D39359B0DF9823F6C56A05 /* PearlHangDetector.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -3874,6 +3877,7 @@
DABD3FCF1714F45C00CF925C /* identity@2x.png in Resources */, DABD3FCF1714F45C00CF925C /* identity@2x.png in Resources */,
DAA1764619D8B82B0044227B /* name_new.png in Resources */, DAA1764619D8B82B0044227B /* name_new.png in Resources */,
DA45224B190628B2008F650A /* icon_gear.png in Resources */, DA45224B190628B2008F650A /* icon_gear.png in Resources */,
DAAA1D4123CD145000F3DF56 /* Storyboard.storyboard in Resources */,
DA8495311A93049300B3053D /* icon_down.png in Resources */, DA8495311A93049300B3053D /* icon_down.png in Resources */,
DA25C5FF197DBF200046CDCF /* icon_thumbs-up@2x.png in Resources */, DA25C5FF197DBF200046CDCF /* icon_thumbs-up@2x.png in Resources */,
DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */, DAE1EF2217E942DE00BC0086 /* Localizable.strings in Resources */,
@ -4059,6 +4063,7 @@
DAFE4A1415039824003ABA7C /* NSObject+PearlExport.m in Sources */, DAFE4A1415039824003ABA7C /* NSObject+PearlExport.m in Sources */,
DAFE4A1615039824003ABA7C /* NSString+PearlNSArrayFormat.m in Sources */, DAFE4A1615039824003ABA7C /* NSString+PearlNSArrayFormat.m in Sources */,
DAFE4A1815039824003ABA7C /* NSString+PearlSEL.m in Sources */, DAFE4A1815039824003ABA7C /* NSString+PearlSEL.m in Sources */,
DAAA1D4823CD164500F3DF56 /* PearlRSAKey.m in Sources */,
DAFE4A1B15039824003ABA7C /* PearlAbstractStrings.m in Sources */, DAFE4A1B15039824003ABA7C /* PearlAbstractStrings.m in Sources */,
DAFE4A1F15039824003ABA7C /* PearlCodeUtils.m in Sources */, DAFE4A1F15039824003ABA7C /* PearlCodeUtils.m in Sources */,
DAEFB01E19BCBD9E00525079 /* UIView+LayoutGone.m in Sources */, DAEFB01E19BCBD9E00525079 /* UIView+LayoutGone.m in Sources */,
@ -4073,7 +4078,6 @@
DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */, DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */,
DA72BD7B19C1510C00E6ACFE /* UIView+FontScale.m in Sources */, DA72BD7B19C1510C00E6ACFE /* UIView+FontScale.m in Sources */,
DA250A17195665A100AC23F1 /* UITableView+PearlReloadItems.m in Sources */, DA250A17195665A100AC23F1 /* UITableView+PearlReloadItems.m in Sources */,
DAFE4A3F15039824003ABA7C /* PearlAlert.m in Sources */,
DAFE4A4115039824003ABA7C /* PearlArrayTVC.m in Sources */, DAFE4A4115039824003ABA7C /* PearlArrayTVC.m in Sources */,
DAFE4A4315039824003ABA7C /* PearlBoxView.m in Sources */, DAFE4A4315039824003ABA7C /* PearlBoxView.m in Sources */,
DAFE4A4515039824003ABA7C /* PearlGradientView.m in Sources */, DAFE4A4515039824003ABA7C /* PearlGradientView.m in Sources */,
@ -4082,7 +4086,6 @@
DAFE4A4B15039824003ABA7C /* PearlMessageView.m in Sources */, DAFE4A4B15039824003ABA7C /* PearlMessageView.m in Sources */,
DACE2F6519BA6A0A0010F92E /* PearlProfiler.m in Sources */, DACE2F6519BA6A0A0010F92E /* PearlProfiler.m in Sources */,
DAFE4A4D15039824003ABA7C /* PearlRootViewController.m in Sources */, DAFE4A4D15039824003ABA7C /* PearlRootViewController.m in Sources */,
DAFE4A4F15039824003ABA7C /* PearlSheet.m in Sources */,
DAFE4A5115039824003ABA7C /* PearlUIDebug.m in Sources */, DAFE4A5115039824003ABA7C /* PearlUIDebug.m in Sources */,
DAFE4A5315039824003ABA7C /* PearlUIUtils.m in Sources */, DAFE4A5315039824003ABA7C /* PearlUIUtils.m in Sources */,
DAFE4A5515039824003ABA7C /* PearlValidatingTextField.m in Sources */, DAFE4A5515039824003ABA7C /* PearlValidatingTextField.m in Sources */,
@ -4119,6 +4122,7 @@
93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */, 93D39A8EA1C49CE43B63F47B /* PearlUICollectionView.m in Sources */,
93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */, 93D399246DC90F50913A1287 /* UIResponder+PearlFirstResponder.m in Sources */,
DAA141201922FF020032B392 /* PearlTween.m in Sources */, DAA141201922FF020032B392 /* PearlTween.m in Sources */,
DAAA1D4423CD161300F3DF56 /* UILayoutGuide+Pearl.m in Sources */,
DAB4FBD7202FDE48002768FB /* UIView+PearlLayout.m in Sources */, DAB4FBD7202FDE48002768FB /* UIView+PearlLayout.m in Sources */,
93D391ECBD9BD2C64115B5DD /* PearlSizedTextView.m in Sources */, 93D391ECBD9BD2C64115B5DD /* PearlSizedTextView.m in Sources */,
DAB4FBD3202FDE48002768FB /* PearlLinks.m in Sources */, DAB4FBD3202FDE48002768FB /* PearlLinks.m in Sources */,
@ -4309,7 +4313,7 @@
GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VALUE = YES; GCC_WARN_UNUSED_VALUE = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 9.3;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "${TARGET_NAME}"; PRODUCT_NAME = "${TARGET_NAME}";
@ -4348,7 +4352,6 @@
"\"$(PROJECT_DIR)/../lib/libjson-c/build-ios~/out/include\"", "\"$(PROJECT_DIR)/../lib/libjson-c/build-ios~/out/include\"",
); );
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist"; INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
@ -4523,7 +4526,7 @@
GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VALUE = YES; GCC_WARN_UNUSED_VALUE = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 9.3;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
@ -4628,7 +4631,7 @@
GCC_WARN_UNUSED_LABEL = YES; GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VALUE = YES; GCC_WARN_UNUSED_VALUE = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 9.3;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "${TARGET_NAME}"; PRODUCT_NAME = "${TARGET_NAME}";
@ -4666,7 +4669,6 @@
"\"$(PROJECT_DIR)/../lib/libjson-c/build-ios~/out/include\"", "\"$(PROJECT_DIR)/../lib/libjson-c/build-ios~/out/include\"",
); );
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist"; INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
@ -4710,7 +4712,6 @@
"\"$(PROJECT_DIR)/../lib/libjson-c/build-ios~/out/include\"", "\"$(PROJECT_DIR)/../lib/libjson-c/build-ios~/out/include\"",
); );
INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist"; INFOPLIST_FILE = "Source/iOS/MasterPassword-Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = ( LIBRARY_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
@ -4728,7 +4729,6 @@
SWIFT_OBJC_BRIDGING_HEADER = "Source/iOS/MasterPassword-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Source/iOS/MasterPassword-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 4.0; SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 1;
}; };
name = Release; name = Release;
}; };

View File

@ -104,24 +104,19 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
if (![[MPAppDelegate_Shared get] canMakePayments]) { if (![[MPAppDelegate_Shared get] canMakePayments]) {
[PearlAlert showAlertWithTitle:@"App Store Not Set Up" message: UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"App Store Not Set Up" message:
@"Make sure your Apple ID is set under Settings -> iTunes & App Store, " @"Make sure your Apple ID is set under Settings -> iTunes & App Store, "
@"you have a payment method added to the account and purchases are" @"you have a payment method added to the account and purchases are"
@"not disabled under General -> Restrictions." @"not disabled under General -> Restrictions."
viewStyle:UIAlertViewStyleDefault initAlert:nil preferredStyle:UIAlertControllerStyleAlert];
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { [controller addAction:[UIAlertAction actionWithTitle:@"Settings" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
if (buttonIndex == alert.cancelButtonIndex) [PearlLinks openSettingsStore];
// Cancel }]];
return; [controller addAction:[UIAlertAction actionWithTitle:@"Try Anyway" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
if (buttonIndex == alert.firstOtherButtonIndex) { [self performPurchaseProductWithIdentifier:productIdentifier quantity:quantity];
// Settings }]];
[PearlLinks openSettingsStore]; [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
return; [self.navigationController presentViewController:controller animated:YES completion:nil];
}
// Try Anyway
[self performPurchaseProductWithIdentifier:productIdentifier quantity:quantity];
} cancelTitle:@"Cancel" otherTitles:@"Settings", @"Try Anyway", nil];
return; return;
} }
#endif #endif
@ -163,11 +158,12 @@ PearlAssociatedObjectProperty( NSMutableArray*, ProductObservers, productObserve
MPError( error, @"StoreKit request (%@) failed.", request ); MPError( error, @"StoreKit request (%@) failed.", request );
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
[PearlAlert showAlertWithTitle:@"Purchase Failed" message: UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Purchase Failed" message:
strf( @"%@\n\n%@", error.localizedDescription, strf( @"%@\n\n%@", error.localizedDescription,
@"Ensure you are online and try logging out and back into iTunes from your device's Settings." ) @"Ensure you are online and try logging out and back into iTunes from your device's Settings." )
viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:nil preferredStyle:UIAlertControllerStyleAlert];
cancelTitle:@"OK" otherTitles:nil]; [controller addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]];
[self.navigationController presentViewController:controller animated:YES completion:nil];
#else #else
#endif #endif
} }

View File

@ -256,17 +256,19 @@
#ifdef PEARL_UIKIT #ifdef PEARL_UIKIT
masterPassword = PearlAwait( ^(void (^setResult)(id)) { masterPassword = PearlAwait( ^(void (^setResult)(id)) {
[PearlAlert showAlertWithTitle:@"Enter Old Master Password" UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Enter Old Master Password" message:
message:PearlString( PearlString( @"Your old master password is required to migrate the stored password for %@", site.name )
@"Your old master password is required to migrate the stored password for %@", preferredStyle:UIAlertControllerStyleAlert];
site.name ) [controller addTextFieldWithConfigurationHandler:nil];
viewStyle:UIAlertViewStyleSecureTextInput [controller addAction:[UIAlertAction actionWithTitle:@"Migrate" style:UIAlertActionStyleDefault handler:
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) { ^(UIAlertAction *_Nonnull action) {
if (buttonIndex_ == [alert_ cancelButtonIndex]) setResult( controller.textFields.firstObject.text );
setResult( nil ); }]];
else [controller addAction:[UIAlertAction actionWithTitle:@"Don't Migrate" style:UIAlertActionStyleCancel handler:
setResult( [alert_ textFieldAtIndex:0].text ); ^(UIAlertAction *_Nonnull action) {
} cancelTitle:@"Don't Migrate" otherTitles:@"Migrate", nil]; setResult( nil );
}]];
[self.navigationController presentViewController:controller animated:YES completion:nil];
} ); } );
#endif #endif
if (!masterPassword) if (!masterPassword)

View File

@ -51,17 +51,21 @@
#define mpw_log(level, format, ...) \ #define mpw_log(level, format, ...) \
do { \ do { \
void (*_sendMsg)(id, SEL, CFStringRef, NSInteger, CFStringRef, NSUInteger, CFStringRef) = (void *)objc_msgSend; \
char *_msg = NULL; \ char *_msg = NULL; \
asprintf( &_msg, format, ##__VA_ARGS__ ); \ asprintf( &_msg, format, ##__VA_ARGS__ ); \
CFStringRef fileStr = CFStringCreateWithCString( NULL, basename( (char *)__FILE__ ), kCFStringEncodingUTF8 ); \ if (_msg) { \
CFStringRef funcStr = CFStringCreateWithCString( NULL, __FUNCTION__, kCFStringEncodingUTF8 ); \ CFStringRef fileStr = CFStringCreateWithCString( NULL, basename( (char *)__FILE__ ), kCFStringEncodingUTF8 ); \
CFStringRef msgStr = CFStringCreateWithCString( NULL, _msg, kCFStringEncodingUTF8 ); \ CFStringRef funcStr = CFStringCreateWithCString( NULL, __FUNCTION__, kCFStringEncodingUTF8 ); \
_sendMsg( objc_msgSend( (id)objc_getClass( "PearlLogger" ), sel_getUid( "get" ) ), \ CFStringRef msgStr = CFStringCreateWithCString( NULL, _msg, kCFStringEncodingUTF8 ); \
sel_getUid( "inFile:atLine:fromFunction:withLevel:text:" ), fileStr, __LINE__, funcStr, level, msgStr ); \ id (*_getLogger)(id, SEL) = (void *)objc_msgSend; \
CFRelease( fileStr ); \ void (*_sendMsg)(id, SEL, CFStringRef, NSInteger, CFStringRef, NSUInteger, CFStringRef) = (void *)objc_msgSend; \
CFRelease( funcStr ); \ _sendMsg( _getLogger( (id)objc_getClass( "PearlLogger" ), sel_getUid( "get" ) ), \
CFRelease( msgStr ); \ sel_getUid( "inFile:atLine:fromFunction:withLevel:text:" ), fileStr, __LINE__, funcStr, level, msgStr ); \
if (fileStr) { CFRelease( fileStr ); } \
if (funcStr) { CFRelease( funcStr ); } \
if (msgStr) { CFRelease( msgStr ); } \
free(_msg); \
} \
} while (0) } while (0)
#define trc(format, ...) mpw_log( 0, format, ##__VA_ARGS__ ); #define trc(format, ...) mpw_log( 0, format, ##__VA_ARGS__ );

View File

@ -172,23 +172,24 @@
if (![site.questions count]) if (![site.questions count])
[self setMultiple:NO animated:YES]; [self setMultiple:NO animated:YES];
else else {
[PearlAlert showAlertWithTitle:@"Remove Site Questions?" message: UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Remove Site Questions?" message:
@"Do you want to remove the questions you have configured for this site?" @"Do you want to remove the questions you have configured for this site?"
viewStyle:UIAlertViewStyleDefault initAlert:nil preferredStyle:UIAlertControllerStyleAlert];
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { [controller addAction:[UIAlertAction actionWithTitle:@"Remove Questions" style:UIAlertActionStyleDestructive handler:
if (buttonIndex == [alert cancelButtonIndex]) ^(UIAlertAction *_Nonnull action) {
return; [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPSiteEntity *site_ = [self siteInContext:context];
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { NSOrderedSet *questions = [site_.questions copy];
MPSiteEntity *site_ = [self siteInContext:context]; for (MPSiteQuestionEntity *question in questions)
NSOrderedSet *questions = [site_.questions copy]; [context deleteObject:question];
for (MPSiteQuestionEntity *question in questions) [context saveToStore];
[context deleteObject:question]; [self setMultiple:NO animated:YES];
[context saveToStore]; }];
[self setMultiple:NO animated:YES]; }]];
}]; [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
} cancelTitle:@"Cancel" otherTitles:@"Remove Questions", nil]; [self presentViewController:controller animated:YES completion:nil];
}
} }
} }
@ -197,9 +198,9 @@
if (!self.multiple) { if (!self.multiple) {
NSObject *answer = [site resolveSiteAnswerUsingKey:[MPiOSAppDelegate get].key]; NSObject *answer = [site resolveSiteAnswerUsingKey:[MPiOSAppDelegate get].key];
body = strf( @"Master Password generated the following security answer for your site: %@\n\n" body = strf( @"Master Password generated the following security answer for your site: %@\n\n"
@"%@\n" @"%@\n"
@"\n\nYou should use this as the answer to each security question the site asks you.\n" @"\n\nYou should use this as the answer to each security question the site asks you.\n"
@"Do not share this answer with others!", site.name, answer ); @"Do not share this answer with others!", site.name, answer );
} }
else { else {
NSMutableString *bodyBuilder = [NSMutableString string]; NSMutableString *bodyBuilder = [NSMutableString string];
@ -209,7 +210,7 @@
[bodyBuilder appendFormat:@"For question: '%@', use answer: %@\n", question.keyword, answer]; [bodyBuilder appendFormat:@"For question: '%@', use answer: %@\n", question.keyword, answer];
} }
[bodyBuilder appendFormat:@"\n\nUse the answer for the matching security question.\n" [bodyBuilder appendFormat:@"\n\nUse the answer for the matching security question.\n"
@"Do not share this answer with others!"]; @"Do not share this answer with others!"];
body = bodyBuilder; body = bodyBuilder;
} }
@ -225,7 +226,7 @@
- (void)copyAnswer:(NSString *)answer { - (void)copyAnswer:(NSString *)answer {
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
if (@available(iOS 10.0, *)) { if (@available( iOS 10.0, * )) {
[pasteboard setItems:@[ @{ UIPasteboardTypeAutomatic: answer } ] [pasteboard setItems:@[ @{ UIPasteboardTypeAutomatic: answer } ]
options:@{ options:@{
UIPasteboardOptionLocalOnly : @NO, UIPasteboardOptionLocalOnly : @NO,

View File

@ -228,9 +228,9 @@ const long MPAvatarAdd = 10000;
case MPAvatarModeLowered: { case MPAvatarModeLowered: {
[self.avatarSizeConstraint updateConstant: [self.avatarSizeConstraint updateConstant:
self.avatarImageView.image.size.height * (self.visibility * 0.3f + 0.7f)]; self.avatarImageView.image.size.height * (self.visibility * 0.3f + 0.7f)];
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultLow]; [self.avatarRaisedConstraint withPriority:UILayoutPriorityDefaultLow];
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow]; [self.avatarToTopConstraint withPriority:UILayoutPriorityDefaultLow];
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultLow]; [self.nameToCenterConstraint withPriority:UILayoutPriorityDefaultLow];
self.nameContainer.visible = YES; self.nameContainer.visible = YES;
self.nameContainer.backgroundColor = [UIColor clearColor]; self.nameContainer.backgroundColor = [UIColor clearColor];
self.avatarImageView.visible = YES; self.avatarImageView.visible = YES;
@ -239,9 +239,9 @@ const long MPAvatarAdd = 10000;
case MPAvatarModeRaisedButInactive: { case MPAvatarModeRaisedButInactive: {
[self.avatarSizeConstraint updateConstant: [self.avatarSizeConstraint updateConstant:
self.avatarImageView.image.size.height * (self.visibility * 0.7f + 0.3f)]; self.avatarImageView.image.size.height * (self.visibility * 0.7f + 0.3f)];
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh]; [self.avatarRaisedConstraint withPriority:UILayoutPriorityDefaultHigh];
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow]; [self.avatarToTopConstraint withPriority:UILayoutPriorityDefaultLow];
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultLow]; [self.nameToCenterConstraint withPriority:UILayoutPriorityDefaultLow];
self.nameContainer.visible = YES; self.nameContainer.visible = YES;
self.nameContainer.backgroundColor = [UIColor clearColor]; self.nameContainer.backgroundColor = [UIColor clearColor];
self.avatarImageView.visible = NO; self.avatarImageView.visible = NO;
@ -250,9 +250,9 @@ const long MPAvatarAdd = 10000;
case MPAvatarModeRaisedAndActive: { case MPAvatarModeRaisedAndActive: {
[self.avatarSizeConstraint updateConstant: [self.avatarSizeConstraint updateConstant:
self.avatarImageView.image.size.height * (self.visibility * 0.7f + 0.3f)]; self.avatarImageView.image.size.height * (self.visibility * 0.7f + 0.3f)];
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh]; [self.avatarRaisedConstraint withPriority:UILayoutPriorityDefaultHigh];
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow]; [self.avatarToTopConstraint withPriority:UILayoutPriorityDefaultLow];
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh]; [self.nameToCenterConstraint withPriority:UILayoutPriorityDefaultHigh];
self.nameContainer.visible = YES; self.nameContainer.visible = YES;
self.nameContainer.backgroundColor = [UIColor blackColor]; self.nameContainer.backgroundColor = [UIColor blackColor];
self.avatarImageView.visible = YES; self.avatarImageView.visible = YES;
@ -261,9 +261,9 @@ const long MPAvatarAdd = 10000;
case MPAvatarModeRaisedAndHidden: { case MPAvatarModeRaisedAndHidden: {
[self.avatarSizeConstraint updateConstant: [self.avatarSizeConstraint updateConstant:
self.avatarImageView.image.size.height * (self.visibility * 0.7f + 0.3f)]; self.avatarImageView.image.size.height * (self.visibility * 0.7f + 0.3f)];
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultHigh]; [self.avatarRaisedConstraint withPriority:UILayoutPriorityDefaultHigh];
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultLow]; [self.avatarToTopConstraint withPriority:UILayoutPriorityDefaultLow];
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh]; [self.nameToCenterConstraint withPriority:UILayoutPriorityDefaultHigh];
self.nameContainer.visible = NO; self.nameContainer.visible = NO;
self.nameContainer.backgroundColor = [UIColor blackColor]; self.nameContainer.backgroundColor = [UIColor blackColor];
self.avatarImageView.visible = NO; self.avatarImageView.visible = NO;
@ -271,9 +271,9 @@ const long MPAvatarAdd = 10000;
} }
case MPAvatarModeRaisedAndMinimized: { case MPAvatarModeRaisedAndMinimized: {
[self.avatarSizeConstraint updateConstant:36]; [self.avatarSizeConstraint updateConstant:36];
[self.avatarRaisedConstraint updatePriority:UILayoutPriorityDefaultLow]; [self.avatarRaisedConstraint withPriority:UILayoutPriorityDefaultLow];
[self.avatarToTopConstraint updatePriority:UILayoutPriorityDefaultHigh + 2]; [self.avatarToTopConstraint withPriority:UILayoutPriorityDefaultHigh + 2];
[self.nameToCenterConstraint updatePriority:UILayoutPriorityDefaultHigh]; [self.nameToCenterConstraint withPriority:UILayoutPriorityDefaultHigh];
self.nameContainer.visible = NO; self.nameContainer.visible = NO;
self.nameContainer.backgroundColor = [UIColor blackColor]; self.nameContainer.backgroundColor = [UIColor blackColor];
self.avatarImageView.visible = YES; self.avatarImageView.visible = YES;

View File

@ -56,16 +56,15 @@
BOOL traceEnabled = (BOOL)self.levelControl.selectedSegmentIndex; BOOL traceEnabled = (BOOL)self.levelControl.selectedSegmentIndex;
if (traceEnabled) { if (traceEnabled) {
[PearlAlert showAlertWithTitle:@"Enable Trace Mode?" message: UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Enable Trace Mode?" message:
@"Trace mode will log the internal operation of the application.\n" @"Trace mode will log the internal operation of the application.\n"
@"Unless you're looking for the cause of a problem, you should leave this off to save memory." @"Unless you're looking for the cause of a problem, you should leave this off to save memory."
viewStyle:UIAlertViewStyleDefault initAlert:nil preferredStyle:UIAlertControllerStyleAlert];
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { [controller addAction:[UIAlertAction actionWithTitle:@"Enable Trace" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
if (buttonIndex == [alert cancelButtonIndex]) [MPiOSConfig get].traceMode = @YES;
return; }]];
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
[MPiOSConfig get].traceMode = @YES; [self presentViewController:controller animated:YES completion:nil];
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Enable Trace", nil];
} }
else else
[MPiOSConfig get].traceMode = @NO; [MPiOSConfig get].traceMode = @NO;
@ -79,13 +78,14 @@
- (IBAction)mail:(UIBarButtonItem *)sender { - (IBAction)mail:(UIBarButtonItem *)sender {
if ([[MPiOSConfig get].traceMode boolValue]) { if ([[MPiOSConfig get].traceMode boolValue]) {
[PearlAlert showAlertWithTitle:@"Hiding Trace Messages" message: UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Hiding Trace Messages" message:
@"Trace-level log messages will not be mailed. " @"Trace-level log messages will not be mailed. "
@"These messages contain sensitive and personal information." @"These messages contain sensitive and personal information."
viewStyle:UIAlertViewStyleDefault initAlert:nil preferredStyle:UIAlertControllerStyleAlert];
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { [controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
[[MPiOSAppDelegate get] openFeedbackWithLogs:YES forVC:self]; [[MPiOSAppDelegate get] openFeedbackWithLogs:YES forVC:self];
} cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil]; }]];
[self presentViewController:controller animated:YES completion:nil];
} }
else else
[[MPiOSAppDelegate get] openFeedbackWithLogs:YES forVC:self]; [[MPiOSAppDelegate get] openFeedbackWithLogs:YES forVC:self];

View File

@ -41,7 +41,7 @@
[UIView animateWithDuration:0.6f delay:0 usingSpringWithDamping:0.75f initialSpringVelocity:1 [UIView animateWithDuration:0.6f delay:0 usingSpringWithDamping:0.75f initialSpringVelocity:1
options:UIViewAnimationOptionCurveEaseOut animations:^{ options:UIViewAnimationOptionCurveEaseOut animations:^{
[[passwordsVC.popdownToTopConstraint updatePriority:1] layoutIfNeeded]; [[passwordsVC.popdownToTopConstraint withPriority:1] layoutIfNeeded];
} completion:^(BOOL finished) { } completion:^(BOOL finished) {
[popdownVC didMoveToParentViewController:passwordsVC]; [popdownVC didMoveToParentViewController:passwordsVC];
@ -63,7 +63,7 @@
[popdownVC willMoveToParentViewController:nil]; [popdownVC willMoveToParentViewController:nil];
[UIView animateWithDuration:0.4f delay:0 options:UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionOverrideInheritedDuration [UIView animateWithDuration:0.4f delay:0 options:UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionOverrideInheritedDuration
animations:^{ animations:^{
[[passwordsVC.popdownToTopConstraint updatePriority:UILayoutPriorityDefaultHigh] layoutIfNeeded]; [[passwordsVC.popdownToTopConstraint withPriority:UILayoutPriorityDefaultHigh] layoutIfNeeded];
} completion:^(BOOL finished) { } completion:^(BOOL finished) {
[popdownVC.view removeFromSuperview]; [popdownVC.view removeFromSuperview];
[popdownVC removeFromParentViewController]; [popdownVC removeFromParentViewController];

View File

@ -114,11 +114,13 @@
if (cell == self.checkInconsistencies) if (cell == self.checkInconsistencies)
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
if ([[MPiOSAppDelegate get] findAndFixInconsistenciesSaveInContext:context] == MPFixableResultNoProblems) if ([[MPiOSAppDelegate get] findAndFixInconsistenciesSaveInContext:context] == MPFixableResultNoProblems) {
[PearlAlert showAlertWithTitle:@"No Inconsistencies" message: UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"No Inconsistencies" message:
@"No inconsistencies were detected in your sites." @"No inconsistencies were detected in your sites."
viewStyle:UIAlertViewStyleDefault initAlert:nil preferredStyle:UIAlertControllerStyleAlert];
tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil]; [controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleDefault handler:nil]];
[self.navigationController presentViewController:controller animated:YES completion:nil];
}
}]; }];
[tableView deselectRowAtIndexPath:indexPath animated:YES]; [tableView deselectRowAtIndexPath:indexPath animated:YES];

View File

@ -261,19 +261,20 @@
if (!site) if (!site)
return; return;
[PearlSheet showSheetWithTitle:strf( @"Delete %@?", site.name ) viewStyle:UIActionSheetStyleAutomatic UIAlertController *controller = [UIAlertController alertControllerWithTitle:strf( @"Delete %@?", site.name ) message:nil
initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) { preferredStyle:UIAlertControllerStyleActionSheet];
if (buttonIndex == [sheet cancelButtonIndex]) [controller addAction:[UIAlertAction actionWithTitle:@"Delete Site" style:UIAlertActionStyleDestructive
return; handler:^(UIAlertAction *_Nonnull action) {
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { MPSiteEntity *site_ = [self siteInContext:context];
MPSiteEntity *site_ = [self siteInContext:context]; if (site_) {
if (site_) { [context deleteObject:site_];
[context deleteObject:site_]; [context saveToStore];
[context saveToStore]; }
} }];
}]; }]];
} cancelTitle:@"Cancel" destructiveTitle:@"Delete Site" otherTitles:nil]; [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
[UIApp.keyWindow.rootViewController presentViewController:controller animated:YES completion:nil];
} }
- (IBAction)doChangeType:(UIButton *)sender { - (IBAction)doChangeType:(UIButton *)sender {
@ -281,29 +282,24 @@
[self setMode:MPPasswordCellModePassword animated:YES]; [self setMode:MPPasswordCellModePassword animated:YES];
MPSiteEntity *mainSite = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]]; MPSiteEntity *mainSite = [self siteInContext:[MPiOSAppDelegate managedObjectContextForMainThreadIfReady]];
[PearlSheet showSheetWithTitle:@"Change Password Type" viewStyle:UIActionSheetStyleAutomatic UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Change Password Type" message:nil
initSheet:^(UIActionSheet *sheet) { preferredStyle:UIAlertControllerStyleActionSheet];
for (NSNumber *typeNumber in [mainSite.algorithm allTypes]) { for (NSNumber *typeNumber in [mainSite.algorithm allTypes]) {
MPResultType type = (MPResultType)[typeNumber unsignedIntegerValue]; MPResultType type = (MPResultType)[typeNumber unsignedIntegerValue];
NSString *typeName = [mainSite.algorithm nameOfType:type]; NSString *typeName = [mainSite.algorithm nameOfType:type];
if (type == mainSite.type) NSString *title = type == mainSite.type? strf( @"● %@", typeName ): typeName;
[sheet addButtonWithTitle:strf( @"● %@", typeName )];
else
[sheet addButtonWithTitle:typeName];
}
} tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) {
if (buttonIndex == [sheet cancelButtonIndex])
return;
MPResultType type = (MPResultType)[[mainSite.algorithm allTypes][buttonIndex] unsignedIntegerValue]?: [controller addAction:[UIAlertAction actionWithTitle:title style:UIAlertActionStyleDefault handler:
mainSite.user.defaultType?: mainSite.algorithm.defaultType; ^(UIAlertAction *_Nonnull action) {
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { MPSiteEntity *site = [self siteInContext:context];
MPSiteEntity *site = [self siteInContext:context]; site = [[MPiOSAppDelegate get] changeSite:site saveInContext:context toType:type];
site = [[MPiOSAppDelegate get] changeSite:site saveInContext:context toType:type]; [self setSite:site animated:YES];
[self setSite:site animated:YES]; }];
}]; }]];
} cancelTitle:@"Cancel" destructiveTitle:nil otherTitles:nil]; }
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
[UIApp.keyWindow.rootViewController presentViewController:controller animated:YES completion:nil];
} }
- (IBAction)doEdit:(UIButton *)sender { - (IBAction)doEdit:(UIButton *)sender {
@ -370,24 +366,23 @@
[MPiOSAppDelegate managedObjectContextForMainThreadPerformBlock:^(NSManagedObjectContext *mainContext) { [MPiOSAppDelegate managedObjectContextForMainThreadPerformBlock:^(NSManagedObjectContext *mainContext) {
MPSiteEntity *mainSite = [self siteInContext:mainContext]; MPSiteEntity *mainSite = [self siteInContext:mainContext];
[PearlAlert showAlertWithTitle:@"Login Page" message:nil UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Login Page" message:nil
viewStyle:UIAlertViewStylePlainTextInput preferredStyle:UIAlertControllerStyleAlert];
initAlert:^(UIAlertView *alert, UITextField *firstField) { [controller addTextFieldWithConfigurationHandler:^(UITextField *textField) {
firstField.placeholder = strf( @"Login URL for %@", mainSite.name ); textField.placeholder = strf( @"Login URL for %@", mainSite.name );
firstField.text = mainSite.url; textField.text = mainSite.url;
} }];
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { [controller addAction:[UIAlertAction actionWithTitle:@"Save" style:UIAlertActionStyleDefault
if (buttonIndex == alert.cancelButtonIndex) handler:^(UIAlertAction *_Nonnull action) {
return; [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPSiteEntity *site = [self siteInContext:context];
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { NSURL *url = [NSURL URLWithString:controller.textFields.firstObject.text];
MPSiteEntity *site = [self siteInContext:context]; site.url = [url.host? url: nil absoluteString];
NSURL *url = [NSURL URLWithString:[alert textFieldAtIndex:0].text]; [context saveToStore];
site.url = [url.host? url: nil absoluteString]; }];
[context saveToStore]; }]];
}]; [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
} [UIApp.keyWindow.rootViewController presentViewController:controller animated:YES completion:nil];
cancelTitle:@"Cancel" otherTitles:@"Save", nil];
}]; }];
} }
@ -446,15 +441,11 @@
if (self.transientSite) { if (self.transientSite) {
[[UIResponder findFirstResponder] resignFirstResponder]; [[UIResponder findFirstResponder] resignFirstResponder];
[PearlAlert showAlertWithTitle:@"Create Site" UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Create Site" message:
message:strf( @"Remember site named:\n%@", self.transientSite ) strf( @"Remember site named:\n%@", self.transientSite )
viewStyle:UIAlertViewStyleDefault preferredStyle:UIAlertControllerStyleActionSheet];
initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { [controller addAction:[UIAlertAction actionWithTitle:@"Yes" style:UIAlertActionStyleDefault handler:
if (buttonIndex == [alert cancelButtonIndex]) { ^(UIAlertAction *_Nonnull action) {
self.contentButton.selected = NO;
return;
}
[[MPiOSAppDelegate get] [[MPiOSAppDelegate get]
addSiteNamed:self.transientSite completion:^(MPSiteEntity *site, NSManagedObjectContext *context) { addSiteNamed:self.transientSite completion:^(MPSiteEntity *site, NSManagedObjectContext *context) {
[self copyContentOfSite:site saveInContext:context]; [self copyContentOfSite:site saveInContext:context];
@ -465,7 +456,11 @@
}]; }];
} ); } );
}]; }];
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil]; }]];
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
self.contentButton.selected = NO;
}]];
[UIApp.keyWindow.rootViewController presentViewController:controller animated:YES completion:nil];
return; return;
} }
@ -677,7 +672,7 @@
[self.window endEditing:YES]; [self.window endEditing:YES];
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
if (@available(iOS 10.0, *)) { if (@available( iOS 10.0, * )) {
[pasteboard setItems:@[ @{ UIPasteboardTypeAutomatic: password } ] [pasteboard setItems:@[ @{ UIPasteboardTypeAutomatic: password } ]
options:@{ options:@{
UIPasteboardOptionLocalOnly : @NO, UIPasteboardOptionLocalOnly : @NO,

View File

@ -447,8 +447,8 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) {
_active = active; _active = active;
[UIView animateWithDuration:animated? 0.4f: 0 animations:^{ [UIView animateWithDuration:animated? 0.4f: 0 animations:^{
[self.navigationBarToTopConstraint updatePriority:active? 1: UILayoutPriorityDefaultHigh]; [self.navigationBarToTopConstraint withPriority:active? 1: UILayoutPriorityDefaultHigh];
[self.sitesToBottomConstraint updatePriority:active? 1: UILayoutPriorityDefaultHigh]; [self.sitesToBottomConstraint withPriority:active? 1: UILayoutPriorityDefaultHigh];
[self.view layoutIfNeeded]; [self.view layoutIfNeeded];
} completion:completion]; } completion:completion];
} }

View File

@ -146,15 +146,14 @@ PearlEnum( MPDevelopmentFuelConsumption,
- (IBAction)restorePurchases:(id)sender { - (IBAction)restorePurchases:(id)sender {
[PearlAlert showAlertWithTitle:@"Restore Previous Purchases" message: UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Restore Previous Purchases" message:
@"This will check with Apple to find and activate any purchases you made from other devices." @"This will check with Apple to find and activate any purchases you made from other devices."
viewStyle:UIAlertViewStyleDefault initAlert:nil preferredStyle:UIAlertControllerStyleAlert];
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { [controller addAction:[UIAlertAction actionWithTitle:@"Find Purchases" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
if (buttonIndex == [alert cancelButtonIndex]) [[MPAppDelegate_Shared get] restoreCompletedTransactions];
return; }]];
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
[[MPAppDelegate_Shared get] restoreCompletedTransactions]; [self presentViewController:controller animated:YES completion:nil];
} cancelTitle:@"Cancel" otherTitles:@"Find Purchases", nil];
} }
- (IBAction)sendThanks:(id)sender { - (IBAction)sendThanks:(id)sender {

View File

@ -432,33 +432,27 @@ referenceSizeForFooterInSection:(NSInteger)section {
return; return;
NSManagedObjectID *userID = user.permanentObjectID; NSManagedObjectID *userID = user.permanentObjectID;
[PearlSheet showSheetWithTitle:user.name UIAlertController *controller = [UIAlertController alertControllerWithTitle:user.name message:nil preferredStyle:UIAlertControllerStyleActionSheet];
viewStyle:UIActionSheetStyleBlackTranslucent [controller addAction:[UIAlertAction actionWithTitle:@"Delete User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
initSheet:nil tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) { UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Deleting User" message:
if (buttonIndex == [sheet cancelButtonIndex]) @"The user and its sites will be deleted." preferredStyle:UIAlertControllerStyleAlert];
return; [controller addAction:[UIAlertAction actionWithTitle:@"Delete User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
[self deleteUser:userID];
if (buttonIndex == [sheet destructiveButtonIndex]) { }]];
// Delete User [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
[PearlAlert showParentalGateWithTitle:@"Deleting User" message: [self presentViewController:controller animated:YES completion:nil];
@"The user and its sites will be deleted.\nPlease confirm by solving:" }]];
completion:^(BOOL continuing) { [controller addAction:[UIAlertAction actionWithTitle:@"Reset Password" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
if (continuing) UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Resetting User" message:
[self deleteUser:userID]; @"The user's master password will be reset." preferredStyle:UIAlertControllerStyleAlert];
}]; [controller addAction:[UIAlertAction actionWithTitle:@"Reset User" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
return; [self resetUser:userID avatar:avatarCell];
} }]];
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
if (buttonIndex == [sheet firstOtherButtonIndex]) [self presentViewController:controller animated:YES completion:nil];
// Reset Password }]];
[PearlAlert showParentalGateWithTitle:@"Resetting User" message: [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
@"The user's master password will be reset.\nPlease confirm by solving:" [self presentViewController:controller animated:YES completion:nil];
completion:^(BOOL continuing) {
if (continuing)
[self resetUser:userID avatar:avatarCell];
}];
} cancelTitle:[PearlStrings get].commonButtonCancel
destructiveTitle:@"Delete User" otherTitles:@"Reset Password", nil];
} }
} }

View File

@ -110,20 +110,24 @@
case MPFixableResultNoProblems: case MPFixableResultNoProblems:
break; break;
case MPFixableResultProblemsFixed: case MPFixableResultProblemsFixed: {
[PearlAlert showAlertWithTitle:@"Inconsistencies Fixed" message: UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Inconsistencies Fixed" message:
@"Some inconsistencies were detected in your sites.\n" @"Some inconsistencies were detected in your sites.\n"
@"All issues were fixed." @"All issues were fixed."
viewStyle:UIAlertViewStyleDefault initAlert:nil preferredStyle:UIAlertControllerStyleAlert];
tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil]; [controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:controller animated:YES completion:nil];
break; break;
case MPFixableResultProblemsNotFixed: }
[PearlAlert showAlertWithTitle:@"Inconsistencies Found" message: case MPFixableResultProblemsNotFixed: {
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Inconsistencies Found" message:
@"Some inconsistencies were detected in your sites.\n" @"Some inconsistencies were detected in your sites.\n"
@"Not all issues could be fixed. Try signing in to each user or checking the logs." @"Not all issues could be fixed. Try signing in to each user or checking the logs."
viewStyle:UIAlertViewStyleDefault initAlert:nil preferredStyle:UIAlertControllerStyleAlert];
tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil]; [controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:controller animated:YES completion:nil];
break; break;
}
} }
} ); } );
@ -133,12 +137,14 @@
} ); } );
NSString *latestFeatures = [MPStoreViewController latestStoreFeatures]; NSString *latestFeatures = [MPStoreViewController latestStoreFeatures];
if (latestFeatures) if (latestFeatures) {
[PearlAlert showAlertWithTitle:@"New Features" message: UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"New Features" message:
strf( @"The following features are now available in the store:\n\n%@•••\n\n" strf( @"The following features are now available in the store:\n\n%@•••\n\n"
@"Find the store from the user pulldown after logging in.", latestFeatures ) @"Find the store from the user pulldown after logging in.", latestFeatures )
viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:nil preferredStyle:UIAlertControllerStyleAlert];
cancelTitle:@"Thanks" otherTitles:nil]; [controller addAction:[UIAlertAction actionWithTitle:@"Thanks" style:UIAlertActionStyleCancel handler:nil]];
[self.navigationController presentViewController:controller animated:YES completion:nil];
}
} }
@catch (id exception) { @catch (id exception) {
err( @"During Post-Startup: %@", exception ); err( @"During Post-Startup: %@", exception );
@ -161,14 +167,22 @@
MPError( error, @"While reading imported sites from %@.", url ); MPError( error, @"While reading imported sites from %@.", url );
if (!importedSitesData) { if (!importedSitesData) {
[PearlAlert showError:strf( @"Master Password couldn't read the import sites.\n\n%@", UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Error" message:
[error localizedDescription]?: error )]; strf( @"Master Password couldn't read the import sites.\n\n%@",
(id)[error localizedDescription]?: error )
preferredStyle:UIAlertControllerStyleAlert];
[controller addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
[self.navigationController presentViewController:controller animated:YES completion:nil];
return; return;
} }
NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding]; NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding];
if (!importedSitesString) { if (!importedSitesString) {
[PearlAlert showError:@"Master Password couldn't understand the import file."]; UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Error" message:
@"Master Password couldn't understand the import file."
preferredStyle:UIAlertControllerStyleAlert];
[controller addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
[self.navigationController presentViewController:controller animated:YES completion:nil];
return; return;
} }
@ -190,33 +204,45 @@
PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:@"Importing"]; PearlOverlay *activityOverlay = [PearlOverlay showProgressOverlayWithTitle:@"Importing"];
[self importSites:importData askImportPassword:^NSString *(NSString *userName) { [self importSites:importData askImportPassword:^NSString *(NSString *userName) {
return PearlAwait( ^(void (^setResult)(id)) { return PearlAwait( ^(void (^setResult)(id)) {
[PearlAlert showAlertWithTitle:strf( @"Importing Sites For\n%@", userName ) UIAlertController *controller = [UIAlertController alertControllerWithTitle:strf( @"Importing Sites For\n%@", userName ) message:
message:@"Enter the master password used to create this export file." @"Enter the master password used to create this export file."
viewStyle:UIAlertViewStyleSecureTextInput preferredStyle:UIAlertControllerStyleAlert];
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) { [controller addTextFieldWithConfigurationHandler:^(UITextField *textField) {
if (buttonIndex_ == [alert_ cancelButtonIndex]) textField.secureTextEntry = YES;
setResult( nil ); }];
else [controller addAction:[UIAlertAction actionWithTitle:@"Import" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
setResult( [alert_ textFieldAtIndex:0].text ); setResult( controller.textFields.firstObject.text );
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Import", nil]; }]];
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
setResult( nil );
}]];
[self.navigationController presentViewController:controller animated:YES completion:nil];
} ); } );
} askUserPassword:^NSString *(NSString *userName) { } askUserPassword:^NSString *(NSString *userName) {
return PearlAwait( (id)^(void (^setResult)(id)) { return PearlAwait( (id)^(void (^setResult)(id)) {
[PearlAlert showAlertWithTitle:strf( @"Master Password For\n%@", userName ) UIAlertController *controller = [UIAlertController alertControllerWithTitle:strf( @"Master Password For\n%@", userName ) message:
message:@"Enter the current master password for this user." @"Enter the current master password for this user."
viewStyle:UIAlertViewStyleSecureTextInput preferredStyle:UIAlertControllerStyleAlert];
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) { [controller addTextFieldWithConfigurationHandler:^(UITextField *textField) {
if (buttonIndex_ == [alert_ cancelButtonIndex]) textField.secureTextEntry = YES;
setResult( nil ); }];
else [controller addAction:[UIAlertAction actionWithTitle:@"Import" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
setResult( [alert_ textFieldAtIndex:0].text ); setResult( controller.textFields.firstObject.text );
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Import", nil]; }]];
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
setResult( nil );
}]];
[self.navigationController presentViewController:controller animated:YES completion:nil];
} ); } );
} result:^(NSError *error) { } result:^(NSError *error) {
[activityOverlay cancelOverlayAnimated:YES]; [activityOverlay cancelOverlayAnimated:YES];
if (error && !(error.domain == NSCocoaErrorDomain && error.code == NSUserCancelledError)) if (error && !(error.domain == NSCocoaErrorDomain && error.code == NSUserCancelledError)) {
[PearlAlert showError:error.localizedDescription]; UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Error" message:[error localizedDescription]
preferredStyle:UIAlertControllerStyleAlert];
[controller addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
[self.navigationController presentViewController:controller animated:YES completion:nil];
}
}]; }];
} }
@ -237,17 +263,17 @@
PearlNotMainQueue( ^{ PearlNotMainQueue( ^{
NSString *importData = [UIPasteboard generalPasteboard].string; NSString *importData = [UIPasteboard generalPasteboard].string;
MPMarshalInfo *importInfo = mpw_marshal_read_info( importData.UTF8String ); MPMarshalInfo *importInfo = mpw_marshal_read_info( importData.UTF8String );
if (importInfo->format != MPMarshalFormatNone) if (importInfo->format != MPMarshalFormatNone) {
[PearlAlert showAlertWithTitle:@"Import Sites?" message: UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Import Sites?" message:
@"We've detected Master Password import sites on your pasteboard, would you like to import them?" @"We've detected Master Password import sites on your pasteboard, would you like to import them?"
viewStyle:UIAlertViewStyleDefault initAlert:nil preferredStyle:UIAlertControllerStyleAlert];
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { [controller addAction:[UIAlertAction actionWithTitle:@"Import Sites" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
if (buttonIndex == [alert cancelButtonIndex]) [self importSites:importData];
return; [UIPasteboard generalPasteboard].string = @"";
}]];
[self importSites:importData]; [controller addAction:[UIAlertAction actionWithTitle:@"No" style:UIAlertActionStyleCancel handler:nil]];
[UIPasteboard generalPasteboard].string = @""; [self.navigationController presentViewController:controller animated:YES completion:nil];
} cancelTitle:@"No" otherTitles:@"Import Sites", nil]; }
mpw_marshal_info_free( &importInfo ); mpw_marshal_info_free( &importInfo );
} ); } );
@ -314,26 +340,29 @@
- (void)showFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController { - (void)showFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController {
if (![PearlEMail canSendMail]) if (![PearlEMail canSendMail]) {
[PearlAlert showAlertWithTitle:@"Feedback" UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Feedback" message:
message: @"Have a question, comment, issue or just saying thanks?\n\n"
@"Have a question, comment, issue or just saying thanks?\n\n" @"We'd love to hear what you think!\n"
@"We'd love to hear what you think!\n" @"masterpassword@lyndir.com"
@"masterpassword@lyndir.com" preferredStyle:UIAlertControllerStyleAlert];
viewStyle:UIAlertViewStyleDefault [controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
initAlert:nil tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay [self.navigationController presentViewController:controller animated:YES completion:nil];
otherTitles:nil]; }
else if (logs) {
else if (logs) UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Feedback" message:
[PearlAlert showAlertWithTitle:@"Feedback" @"Have a question, comment, issue or just saying thanks?\n\n"
message: @"If you're having trouble, it may help us if you can first reproduce the problem "
@"Have a question, comment, issue or just saying thanks?\n\n" @"and then include log files in your message."
@"If you're having trouble, it may help us if you can first reproduce the problem " preferredStyle:UIAlertControllerStyleAlert];
@"and then include log files in your message." [controller addAction:[UIAlertAction actionWithTitle:@"Include Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
viewStyle:UIAlertViewStyleDefault [self openFeedbackWithLogs:YES forVC:viewController];
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) { }]];
[self openFeedbackWithLogs:(buttonIndex_ == [alert_ firstOtherButtonIndex]) forVC:viewController]; [controller addAction:[UIAlertAction actionWithTitle:@"No Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
} cancelTitle:nil otherTitles:@"Include Logs", @"No Logs", nil]; [self openFeedbackWithLogs:NO forVC:viewController];
}]];
[self.navigationController presentViewController:controller animated:YES completion:nil];
}
else else
[self openFeedbackWithLogs:NO forVC:viewController]; [self openFeedbackWithLogs:NO forVC:viewController];
} }
@ -349,9 +378,9 @@
subject:strf( @"Feedback for Master Password [%@]", subject:strf( @"Feedback for Master Password [%@]",
[[PearlKeyChain deviceIdentifier] stringByDeletingMatchesOf:@"-.*"] ) [[PearlKeyChain deviceIdentifier] stringByDeletingMatchesOf:@"-.*"] )
body:strf( @"\n\n\n" body:strf( @"\n\n\n"
@"--\n" @"--\n"
@"%@" @"%@"
@"Master Password %@, build %@", @"Master Password %@, build %@",
userName? ([userName stringByAppendingString:@"\n"]): @"", userName? ([userName stringByAppendingString:@"\n"]): @"",
[PearlInfoPlist get].CFBundleShortVersionString, [PearlInfoPlist get].CFBundleShortVersionString,
[PearlInfoPlist get].CFBundleVersion ) [PearlInfoPlist get].CFBundleVersion )
@ -372,173 +401,163 @@
static dispatch_once_t once = 0; static dispatch_once_t once = 0;
dispatch_once( &once, ^{ dispatch_once( &once, ^{
[PearlAlert showAlertWithTitle:@"Failed To Load Sites" message: UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Failed To Load Sites" message:
@"Master Password was unable to open your sites history.\n" @"Master Password was unable to open your sites history.\n"
@"This may be due to corruption. You can either reset Master Password and " @"This may be due to corruption. You can either reset Master Password and "
@"recreate your user, or E-Mail us your logs and leave your corrupt store as-is for now." @"recreate your user, or E-Mail us your logs and leave your corrupt store as-is for now."
viewStyle:UIAlertViewStyleDefault initAlert:nil preferredStyle:UIAlertControllerStyleAlert];
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { [controller addAction:[UIAlertAction actionWithTitle:@"E-Mail Logs" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
if (buttonIndex == [alert cancelButtonIndex]) [self openFeedbackWithLogs:YES forVC:nil];
return; }]];
if (buttonIndex == [alert firstOtherButtonIndex]) [controller addAction:[UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
[self openFeedbackWithLogs:YES forVC:nil]; [self deleteAndResetStore];
if (buttonIndex == [alert firstOtherButtonIndex] + 1) }]];
[self deleteAndResetStore]; [controller addAction:[UIAlertAction actionWithTitle:@"Ignore" style:UIAlertActionStyleCancel handler:nil]];
} cancelTitle:@"Ignore" otherTitles:@"E-Mail Logs", @"Reset", nil]; [self.navigationController presentViewController:controller animated:YES completion:nil];
} ); } );
} }
- (void)showExportForVC:(UIViewController *)viewController { - (void)showExportForVC:(UIViewController *)viewController {
[PearlAlert showAlertWithTitle:@"Exporting Your Sites" UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Exporting Your Sites" message:
message:@"An export is great for keeping a " @"An export is great for keeping a backup list of your accounts.\n\n"
@"backup list of your accounts.\n\n" @"When the file is ready, you will be able to mail it to yourself.\n"
@"When the file is ready, you will be " @"You can open it with a text editor or with Master Password if you need to restore your list of sites."
@"able to mail it to yourself.\n" preferredStyle:UIAlertControllerStyleAlert];
@"You can open it with a text editor or " [controller addAction:[UIAlertAction actionWithTitle:@"Export Sites" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
@"with Master Password if you need to " UIAlertController *controller_ = [UIAlertController alertControllerWithTitle:@"Show Passwords?" message:
@"restore your list of sites." @"Would you like to make all your passwords visible in the export file?\n\n"
viewStyle:UIAlertViewStyleDefault initAlert:nil @"A safe export will include all sites but make their passwords invisible.\n"
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { @"It is great as a backup and remains safe when fallen in the wrong hands."
if (buttonIndex != [alert cancelButtonIndex]) preferredStyle:UIAlertControllerStyleAlert];
[PearlAlert showAlertWithTitle:@"Show Passwords?" [controller_ addAction:[UIAlertAction actionWithTitle:@"Safe Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
message:@"Would you like to make all your passwords " [self showExportRevealPasswords:NO forVC:viewController];
@"visible in the export file?\n\n" }]];
@"A safe export will include all sites " [controller_ addAction:[UIAlertAction actionWithTitle:@"Show Passwords" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
@"but make their passwords invisible.\n" [self showExportRevealPasswords:YES forVC:viewController];
@"It is great as a backup and remains " }]];
@"safe when fallen in the wrong hands." [controller_ addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
viewStyle:UIAlertViewStyleDefault initAlert:nil [self.navigationController presentViewController:controller_ animated:YES completion:nil];
tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) { }]];
if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 0) [controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
// Safe Export [self.navigationController presentViewController:controller animated:YES completion:nil];
[self showExportRevealPasswords:NO forVC:viewController];
if (buttonIndex_ == [alert_ firstOtherButtonIndex] + 1)
// Show Passwords
[self showExportRevealPasswords:YES forVC:viewController];
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Safe Export", @"Show Passwords",
nil];
} cancelTitle:@"Cancel" otherTitles:@"Export Sites", nil];
} }
- (void)showExportRevealPasswords:(BOOL)revealPasswords forVC:(UIViewController *)viewController { - (void)showExportRevealPasswords:(BOOL)revealPasswords forVC:(UIViewController *)viewController {
if (![PearlEMail canSendMail]) { if (![PearlEMail canSendMail]) {
[PearlAlert showAlertWithTitle:@"Cannot Send Mail" UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Cannot Send Mail" message:
message: @"Your device is not yet set up for sending mail.\n"
@"Your device is not yet set up for sending mail.\n" @"Close Master Password, go into Settings and add a Mail account."
@"Close Master Password, go into Settings and add a Mail account." preferredStyle:UIAlertControllerStyleAlert];
viewStyle:UIAlertViewStyleDefault [controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
initAlert:nil tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay [self.navigationController presentViewController:controller animated:YES completion:nil];
otherTitles:nil];
return; return;
} }
[self exportSitesRevealPasswords:revealPasswords askExportPassword:^NSString *(NSString *userName) { [self exportSitesRevealPasswords:revealPasswords askExportPassword:^NSString *(NSString *userName) {
return PearlAwait( ^(void (^setResult)(id)) { return PearlAwait( ^(void (^setResult)(id)) {
[PearlAlert showAlertWithTitle:strf( @"Master Password For:\n%@", userName ) UIAlertController *controller = [UIAlertController alertControllerWithTitle:strf( @"Master Password For:\n%@", userName ) message:
message:@"Enter the user's master password to create an export file." @"Enter the user's master password to create an export file."
viewStyle:UIAlertViewStyleSecureTextInput preferredStyle:UIAlertControllerStyleAlert];
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) { [controller addTextFieldWithConfigurationHandler:^(UITextField *textField) {
if (buttonIndex_ == [alert_ cancelButtonIndex]) textField.secureTextEntry = YES;
setResult( nil ); }];
else [controller addAction:[UIAlertAction actionWithTitle:@"Export" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
setResult( [alert_ textFieldAtIndex:0].text ); setResult( controller.textFields.firstObject.text );
} cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Export", nil]; }]];
[controller addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
setResult( nil );
}]];
[self.navigationController presentViewController:controller animated:YES completion:nil];
} ); } );
} result:^(NSString *mpsites, NSError *error) { } result:^(NSString *mpsites, NSError *error) {
if (!mpsites || error) { if (!mpsites || error) {
MPError( error, @"Failed to export mpsites." ); MPError( error, @"Failed to export mpsites." );
[PearlAlert showAlertWithTitle:@"Export Error" UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Export Error" message:[error localizedDescription]
message:error.localizedDescription preferredStyle:UIAlertControllerStyleAlert];
viewStyle:UIAlertViewStyleDefault [controller addAction:[UIAlertAction actionWithTitle:@"Okay" style:UIAlertActionStyleCancel handler:nil]];
initAlert:nil tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay [self.navigationController presentViewController:controller animated:YES completion:nil];
otherTitles:nil];
return; return;
} }
[PearlSheet showSheetWithTitle:@"Export Destination" viewStyle:UIActionSheetStyleBlackTranslucent initSheet:nil NSDateFormatter *exportDateFormatter = [NSDateFormatter new];
tappedButtonBlock:^(UIActionSheet *sheet, NSInteger buttonIndex) { [exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
if (buttonIndex == [sheet cancelButtonIndex]) NSString *exportFileName = strf( @"%@ (%@).mpsites",
return; [self activeUserForMainThread].name, [exportDateFormatter stringFromDate:[NSDate date]] );
NSDateFormatter *exportDateFormatter = [NSDateFormatter new]; UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Export Destination" message:nil
[exportDateFormatter setDateFormat:@"yyyy'-'MM'-'dd"]; preferredStyle:UIAlertControllerStyleActionSheet];
NSString *exportFileName = strf( @"%@ (%@).mpsites", [controller addAction:[UIAlertAction actionWithTitle:@"Send As E-Mail" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
[self activeUserForMainThread].name, [exportDateFormatter stringFromDate:[NSDate date]] ); NSString *message;
if (revealPasswords)
message = strf( @"Export of Master Password sites with passwords included.\n\n"
@"REMINDER: Make sure nobody else sees this file! Passwords are visible!\n\n\n"
@"--\n"
@"%@\n"
@"Master Password %@, build %@",
[self activeUserForMainThread].name,
[PearlInfoPlist get].CFBundleShortVersionString,
[PearlInfoPlist get].CFBundleVersion );
else
message = strf( @"Backup of Master Password sites.\n\n\n"
@"--\n"
@"%@\n"
@"Master Password %@, build %@",
[self activeUserForMainThread].name,
[PearlInfoPlist get].CFBundleShortVersionString,
[PearlInfoPlist get].CFBundleVersion );
if (buttonIndex == [sheet firstOtherButtonIndex]) { [PearlEMail sendEMailTo:nil fromVC:viewController subject:@"Master Password Export" body:message
NSString *message; attachments:[[PearlEMailAttachment alloc]
if (revealPasswords) initWithContent:[mpsites dataUsingEncoding:NSUTF8StringEncoding]
message = strf( @"Export of Master Password sites with passwords included.\n\n" mimeType:@"text/plain" fileName:exportFileName],
@"REMINDER: Make sure nobody else sees this file! Passwords are visible!\n\n\n" nil];
@"--\n" return;
@"%@\n" }]];
@"Master Password %@, build %@", [controller addAction:[UIAlertAction actionWithTitle:@"Share / Airdrop" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
[self activeUserForMainThread].name, NSURL *applicationSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory
[PearlInfoPlist get].CFBundleShortVersionString, inDomains:NSUserDomainMask] lastObject];
[PearlInfoPlist get].CFBundleVersion ); NSURL *exportURL = [[applicationSupportURL
else URLByAppendingPathComponent:[NSBundle mainBundle].bundleIdentifier isDirectory:YES]
message = strf( @"Backup of Master Password sites.\n\n\n" URLByAppendingPathComponent:exportFileName isDirectory:NO];
@"--\n" NSError *writeError = nil;
@"%@\n" if (![[mpsites dataUsingEncoding:NSUTF8StringEncoding]
@"Master Password %@, build %@", writeToURL:exportURL options:NSDataWritingFileProtectionComplete error:&writeError])
[self activeUserForMainThread].name, MPError( writeError, @"Failed to write export data to URL %@.", exportURL );
[PearlInfoPlist get].CFBundleShortVersionString, else {
[PearlInfoPlist get].CFBundleVersion ); self.interactionController = [UIDocumentInteractionController interactionControllerWithURL:exportURL];
self.interactionController.UTI = @"com.lyndir.masterpassword.sites";
[PearlEMail sendEMailTo:nil fromVC:viewController subject:@"Master Password Export" body:message self.interactionController.delegate = self;
attachments:[[PearlEMailAttachment alloc] [self.interactionController presentOpenInMenuFromRect:CGRectZero inView:viewController.view animated:YES];
initWithContent:[mpsites dataUsingEncoding:NSUTF8StringEncoding] }
mimeType:@"text/plain" fileName:exportFileName], }]];
nil]; [controller addAction:[UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleCancel handler:nil]];
return; [self.navigationController presentViewController:controller animated:YES completion:nil];
}
NSURL *applicationSupportURL = [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory
inDomains:NSUserDomainMask] lastObject];
NSURL *exportURL = [[applicationSupportURL
URLByAppendingPathComponent:[NSBundle mainBundle].bundleIdentifier isDirectory:YES]
URLByAppendingPathComponent:exportFileName isDirectory:NO];
NSError *writeError = nil;
if (![[mpsites dataUsingEncoding:NSUTF8StringEncoding]
writeToURL:exportURL options:NSDataWritingFileProtectionComplete error:&writeError])
MPError( writeError, @"Failed to write export data to URL %@.", exportURL );
else {
self.interactionController = [UIDocumentInteractionController interactionControllerWithURL:exportURL];
self.interactionController.UTI = @"com.lyndir.masterpassword.sites";
self.interactionController.delegate = self;
[self.interactionController presentOpenInMenuFromRect:CGRectZero inView:viewController.view animated:YES];
}
} cancelTitle:@"Cancel" destructiveTitle:nil otherTitles:@"Send As E-Mail", @"Share / Airdrop", nil];
}]; }];
} }
- (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset { - (void)changeMasterPasswordFor:(MPUserEntity *)user saveInContext:(NSManagedObjectContext *)moc didResetBlock:(void ( ^ )(void))didReset {
[PearlAlert showAlertWithTitle:@"Changing Master Password" UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Changing Master Password" message:
message: @"If you continue, you'll be able to set a new master password.\n\n"
@"If you continue, you'll be able to set a new master password.\n\n" @"Changing your master password will cause all your generated passwords to change!\n"
@"Changing your master password will cause all your generated passwords to change!\n" @"Changing the master password back to the old one will cause your passwords to revert as well."
@"Changing the master password back to the old one will cause your passwords to revert as well." preferredStyle:UIAlertControllerStyleAlert];
viewStyle:UIAlertViewStyleDefault [controller addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { [moc performBlockAndWait:^{
if (buttonIndex == [alert cancelButtonIndex]) inf( @"Clearing keyID for user: %@.", user.userID );
return; user.keyID = nil;
[self forgetSavedKeyFor:user];
[moc saveToStore];
}];
[moc performBlockAndWait:^{ [self signOutAnimated:YES];
inf( @"Clearing keyID for user: %@.", user.userID ); if (didReset)
user.keyID = nil; didReset();
[self forgetSavedKeyFor:user]; }]];
[moc saveToStore]; [controller addAction:[UIAlertAction actionWithTitle:@"Abort" style:UIAlertActionStyleCancel handler:nil]];
}]; [self.navigationController presentViewController:controller animated:YES completion:nil];
[self signOutAnimated:YES];
if (didReset)
didReset();
}
cancelTitle:[PearlStrings get].commonButtonAbort
otherTitles:[PearlStrings get].commonButtonContinue, nil];
} }
#pragma mark - UIDocumentInteractionControllerDelegate #pragma mark - UIDocumentInteractionControllerDelegate

View File

@ -1,133 +1,135 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>M. Password</string> <string>M. Password</string>
<key>CFBundleDocumentTypes</key> <key>CFBundleDocumentTypes</key>
<array> <array>
<dict> <dict>
<key>CFBundleTypeExtensions</key> <key>CFBundleTypeExtensions</key>
<array> <array>
<string>mpsites</string> <string>mpsites</string>
</array> </array>
<key>CFBundleTypeIconFiles</key> <key>CFBundleTypeIconFiles</key>
<array> <array>
<string>Icon-Small</string> <string>Icon-Small</string>
</array> </array>
<key>CFBundleTypeName</key> <key>CFBundleTypeName</key>
<string>Master Password sites</string> <string>Master Password sites</string>
<key>LSHandlerRank</key> <key>LSHandlerRank</key>
<string>Owner</string> <string>Owner</string>
<key>LSItemContentTypes</key> <key>LSItemContentTypes</key>
<array> <array>
<string>com.lyndir.masterpassword.sites</string> <string>com.lyndir.masterpassword.sites</string>
</array> </array>
</dict> </dict>
</array> </array>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string> <string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>[auto]</string> <string>[auto]</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>[auto]</string> <string>[auto]</string>
<key>Fabric</key> <key>Fabric</key>
<dict> <dict>
<key>APIKey</key> <key>APIKey</key>
<string>0d10c90776f5ef5acd01ddbeaca9a6cba4814560</string> <string>0d10c90776f5ef5acd01ddbeaca9a6cba4814560</string>
<key>Kits</key> <key>Kits</key>
<array> <array>
<dict> <dict>
<key>KitInfo</key> <key>KitInfo</key>
<dict/> <dict/>
<key>KitName</key> <key>KitName</key>
<string>Crashlytics</string> <string>Crashlytics</string>
</dict> </dict>
</array> </array>
</dict> </dict>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>© 2011-2018</string> <string>© 2011-2018</string>
<key>UIAppFonts</key> <key>UIAppFonts</key>
<array> <array>
<string>Exo2.0-Bold.otf</string> <string>Exo2.0-Bold.otf</string>
<string>Exo2.0-ExtraBold.otf</string> <string>Exo2.0-ExtraBold.otf</string>
<string>Exo2.0-Regular.otf</string> <string>Exo2.0-Regular.otf</string>
<string>Exo2.0-Thin.otf</string> <string>Exo2.0-Thin.otf</string>
<string>SourceCodePro-Black.otf</string> <string>SourceCodePro-Black.otf</string>
<string>SourceCodePro-Regular.otf</string> <string>SourceCodePro-Regular.otf</string>
<string>SourceCodePro-ExtraLight.otf</string> <string>SourceCodePro-ExtraLight.otf</string>
</array> </array>
<key>UIStatusBarHidden</key> <key>UIMainStoryboardFile</key>
<true/> <string>Storyboard</string>
<key>UIStatusBarStyle</key> <key>UIStatusBarHidden</key>
<string>UIStatusBarStyleDefault</string> <true/>
<key>UIStatusBarTintParameters</key> <key>UIStatusBarStyle</key>
<dict> <string>UIStatusBarStyleDefault</string>
<key>UINavigationBar</key> <key>UIStatusBarTintParameters</key>
<dict> <dict>
<key>Style</key> <key>UINavigationBar</key>
<string>UIBarStyleDefault</string> <dict>
<key>TintColor</key> <key>Style</key>
<dict> <string>UIBarStyleDefault</string>
<key>Blue</key> <key>TintColor</key>
<real>0.42745098039215684</real> <dict>
<key>Green</key> <key>Blue</key>
<real>0.39215686274509803</real> <real>0.42745098039215684</real>
<key>Red</key> <key>Green</key>
<real>0.37254901960784315</real> <real>0.39215686274509803</real>
</dict> <key>Red</key>
<key>Translucent</key> <real>0.37254901960784315</real>
<false/> </dict>
</dict> <key>Translucent</key>
</dict> <false/>
<key>UISupportedInterfaceOrientations</key> </dict>
<array> </dict>
<string>UIInterfaceOrientationPortrait</string> <key>UISupportedInterfaceOrientations</key>
<string>UIInterfaceOrientationLandscapeLeft</string> <array>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationPortrait</string>
</array> <string>UIInterfaceOrientationLandscapeLeft</string>
<key>UISupportedInterfaceOrientations~ipad</key> <string>UIInterfaceOrientationLandscapeRight</string>
<array> </array>
<string>UIInterfaceOrientationPortrait</string> <key>UISupportedInterfaceOrientations~ipad</key>
<string>UIInterfaceOrientationPortraitUpsideDown</string> <array>
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationPortraitUpsideDown</string>
</array> <string>UIInterfaceOrientationLandscapeLeft</string>
<key>UTExportedTypeDeclarations</key> <string>UIInterfaceOrientationLandscapeRight</string>
<array> </array>
<dict> <key>UTExportedTypeDeclarations</key>
<key>UTTypeConformsTo</key> <array>
<array> <dict>
<string>public.utf8-plain-text</string> <key>UTTypeConformsTo</key>
</array> <array>
<key>UTTypeDescription</key> <string>public.utf8-plain-text</string>
<string>Master Password sites</string> </array>
<key>UTTypeIdentifier</key> <key>UTTypeDescription</key>
<string>com.lyndir.masterpassword.sites</string> <string>Master Password sites</string>
<key>UTTypeSize320IconFile</key> <key>UTTypeIdentifier</key>
<string>Icon-320.png</string> <string>com.lyndir.masterpassword.sites</string>
<key>UTTypeSize64IconFile</key> <key>UTTypeSize320IconFile</key>
<string>Icon-64.png</string> <string>Icon-320.png</string>
<key>UTTypeTagSpecification</key> <key>UTTypeSize64IconFile</key>
<dict> <string>Icon-64.png</string>
<key>public.filename-extension</key> <key>UTTypeTagSpecification</key>
<array> <dict>
<string>mpsites</string> <key>public.filename-extension</key>
</array> <array>
</dict> <string>mpsites</string>
</dict> </array>
</array> </dict>
</dict> </dict>
</array>
</dict>
</plist> </plist>

View File

@ -25,6 +25,7 @@
#include "mpw-types.h" #include "mpw-types.h"
//// Logging. //// Logging.
#ifndef trc
extern int mpw_verbosity; extern int mpw_verbosity;
#ifndef mpw_log_do #ifndef mpw_log_do
@ -39,7 +40,6 @@ extern int mpw_verbosity;
}; } while (0) }; } while (0)
#endif #endif
#ifndef trc
/** Logging internal state. */ /** Logging internal state. */
#define trc_level 3 #define trc_level 3
#define trc(format, ...) mpw_log( trc_level, format, ##__VA_ARGS__ ) #define trc(format, ...) mpw_log( trc_level, format, ##__VA_ARGS__ )