Import improvements and core data fixes.
[FIXED] Import fixes: - Wait for MOC to become available. - Progress UI while working. - Import files exported with a different master password. - Core Data crashes. [RENAMED] Site's User name -> Login name. [FIXED] Core Data crashes related to using entities from old MOCs.
This commit is contained in:
parent
479d357bd1
commit
75ef15bb4d
Binary file not shown.
Binary file not shown.
2
External/Pearl
vendored
2
External/Pearl
vendored
@ -1 +1 @@
|
|||||||
Subproject commit cc97c1be4c0f2ee0080af417940244ac8f3e5f47
|
Subproject commit 5a35cdb73c57c65f22959accab2f6ddbeeee0b33
|
@ -17,10 +17,6 @@
|
|||||||
DA0A1D1515690AF40092735D /* Icon-72@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0A1D1315690AF30092735D /* Icon-72@2x.png */; };
|
DA0A1D1515690AF40092735D /* Icon-72@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0A1D1315690AF30092735D /* Icon-72@2x.png */; };
|
||||||
DA0A1D1615690AF40092735D /* Icon-Small-50@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0A1D1415690AF40092735D /* Icon-Small-50@2x.png */; };
|
DA0A1D1615690AF40092735D /* Icon-Small-50@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = DA0A1D1415690AF40092735D /* Icon-Small-50@2x.png */; };
|
||||||
DA0E07961577FE490008A67E /* MPEntities.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0E07951577FE490008A67E /* MPEntities.m */; };
|
DA0E07961577FE490008A67E /* MPEntities.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0E07951577FE490008A67E /* MPEntities.m */; };
|
||||||
DA0F9F3315B55397007ED9BC /* MPUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0F9F3215B55397007ED9BC /* MPUserEntity.m */; };
|
|
||||||
DA0F9F3615B55397007ED9BC /* MPElementGeneratedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0F9F3515B55397007ED9BC /* MPElementGeneratedEntity.m */; };
|
|
||||||
DA0F9F3915B55397007ED9BC /* MPElementStoredEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0F9F3815B55397007ED9BC /* MPElementStoredEntity.m */; };
|
|
||||||
DA0F9F3C15B55397007ED9BC /* MPElementEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA0F9F3B15B55397007ED9BC /* MPElementEntity.m */; };
|
|
||||||
DA30E9CE15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA30E9CB15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h */; };
|
DA30E9CE15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA30E9CB15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h */; };
|
||||||
DA30E9CF15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CC15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m */; };
|
DA30E9CF15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CC15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m */; };
|
||||||
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CD15722ECA00A68B4C /* Pearl.m */; };
|
DA30E9D015722ECA00A68B4C /* Pearl.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30E9CD15722ECA00A68B4C /* Pearl.m */; };
|
||||||
@ -95,6 +91,10 @@
|
|||||||
DA95D5F614DF0B9F008D1B94 /* IASKPSTextFieldSpecifierViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA95D5CC14DF0691008D1B94 /* IASKPSTextFieldSpecifierViewCell.xib */; };
|
DA95D5F614DF0B9F008D1B94 /* IASKPSTextFieldSpecifierViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA95D5CC14DF0691008D1B94 /* IASKPSTextFieldSpecifierViewCell.xib */; };
|
||||||
DA95D5F714DF0B9F008D1B94 /* IASKPSToggleSwitchSpecifierViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA95D5CD14DF0691008D1B94 /* IASKPSToggleSwitchSpecifierViewCell.xib */; };
|
DA95D5F714DF0B9F008D1B94 /* IASKPSToggleSwitchSpecifierViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA95D5CD14DF0691008D1B94 /* IASKPSToggleSwitchSpecifierViewCell.xib */; };
|
||||||
DA95D5F814DF0B9F008D1B94 /* IASKSpecifierValuesView.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA95D5CE14DF0691008D1B94 /* IASKSpecifierValuesView.xib */; };
|
DA95D5F814DF0B9F008D1B94 /* IASKSpecifierValuesView.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA95D5CE14DF0691008D1B94 /* IASKSpecifierValuesView.xib */; };
|
||||||
|
DAA096FC15E0C59B00912D63 /* MPElementEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA096FB15E0C59B00912D63 /* MPElementEntity.m */; };
|
||||||
|
DAA096FF15E0C59B00912D63 /* MPElementGeneratedEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA096FE15E0C59B00912D63 /* MPElementGeneratedEntity.m */; };
|
||||||
|
DAA0970215E0C59B00912D63 /* MPElementStoredEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA0970115E0C59B00912D63 /* MPElementStoredEntity.m */; };
|
||||||
|
DAA0970515E0C59B00912D63 /* MPUserEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA0970415E0C59B00912D63 /* MPUserEntity.m */; };
|
||||||
DAB8D45D15036BCF00CED3BC /* MasterPassword.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D43C15036BCF00CED3BC /* MasterPassword.xcdatamodeld */; };
|
DAB8D45D15036BCF00CED3BC /* MasterPassword.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D43C15036BCF00CED3BC /* MasterPassword.xcdatamodeld */; };
|
||||||
DAB8D45E15036BCF00CED3BC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DAB8D43F15036BCF00CED3BC /* InfoPlist.strings */; };
|
DAB8D45E15036BCF00CED3BC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DAB8D43F15036BCF00CED3BC /* InfoPlist.strings */; };
|
||||||
DAB8D45F15036BCF00CED3BC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44115036BCF00CED3BC /* main.m */; };
|
DAB8D45F15036BCF00CED3BC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44115036BCF00CED3BC /* main.m */; };
|
||||||
@ -912,14 +912,6 @@
|
|||||||
DA0A1D1415690AF40092735D /* Icon-Small-50@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small-50@2x.png"; sourceTree = "<group>"; };
|
DA0A1D1415690AF40092735D /* Icon-Small-50@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon-Small-50@2x.png"; sourceTree = "<group>"; };
|
||||||
DA0E07941577FE490008A67E /* MPEntities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPEntities.h; sourceTree = "<group>"; };
|
DA0E07941577FE490008A67E /* MPEntities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPEntities.h; sourceTree = "<group>"; };
|
||||||
DA0E07951577FE490008A67E /* MPEntities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPEntities.m; sourceTree = "<group>"; };
|
DA0E07951577FE490008A67E /* MPEntities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPEntities.m; sourceTree = "<group>"; };
|
||||||
DA0F9F3115B55397007ED9BC /* MPUserEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUserEntity.h; sourceTree = "<group>"; };
|
|
||||||
DA0F9F3215B55397007ED9BC /* MPUserEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUserEntity.m; sourceTree = "<group>"; };
|
|
||||||
DA0F9F3415B55397007ED9BC /* MPElementGeneratedEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementGeneratedEntity.h; sourceTree = "<group>"; };
|
|
||||||
DA0F9F3515B55397007ED9BC /* MPElementGeneratedEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementGeneratedEntity.m; sourceTree = "<group>"; };
|
|
||||||
DA0F9F3715B55397007ED9BC /* MPElementStoredEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementStoredEntity.h; sourceTree = "<group>"; };
|
|
||||||
DA0F9F3815B55397007ED9BC /* MPElementStoredEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementStoredEntity.m; sourceTree = "<group>"; };
|
|
||||||
DA0F9F3A15B55397007ED9BC /* MPElementEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementEntity.h; sourceTree = "<group>"; };
|
|
||||||
DA0F9F3B15B55397007ED9BC /* MPElementEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementEntity.m; sourceTree = "<group>"; };
|
|
||||||
DA30E9CB15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+PearlMutableInfo.h"; sourceTree = "<group>"; };
|
DA30E9CB15722ECA00A68B4C /* NSBundle+PearlMutableInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+PearlMutableInfo.h"; sourceTree = "<group>"; };
|
||||||
DA30E9CC15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+PearlMutableInfo.m"; sourceTree = "<group>"; };
|
DA30E9CC15722ECA00A68B4C /* NSBundle+PearlMutableInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+PearlMutableInfo.m"; sourceTree = "<group>"; };
|
||||||
DA30E9CD15722ECA00A68B4C /* Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pearl.m; sourceTree = "<group>"; };
|
DA30E9CD15722ECA00A68B4C /* Pearl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pearl.m; sourceTree = "<group>"; };
|
||||||
@ -998,6 +990,14 @@
|
|||||||
DA95D5CD14DF0691008D1B94 /* IASKPSToggleSwitchSpecifierViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IASKPSToggleSwitchSpecifierViewCell.xib; sourceTree = "<group>"; };
|
DA95D5CD14DF0691008D1B94 /* IASKPSToggleSwitchSpecifierViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IASKPSToggleSwitchSpecifierViewCell.xib; sourceTree = "<group>"; };
|
||||||
DA95D5CE14DF0691008D1B94 /* IASKSpecifierValuesView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IASKSpecifierValuesView.xib; sourceTree = "<group>"; };
|
DA95D5CE14DF0691008D1B94 /* IASKSpecifierValuesView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IASKSpecifierValuesView.xib; sourceTree = "<group>"; };
|
||||||
DA95D5F014DF0B1E008D1B94 /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; };
|
DA95D5F014DF0B1E008D1B94 /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; };
|
||||||
|
DAA096FA15E0C59B00912D63 /* MPElementEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementEntity.h; sourceTree = "<group>"; };
|
||||||
|
DAA096FB15E0C59B00912D63 /* MPElementEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementEntity.m; sourceTree = "<group>"; };
|
||||||
|
DAA096FD15E0C59B00912D63 /* MPElementGeneratedEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementGeneratedEntity.h; sourceTree = "<group>"; };
|
||||||
|
DAA096FE15E0C59B00912D63 /* MPElementGeneratedEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementGeneratedEntity.m; sourceTree = "<group>"; };
|
||||||
|
DAA0970015E0C59B00912D63 /* MPElementStoredEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPElementStoredEntity.h; sourceTree = "<group>"; };
|
||||||
|
DAA0970115E0C59B00912D63 /* MPElementStoredEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPElementStoredEntity.m; sourceTree = "<group>"; };
|
||||||
|
DAA0970315E0C59B00912D63 /* MPUserEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUserEntity.h; sourceTree = "<group>"; };
|
||||||
|
DAA0970415E0C59B00912D63 /* MPUserEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPUserEntity.m; 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; };
|
||||||
DAB8D43D15036BCF00CED3BC /* MasterPassword 1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 1.xcdatamodel"; sourceTree = "<group>"; };
|
DAB8D43D15036BCF00CED3BC /* MasterPassword 1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 1.xcdatamodel"; sourceTree = "<group>"; };
|
||||||
DAB8D44015036BCF00CED3BC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
DAB8D44015036BCF00CED3BC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
@ -1737,6 +1737,7 @@
|
|||||||
DAE4C967157E63BE00EFE047 /* avatar-18.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-18.png"; sourceTree = "<group>"; };
|
DAE4C967157E63BE00EFE047 /* avatar-18.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-18.png"; sourceTree = "<group>"; };
|
||||||
DAE4C968157E63BE00EFE047 /* avatar-18@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-18@2x.png"; sourceTree = "<group>"; };
|
DAE4C968157E63BE00EFE047 /* avatar-18@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "avatar-18@2x.png"; sourceTree = "<group>"; };
|
||||||
DAEBC45214F6364500987BF6 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
|
DAEBC45214F6364500987BF6 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
|
||||||
|
DAF83D6B15E02E04009C8D49 /* MasterPassword 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MasterPassword 3.xcdatamodel"; sourceTree = "<group>"; };
|
||||||
DAFE45D815039823003ABA7C /* NSObject+PearlExport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+PearlExport.h"; sourceTree = "<group>"; };
|
DAFE45D815039823003ABA7C /* NSObject+PearlExport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+PearlExport.h"; sourceTree = "<group>"; };
|
||||||
DAFE45D915039823003ABA7C /* NSObject+PearlExport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+PearlExport.m"; sourceTree = "<group>"; };
|
DAFE45D915039823003ABA7C /* NSObject+PearlExport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+PearlExport.m"; sourceTree = "<group>"; };
|
||||||
DAFE45DA15039823003ABA7C /* NSString+PearlNSArrayFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+PearlNSArrayFormat.h"; sourceTree = "<group>"; };
|
DAFE45DA15039823003ABA7C /* NSString+PearlNSArrayFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+PearlNSArrayFormat.h"; sourceTree = "<group>"; };
|
||||||
@ -2022,14 +2023,14 @@
|
|||||||
DA0E07941577FE490008A67E /* MPEntities.h */,
|
DA0E07941577FE490008A67E /* MPEntities.h */,
|
||||||
DA0E07951577FE490008A67E /* MPEntities.m */,
|
DA0E07951577FE490008A67E /* MPEntities.m */,
|
||||||
DAB8D43C15036BCF00CED3BC /* MasterPassword.xcdatamodeld */,
|
DAB8D43C15036BCF00CED3BC /* MasterPassword.xcdatamodeld */,
|
||||||
DA0F9F3115B55397007ED9BC /* MPUserEntity.h */,
|
DAA096FA15E0C59B00912D63 /* MPElementEntity.h */,
|
||||||
DA0F9F3215B55397007ED9BC /* MPUserEntity.m */,
|
DAA096FB15E0C59B00912D63 /* MPElementEntity.m */,
|
||||||
DA0F9F3415B55397007ED9BC /* MPElementGeneratedEntity.h */,
|
DAA096FD15E0C59B00912D63 /* MPElementGeneratedEntity.h */,
|
||||||
DA0F9F3515B55397007ED9BC /* MPElementGeneratedEntity.m */,
|
DAA096FE15E0C59B00912D63 /* MPElementGeneratedEntity.m */,
|
||||||
DA0F9F3715B55397007ED9BC /* MPElementStoredEntity.h */,
|
DAA0970015E0C59B00912D63 /* MPElementStoredEntity.h */,
|
||||||
DA0F9F3A15B55397007ED9BC /* MPElementEntity.h */,
|
DAA0970115E0C59B00912D63 /* MPElementStoredEntity.m */,
|
||||||
DA0F9F3B15B55397007ED9BC /* MPElementEntity.m */,
|
DAA0970315E0C59B00912D63 /* MPUserEntity.h */,
|
||||||
DA0F9F3815B55397007ED9BC /* MPElementStoredEntity.m */,
|
DAA0970415E0C59B00912D63 /* MPUserEntity.m */,
|
||||||
DA600C2415054F3A008E9AB6 /* MPAppDelegate_Key.h */,
|
DA600C2415054F3A008E9AB6 /* MPAppDelegate_Key.h */,
|
||||||
DA600C2315054F3A008E9AB6 /* MPAppDelegate_Key.m */,
|
DA600C2315054F3A008E9AB6 /* MPAppDelegate_Key.m */,
|
||||||
DA4426041557C1990052177D /* MPAppDelegate_Shared.h */,
|
DA4426041557C1990052177D /* MPAppDelegate_Shared.h */,
|
||||||
@ -4269,10 +4270,10 @@
|
|||||||
93D390BC6AE7A1C9B91A3668 /* MPKey.m in Sources */,
|
93D390BC6AE7A1C9B91A3668 /* MPKey.m in Sources */,
|
||||||
93D394744B5485303B326ECB /* MPAlgorithm.m in Sources */,
|
93D394744B5485303B326ECB /* MPAlgorithm.m in Sources */,
|
||||||
93D39DC7A7282137B08C8D82 /* MPAlgorithmV1.m in Sources */,
|
93D39DC7A7282137B08C8D82 /* MPAlgorithmV1.m in Sources */,
|
||||||
DA0F9F3315B55397007ED9BC /* MPUserEntity.m in Sources */,
|
DAA096FC15E0C59B00912D63 /* MPElementEntity.m in Sources */,
|
||||||
DA0F9F3615B55397007ED9BC /* MPElementGeneratedEntity.m in Sources */,
|
DAA096FF15E0C59B00912D63 /* MPElementGeneratedEntity.m in Sources */,
|
||||||
DA0F9F3915B55397007ED9BC /* MPElementStoredEntity.m in Sources */,
|
DAA0970215E0C59B00912D63 /* MPElementStoredEntity.m in Sources */,
|
||||||
DA0F9F3C15B55397007ED9BC /* MPElementEntity.m in Sources */,
|
DAA0970515E0C59B00912D63 /* MPUserEntity.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -5092,10 +5093,11 @@
|
|||||||
DAB8D43C15036BCF00CED3BC /* MasterPassword.xcdatamodeld */ = {
|
DAB8D43C15036BCF00CED3BC /* MasterPassword.xcdatamodeld */ = {
|
||||||
isa = XCVersionGroup;
|
isa = XCVersionGroup;
|
||||||
children = (
|
children = (
|
||||||
|
DAF83D6B15E02E04009C8D49 /* MasterPassword 3.xcdatamodel */,
|
||||||
DA46826C15AB48F100FB09E7 /* MasterPassword 2.xcdatamodel */,
|
DA46826C15AB48F100FB09E7 /* MasterPassword 2.xcdatamodel */,
|
||||||
DAB8D43D15036BCF00CED3BC /* MasterPassword 1.xcdatamodel */,
|
DAB8D43D15036BCF00CED3BC /* MasterPassword 1.xcdatamodel */,
|
||||||
);
|
);
|
||||||
currentVersion = DA46826C15AB48F100FB09E7 /* MasterPassword 2.xcdatamodel */;
|
currentVersion = DAF83D6B15E02E04009C8D49 /* MasterPassword 3.xcdatamodel */;
|
||||||
path = MasterPassword.xcdatamodeld;
|
path = MasterPassword.xcdatamodeld;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
versionGroupType = wrapper.xcdatamodel;
|
versionGroupType = wrapper.xcdatamodel;
|
||||||
|
@ -50,13 +50,14 @@
|
|||||||
</MacroExpansion>
|
</MacroExpansion>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
debugDocumentVersioning = "YES"
|
debugDocumentVersioning = "YES"
|
||||||
|
enableOpenGLFrameCaptureMode = "0"
|
||||||
allowLocationSimulation = "YES">
|
allowLocationSimulation = "YES">
|
||||||
<BuildableProductRunnable>
|
<BuildableProductRunnable>
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
|
@ -47,6 +47,9 @@
|
|||||||
|
|
||||||
- (MPUserEntity *)activeUser {
|
- (MPUserEntity *)activeUser {
|
||||||
|
|
||||||
|
if (!self.activeUserID)
|
||||||
|
return nil;
|
||||||
|
|
||||||
return (MPUserEntity *)[self.managedObjectContextIfReady objectWithID:self.activeUserID];
|
return (MPUserEntity *)[self.managedObjectContextIfReady objectWithID:self.activeUserID];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,8 +28,9 @@ typedef enum {
|
|||||||
- (UbiquityStoreManager *)storeManager;
|
- (UbiquityStoreManager *)storeManager;
|
||||||
- (void)saveContext;
|
- (void)saveContext;
|
||||||
|
|
||||||
- (MPImportResult)importSites:(NSString *)importedSitesString withPassword:(NSString *)password
|
- (MPImportResult)importSites:(NSString *)importedSitesString
|
||||||
askConfirmation:(BOOL(^)(NSUInteger importCount, NSUInteger deleteCount))confirmation;
|
askImportPassword:(NSString *(^)(NSString *userName))importPassword
|
||||||
|
askUserPassword:(NSString *(^)(NSString *userName, NSUInteger importCount, NSUInteger deleteCount))userPassword;
|
||||||
- (NSString *)exportSitesShowingPasswords:(BOOL)showPasswords;
|
- (NSString *)exportSitesShowingPasswords:(BOOL)showPasswords;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -183,8 +183,12 @@
|
|||||||
|
|
||||||
#pragma mark - Import / Export
|
#pragma mark - Import / Export
|
||||||
|
|
||||||
- (MPImportResult)importSites:(NSString *)importedSitesString withPassword:(NSString *)password
|
- (MPImportResult)importSites:(NSString *)importedSitesString
|
||||||
askConfirmation:(BOOL(^)(NSUInteger importCount, NSUInteger deleteCount))confirmation {
|
askImportPassword:(NSString *(^)(NSString *userName))importPassword
|
||||||
|
askUserPassword:(NSString *(^)(NSString *userName, NSUInteger importCount, NSUInteger deleteCount))userPassword {
|
||||||
|
|
||||||
|
while (![self managedObjectContextIfReady])
|
||||||
|
usleep((useconds_t)(USEC_PER_SEC * 0.2));
|
||||||
|
|
||||||
inf(@"Importing sites.");
|
inf(@"Importing sites.");
|
||||||
|
|
||||||
@ -205,14 +209,15 @@
|
|||||||
if (!headerPattern || !sitePattern)
|
if (!headerPattern || !sitePattern)
|
||||||
return MPImportResultInternalError;
|
return MPImportResultInternalError;
|
||||||
|
|
||||||
MPKey *key = nil;
|
__block MPUserEntity *user = nil;
|
||||||
__block MPUserEntity *user = nil;
|
id<MPAlgorithm> importAlgorithm = nil;
|
||||||
NSString *bundleVersion = nil, *keyIDHex = nil, *userName = nil;
|
NSString *importBundleVersion = nil, *importUserName = nil;
|
||||||
BOOL headerStarted = NO, headerEnded = NO, clearText = NO;
|
NSData *importKeyID = nil;
|
||||||
|
BOOL headerStarted = NO, headerEnded = NO, clearText = NO;
|
||||||
NSArray *importedSiteLines = [importedSitesString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
|
NSArray *importedSiteLines = [importedSitesString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
|
||||||
NSMutableSet *elementsToDelete = [NSMutableSet set];
|
NSMutableSet *elementsToDelete = [NSMutableSet set];
|
||||||
NSMutableArray *importedSiteElements = [NSMutableArray arrayWithCapacity:[importedSiteLines count]];
|
NSMutableArray *importedSiteElements = [NSMutableArray arrayWithCapacity:[importedSiteLines count]];
|
||||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
|
NSFetchRequest *elementFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
|
||||||
for (NSString *importedSiteLine in importedSiteLines) {
|
for (NSString *importedSiteLine in importedSiteLines) {
|
||||||
if ([importedSiteLine hasPrefix:@"#"]) {
|
if ([importedSiteLine hasPrefix:@"#"]) {
|
||||||
// Comment or header
|
// Comment or header
|
||||||
@ -238,20 +243,20 @@
|
|||||||
NSString *headerName = [importedSiteLine substringWithRange:[headerElements rangeAtIndex:1]];
|
NSString *headerName = [importedSiteLine substringWithRange:[headerElements rangeAtIndex:1]];
|
||||||
NSString *headerValue = [importedSiteLine substringWithRange:[headerElements rangeAtIndex:2]];
|
NSString *headerValue = [importedSiteLine substringWithRange:[headerElements rangeAtIndex:2]];
|
||||||
if ([headerName isEqualToString:@"User Name"]) {
|
if ([headerName isEqualToString:@"User Name"]) {
|
||||||
userName = headerValue;
|
importUserName = headerValue;
|
||||||
|
|
||||||
NSFetchRequest *userFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPUserEntity class])];
|
NSFetchRequest *userFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPUserEntity class])];
|
||||||
userFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@", userName];
|
userFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@", importUserName];
|
||||||
__block NSArray *users = nil;
|
__block NSArray *users = nil;
|
||||||
[self.managedObjectContextIfReady performBlockAndWait:^{
|
[self.managedObjectContextIfReady performBlockAndWait:^{
|
||||||
users = [self.managedObjectContextIfReady executeFetchRequest:userFetchRequest error:&error];
|
users = [self.managedObjectContextIfReady executeFetchRequest:userFetchRequest error:&error];
|
||||||
}];
|
}];
|
||||||
if (!users) {
|
if (!users) {
|
||||||
err(@"While looking for user: %@, error: %@", userName, error);
|
err(@"While looking for user: %@, error: %@", importUserName, error);
|
||||||
return MPImportResultInternalError;
|
return MPImportResultInternalError;
|
||||||
}
|
}
|
||||||
if ([users count] > 1) {
|
if ([users count] > 1) {
|
||||||
err(@"While looking for user: %@, found more than one: %u", userName, [users count]);
|
err(@"While looking for user: %@, found more than one: %u", importUserName, [users count]);
|
||||||
return MPImportResultInternalError;
|
return MPImportResultInternalError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,9 +264,11 @@
|
|||||||
dbg(@"Found user: %@", [user debugDescription]);
|
dbg(@"Found user: %@", [user debugDescription]);
|
||||||
}
|
}
|
||||||
if ([headerName isEqualToString:@"Key ID"])
|
if ([headerName isEqualToString:@"Key ID"])
|
||||||
keyIDHex = headerValue;
|
importKeyID = [headerValue decodeHex];
|
||||||
if ([headerName isEqualToString:@"Version"])
|
if ([headerName isEqualToString:@"Version"]) {
|
||||||
bundleVersion = headerValue;
|
importBundleVersion = headerValue;
|
||||||
|
importAlgorithm = MPAlgorithmDefaultForBundleVersion(importBundleVersion);
|
||||||
|
}
|
||||||
if ([headerName isEqualToString:@"Passwords"]) {
|
if ([headerName isEqualToString:@"Passwords"]) {
|
||||||
if ([headerValue isEqualToString:@"VISIBLE"])
|
if ([headerValue isEqualToString:@"VISIBLE"])
|
||||||
clearText = YES;
|
clearText = YES;
|
||||||
@ -271,13 +278,8 @@
|
|||||||
}
|
}
|
||||||
if (!headerEnded)
|
if (!headerEnded)
|
||||||
continue;
|
continue;
|
||||||
if (!keyIDHex || ![userName length])
|
if (!importKeyID || ![importUserName length])
|
||||||
return MPImportResultMalformedInput;
|
return MPImportResultMalformedInput;
|
||||||
if (!key) {
|
|
||||||
key = [MPAlgorithmDefaultForBundleVersion(bundleVersion) keyForPassword:password ofUserNamed:userName];
|
|
||||||
if (![keyIDHex isEqualToString:[key.keyID encodeHex]])
|
|
||||||
return MPImportResultInvalidPassword;
|
|
||||||
}
|
|
||||||
if (![importedSiteLine length])
|
if (![importedSiteLine length])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -297,10 +299,10 @@
|
|||||||
|
|
||||||
// Find existing site.
|
// Find existing site.
|
||||||
if (user) {
|
if (user) {
|
||||||
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@ AND user == %@", name, user];
|
elementFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@ AND user == %@", name, user];
|
||||||
__block NSArray *existingSites = nil;
|
__block NSArray *existingSites = nil;
|
||||||
[self.managedObjectContextIfReady performBlockAndWait:^{
|
[self.managedObjectContextIfReady performBlockAndWait:^{
|
||||||
existingSites = [self.managedObjectContextIfReady executeFetchRequest:fetchRequest error:&error];
|
existingSites = [self.managedObjectContextIfReady executeFetchRequest:elementFetchRequest error:&error];
|
||||||
}];
|
}];
|
||||||
if (!existingSites) {
|
if (!existingSites) {
|
||||||
err(@"Lookup of existing sites failed for site: %@, user: %@, error: %@", name, user.userID, error);
|
err(@"Lookup of existing sites failed for site: %@, user: %@, error: %@", name, user.userID, error);
|
||||||
@ -314,14 +316,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inf(@"Importing %u sites, deleting %u sites, for user: %@",
|
// Ask for confirmation to import these sites and the master password of the user.
|
||||||
[importedSiteElements count], [elementsToDelete count], [MPUserEntity idFor:userName]);
|
inf(@"Importing %u sites, deleting %u sites, for user: %@", [importedSiteElements count], [elementsToDelete count], [MPUserEntity idFor:importUserName]);
|
||||||
|
NSString *userMasterPassword = userPassword(user.name, [importedSiteElements count], [elementsToDelete count]);
|
||||||
// Ask for confirmation to import these sites.
|
if (!userMasterPassword) {
|
||||||
if (!confirmation([importedSiteElements count], [elementsToDelete count])) {
|
|
||||||
inf(@"Import cancelled.");
|
inf(@"Import cancelled.");
|
||||||
return MPImportResultCancelled;
|
return MPImportResultCancelled;
|
||||||
}
|
}
|
||||||
|
MPKey *userKey = [MPAlgorithmDefault keyForPassword:userMasterPassword ofUserNamed:user.name];
|
||||||
|
if (![userKey.keyID isEqualToData:user.keyID])
|
||||||
|
return MPImportResultInvalidPassword;
|
||||||
|
__block MPKey *importKey = userKey;
|
||||||
|
if ([importKey.keyID isEqualToData:importKeyID])
|
||||||
|
importKey = nil;
|
||||||
|
|
||||||
BOOL success = NO;
|
BOOL success = NO;
|
||||||
[self.managedObjectContextIfReady.undoManager beginUndoGrouping];
|
[self.managedObjectContextIfReady.undoManager beginUndoGrouping];
|
||||||
@ -337,16 +344,19 @@
|
|||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
// Import new sites.
|
// Make sure there is a user.
|
||||||
if (!user) {
|
if (!user) {
|
||||||
[self.managedObjectContextIfReady performBlockAndWait:^{
|
[self.managedObjectContextIfReady performBlockAndWait:^{
|
||||||
user = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPUserEntity class])
|
user = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPUserEntity class])
|
||||||
inManagedObjectContext:self.managedObjectContextIfReady];
|
inManagedObjectContext:self.managedObjectContextIfReady];
|
||||||
user.name = userName;
|
user.name = importUserName;
|
||||||
user.keyID = [keyIDHex decodeHex];
|
user.keyID = importKeyID;
|
||||||
}];
|
}];
|
||||||
dbg(@"Created User: %@", [user debugDescription]);
|
dbg(@"Created User: %@", [user debugDescription]);
|
||||||
}
|
}
|
||||||
|
[self saveContext];
|
||||||
|
|
||||||
|
// Import new sites.
|
||||||
for (NSArray *siteElements in importedSiteElements) {
|
for (NSArray *siteElements in importedSiteElements) {
|
||||||
NSDate *lastUsed = [[NSDateFormatter rfc3339DateFormatter] dateFromString:[siteElements objectAtIndex:0]];
|
NSDate *lastUsed = [[NSDateFormatter rfc3339DateFormatter] dateFromString:[siteElements objectAtIndex:0]];
|
||||||
NSUInteger uses = (unsigned)[[siteElements objectAtIndex:1] integerValue];
|
NSUInteger uses = (unsigned)[[siteElements objectAtIndex:1] integerValue];
|
||||||
@ -356,9 +366,10 @@
|
|||||||
NSString *exportContent = [siteElements objectAtIndex:5];
|
NSString *exportContent = [siteElements objectAtIndex:5];
|
||||||
|
|
||||||
// Create new site.
|
// Create new site.
|
||||||
|
__block MPImportResult result = MPImportResultSuccess;
|
||||||
[self.managedObjectContextIfReady performBlockAndWait:^{
|
[self.managedObjectContextIfReady performBlockAndWait:^{
|
||||||
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:[key.algorithm classNameOfType:type]
|
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:[MPAlgorithmForVersion(version) classNameOfType:type]
|
||||||
inManagedObjectContext:self.managedObjectContextIfReady];
|
inManagedObjectContext:self.managedObjectContextIfReady];
|
||||||
element.name = name;
|
element.name = name;
|
||||||
element.user = user;
|
element.user = user;
|
||||||
element.type = type;
|
element.type = type;
|
||||||
@ -367,12 +378,23 @@
|
|||||||
element.version = version;
|
element.version = version;
|
||||||
if ([exportContent length]) {
|
if ([exportContent length]) {
|
||||||
if (clearText)
|
if (clearText)
|
||||||
[element importClearTextContent:exportContent usingKey:key];
|
[element importClearTextContent:exportContent usingKey:userKey];
|
||||||
else
|
else {
|
||||||
[element importProtectedContent:exportContent];
|
if (!importKey)
|
||||||
|
importKey = [importAlgorithm keyForPassword:importPassword(user.name) ofUserNamed:user.name];
|
||||||
|
if (![importKey.keyID isEqualToData:importKeyID]) {
|
||||||
|
result = MPImportResultInvalidPassword;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[element importProtectedContent:exportContent protectedByKey:importKey usingKey:userKey];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg(@"Created Element: %@", [element debugDescription]);
|
dbg(@"Created Element: %@", [element debugDescription]);
|
||||||
}];
|
}];
|
||||||
|
if (result != MPImportResultSuccess)
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
[self saveContext];
|
[self saveContext];
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// MPElementEntity.h
|
// MPElementEntity.h
|
||||||
// MasterPassword-iOS
|
// MasterPassword-iOS
|
||||||
//
|
//
|
||||||
// Created by Maarten Billemont on 17/07/12.
|
// Created by Maarten Billemont on 2012-08-19.
|
||||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -15,10 +15,10 @@
|
|||||||
|
|
||||||
@property (nonatomic, retain) id content;
|
@property (nonatomic, retain) id content;
|
||||||
@property (nonatomic, retain) NSDate * lastUsed;
|
@property (nonatomic, retain) NSDate * lastUsed;
|
||||||
|
@property (nonatomic, retain) NSString * loginName;
|
||||||
@property (nonatomic, retain) NSString * name;
|
@property (nonatomic, retain) NSString * name;
|
||||||
@property (nonatomic, retain) NSNumber * requiresExplicitMigration_;
|
@property (nonatomic, retain) NSNumber * requiresExplicitMigration_;
|
||||||
@property (nonatomic, retain) NSNumber * type_;
|
@property (nonatomic, retain) NSNumber * type_;
|
||||||
@property (nonatomic, retain) NSString * userName;
|
|
||||||
@property (nonatomic, retain) NSNumber * uses_;
|
@property (nonatomic, retain) NSNumber * uses_;
|
||||||
@property (nonatomic, retain) NSNumber * version_;
|
@property (nonatomic, retain) NSNumber * version_;
|
||||||
@property (nonatomic, retain) MPUserEntity *user;
|
@property (nonatomic, retain) MPUserEntity *user;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// MPElementEntity.m
|
// MPElementEntity.m
|
||||||
// MasterPassword-iOS
|
// MasterPassword-iOS
|
||||||
//
|
//
|
||||||
// Created by Maarten Billemont on 17/07/12.
|
// Created by Maarten Billemont on 2012-08-19.
|
||||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -14,10 +14,10 @@
|
|||||||
|
|
||||||
@dynamic content;
|
@dynamic content;
|
||||||
@dynamic lastUsed;
|
@dynamic lastUsed;
|
||||||
|
@dynamic loginName;
|
||||||
@dynamic name;
|
@dynamic name;
|
||||||
@dynamic requiresExplicitMigration_;
|
@dynamic requiresExplicitMigration_;
|
||||||
@dynamic type_;
|
@dynamic type_;
|
||||||
@dynamic userName;
|
|
||||||
@dynamic uses_;
|
@dynamic uses_;
|
||||||
@dynamic version_;
|
@dynamic version_;
|
||||||
@dynamic user;
|
@dynamic user;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// MPElementGeneratedEntity.h
|
// MPElementGeneratedEntity.h
|
||||||
// MasterPassword-iOS
|
// MasterPassword-iOS
|
||||||
//
|
//
|
||||||
// Created by Maarten Billemont on 17/07/12.
|
// Created by Maarten Billemont on 2012-08-19.
|
||||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// MPElementGeneratedEntity.m
|
// MPElementGeneratedEntity.m
|
||||||
// MasterPassword-iOS
|
// MasterPassword-iOS
|
||||||
//
|
//
|
||||||
// Created by Maarten Billemont on 17/07/12.
|
// Created by Maarten Billemont on 2012-08-19.
|
||||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// MPElementStoredEntity.h
|
// MPElementStoredEntity.h
|
||||||
// MasterPassword-iOS
|
// MasterPassword-iOS
|
||||||
//
|
//
|
||||||
// Created by Maarten Billemont on 17/07/12.
|
// Created by Maarten Billemont on 2012-08-19.
|
||||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// MPElementStoredEntity.m
|
// MPElementStoredEntity.m
|
||||||
// MasterPassword-iOS
|
// MasterPassword-iOS
|
||||||
//
|
//
|
||||||
// Created by Maarten Billemont on 17/07/12.
|
// Created by Maarten Billemont on 2012-08-19.
|
||||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
- (NSUInteger)use;
|
- (NSUInteger)use;
|
||||||
- (NSString *)exportContent;
|
- (NSString *)exportContent;
|
||||||
- (void)importProtectedContent:(NSString *)protectedContent;
|
- (void)importProtectedContent:(NSString *)protectedContent protectedByKey:(MPKey *)contentProtectionKey usingKey:(MPKey *)key2;
|
||||||
- (void)importClearTextContent:(NSString *)clearContent usingKey:(MPKey *)key;
|
- (void)importClearTextContent:(NSString *)clearContent usingKey:(MPKey *)key;
|
||||||
- (BOOL)migrateExplicitly:(BOOL)explicit;
|
- (BOOL)migrateExplicitly:(BOOL)explicit;
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)importProtectedContent:(NSString *)content {
|
- (void)importProtectedContent:(NSString *)protectedContent protectedByKey:(MPKey *)contentProtectionKey usingKey:(MPKey *)key {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,9 +107,9 @@
|
|||||||
|
|
||||||
- (NSString *)debugDescription {
|
- (NSString *)debugDescription {
|
||||||
|
|
||||||
return PearlString(@"{%@: name=%@, user=%@, type=%d, uses=%d, lastUsed=%@, version=%d, userName=%@, requiresExplicitMigration=%d}",
|
return PearlString(@"{%@: name=%@, user=%@, type=%d, uses=%d, lastUsed=%@, version=%d, loginName=%@, requiresExplicitMigration=%d}",
|
||||||
NSStringFromClass([self class]), self.name, self.user.name, self.type, self.uses, self.lastUsed, self.version,
|
NSStringFromClass([self class]), self.name, self.user.name, self.type, self.uses, self.lastUsed, self.version,
|
||||||
self.userName, self.requiresExplicitMigration);
|
self.loginName, self.requiresExplicitMigration);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)migrateExplicitly:(BOOL)explicit {
|
- (BOOL)migrateExplicitly:(BOOL)explicit {
|
||||||
@ -185,7 +185,6 @@
|
|||||||
if (!key)
|
if (!key)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
assert([key.keyID isEqualToData:self.user.keyID]);
|
|
||||||
[self setContent:content usingKey:key];
|
[self setContent:content usingKey:key];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,17 +201,23 @@
|
|||||||
|
|
||||||
NSData *decryptedContent = nil;
|
NSData *decryptedContent = nil;
|
||||||
if ([encryptedContent length])
|
if ([encryptedContent length])
|
||||||
decryptedContent = [encryptedContent decryptWithSymmetricKey:[key subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
decryptedContent = [self decryptContent:encryptedContent usingKey:key];
|
||||||
|
|
||||||
return [[NSString alloc] initWithBytes:decryptedContent.bytes length:decryptedContent.length encoding:NSUTF8StringEncoding];
|
return [[NSString alloc] initWithBytes:decryptedContent.bytes length:decryptedContent.length encoding:NSUTF8StringEncoding];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSData *)decryptContent:(NSData *)encryptedContent usingKey:(MPKey *)key {
|
||||||
|
|
||||||
|
return [encryptedContent decryptWithSymmetricKey:[key subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)setContent:(id)content usingKey:(MPKey *)key {
|
- (void)setContent:(id)content usingKey:(MPKey *)key {
|
||||||
|
|
||||||
assert(self.type & MPElementTypeClassStored);
|
assert(self.type & MPElementTypeClassStored);
|
||||||
assert(key);
|
assert([key.keyID isEqualToData:self.user.keyID]);
|
||||||
|
|
||||||
NSData *encryptedContent = [[content description] encryptWithSymmetricKey:[key subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
NSData *encryptedContent = [[[content description] dataUsingEncoding:NSUTF8StringEncoding]
|
||||||
|
encryptWithSymmetricKey:[key subKeyOfLength:PearlCryptKeySize].keyData padding:YES];
|
||||||
|
|
||||||
if (self.type & MPElementFeatureDevicePrivate) {
|
if (self.type & MPElementFeatureDevicePrivate) {
|
||||||
[PearlKeyChain addOrUpdateItemForQuery:[MPElementStoredEntity queryForDevicePrivateElementNamed:self.name]
|
[PearlKeyChain addOrUpdateItemForQuery:[MPElementStoredEntity queryForDevicePrivateElementNamed:self.name]
|
||||||
@ -233,9 +238,18 @@
|
|||||||
return [self.contentObject encodeBase64];
|
return [self.contentObject encodeBase64];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)importProtectedContent:(NSString *)protectedContent {
|
- (void)importProtectedContent:(NSString *)protectedContent protectedByKey:(MPKey *)contentProtectionKey usingKey:(MPKey *)key {
|
||||||
|
|
||||||
self.contentObject = [protectedContent decodeBase64];
|
if ([contentProtectionKey.keyID isEqualToData:key.keyID])
|
||||||
|
self.contentObject = [protectedContent decodeBase64];
|
||||||
|
|
||||||
|
else {
|
||||||
|
NSString *clearContent = [[NSString alloc] initWithData:[self decryptContent:[protectedContent decodeBase64]
|
||||||
|
usingKey:contentProtectionKey]
|
||||||
|
encoding:NSUTF8StringEncoding];
|
||||||
|
|
||||||
|
[self importClearTextContent:clearContent usingKey:key];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)importClearTextContent:(NSString *)clearContent usingKey:(MPKey *)key {
|
- (void)importClearTextContent:(NSString *)clearContent usingKey:(MPKey *)key {
|
||||||
|
@ -43,11 +43,11 @@ typedef enum {
|
|||||||
#define MPCheckpointAction @"MPCheckpointAction"
|
#define MPCheckpointAction @"MPCheckpointAction"
|
||||||
#define MPCheckpointHelpChapter @"MPCheckpointHelpChapter"
|
#define MPCheckpointHelpChapter @"MPCheckpointHelpChapter"
|
||||||
#define MPCheckpointCopyToPasteboard @"MPCheckpointCopyToPasteboard"
|
#define MPCheckpointCopyToPasteboard @"MPCheckpointCopyToPasteboard"
|
||||||
#define MPCheckpointCopyUserNameToPasteboard @"MPCheckpointCopyUserNameToPasteboard"
|
#define MPCheckpointCopyLoginNameToPasteboard @"MPCheckpointCopyLoginNameToPasteboard"
|
||||||
#define MPCheckpointResetPasswordCounter @"MPCheckpointResetPasswordCounter"
|
#define MPCheckpointResetPasswordCounter @"MPCheckpointResetPasswordCounter"
|
||||||
#define MPCheckpointIncrementPasswordCounter @"MPCheckpointIncrementPasswordCounter"
|
#define MPCheckpointIncrementPasswordCounter @"MPCheckpointIncrementPasswordCounter"
|
||||||
#define MPCheckpointEditPassword @"MPCheckpointEditPassword"
|
#define MPCheckpointEditPassword @"MPCheckpointEditPassword"
|
||||||
#define MPCheckpointEditUserName @"MPCheckpointEditUserName"
|
#define MPCheckpointEditLoginName @"MPCheckpointEditLoginName"
|
||||||
#define MPCheckpointCloseAlert @"MPCheckpointCloseAlert"
|
#define MPCheckpointCloseAlert @"MPCheckpointCloseAlert"
|
||||||
#define MPCheckpointCloseOutdatedAlert @"MPCheckpointCloseOutdatedAlert"
|
#define MPCheckpointCloseOutdatedAlert @"MPCheckpointCloseOutdatedAlert"
|
||||||
#define MPCheckpointUseType @"MPCheckpointUseType"
|
#define MPCheckpointUseType @"MPCheckpointUseType"
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// MPUserEntity.h
|
// MPUserEntity.h
|
||||||
// MasterPassword-iOS
|
// MasterPassword-iOS
|
||||||
//
|
//
|
||||||
// Created by Maarten Billemont on 17/07/12.
|
// Created by Maarten Billemont on 2012-08-19.
|
||||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -18,8 +18,8 @@
|
|||||||
@property (nonatomic, retain) NSData * keyID;
|
@property (nonatomic, retain) NSData * keyID;
|
||||||
@property (nonatomic, retain) NSDate * lastUsed;
|
@property (nonatomic, retain) NSDate * lastUsed;
|
||||||
@property (nonatomic, retain) NSString * name;
|
@property (nonatomic, retain) NSString * name;
|
||||||
@property (nonatomic, retain) NSNumber * saveKey_;
|
|
||||||
@property (nonatomic, retain) NSNumber * requiresExplicitMigration_;
|
@property (nonatomic, retain) NSNumber * requiresExplicitMigration_;
|
||||||
|
@property (nonatomic, retain) NSNumber * saveKey_;
|
||||||
@property (nonatomic, retain) NSSet *elements;
|
@property (nonatomic, retain) NSSet *elements;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// MPUserEntity.m
|
// MPUserEntity.m
|
||||||
// MasterPassword-iOS
|
// MasterPassword-iOS
|
||||||
//
|
//
|
||||||
// Created by Maarten Billemont on 17/07/12.
|
// Created by Maarten Billemont on 2012-08-19.
|
||||||
// Copyright (c) 2012 Lyndir. All rights reserved.
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -17,8 +17,8 @@
|
|||||||
@dynamic keyID;
|
@dynamic keyID;
|
||||||
@dynamic lastUsed;
|
@dynamic lastUsed;
|
||||||
@dynamic name;
|
@dynamic name;
|
||||||
@dynamic saveKey_;
|
|
||||||
@dynamic requiresExplicitMigration_;
|
@dynamic requiresExplicitMigration_;
|
||||||
|
@dynamic saveKey_;
|
||||||
@dynamic elements;
|
@dynamic elements;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>_XCCurrentVersionName</key>
|
<key>_XCCurrentVersionName</key>
|
||||||
<string>MasterPassword 2.xcdatamodel</string>
|
<string>MasterPassword 3.xcdatamodel</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -32,9 +32,9 @@
|
|||||||
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity" inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
|
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity" inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
|
||||||
</entity>
|
</entity>
|
||||||
<elements>
|
<elements>
|
||||||
<element name="MPElementEntity" positionX="160" positionY="192" width="128" height="180"/>
|
<element name="MPElementEntity" positionX="0" positionY="0" width="0" height="0"/>
|
||||||
<element name="MPElementGeneratedEntity" positionX="160" positionY="192" width="128" height="60"/>
|
<element name="MPElementGeneratedEntity" positionX="0" positionY="0" width="0" height="0"/>
|
||||||
<element name="MPElementStoredEntity" positionX="160" positionY="192" width="128" height="60"/>
|
<element name="MPElementStoredEntity" positionX="0" positionY="0" width="0" height="0"/>
|
||||||
<element name="MPUserEntity" positionX="160" positionY="192" width="128" height="150"/>
|
<element name="MPUserEntity" positionX="0" positionY="0" width="0" height="0"/>
|
||||||
</elements>
|
</elements>
|
||||||
</model>
|
</model>
|
@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1487" systemVersion="12A269" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||||
|
<entity name="MPElementEntity" representedClassName="MPElementEntity" isAbstract="YES" syncable="YES">
|
||||||
|
<attribute name="content" optional="YES" transient="YES" attributeType="Transformable" syncable="YES"/>
|
||||||
|
<attribute name="lastUsed" attributeType="Date" indexed="YES" syncable="YES"/>
|
||||||
|
<attribute name="loginName" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="name" attributeType="String" minValueString="1" indexed="YES" syncable="YES"/>
|
||||||
|
<attribute name="requiresExplicitMigration_" attributeType="Boolean" defaultValueString="NO">
|
||||||
|
<userInfo/>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="type_" attributeType="Integer 16" defaultValueString="17" syncable="YES"/>
|
||||||
|
<attribute name="uses_" attributeType="Integer 16" defaultValueString="0" indexed="YES" syncable="YES"/>
|
||||||
|
<attribute name="version_" attributeType="Integer 16" minValueString="0" defaultValueString="0" syncable="YES"/>
|
||||||
|
<relationship name="user" minCount="1" maxCount="1" deletionRule="Nullify" destinationEntity="MPUserEntity" inverseName="elements" inverseEntity="MPUserEntity" syncable="YES"/>
|
||||||
|
</entity>
|
||||||
|
<entity name="MPElementGeneratedEntity" representedClassName="MPElementGeneratedEntity" parentEntity="MPElementEntity" syncable="YES">
|
||||||
|
<attribute name="counter_" optional="YES" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
|
||||||
|
</entity>
|
||||||
|
<entity name="MPElementStoredEntity" representedClassName="MPElementStoredEntity" parentEntity="MPElementEntity" syncable="YES">
|
||||||
|
<attribute name="contentObject" optional="YES" attributeType="Transformable" storedInTruthFile="YES" syncable="YES"/>
|
||||||
|
</entity>
|
||||||
|
<entity name="MPUserEntity" representedClassName="MPUserEntity" syncable="YES">
|
||||||
|
<attribute name="avatar_" attributeType="Integer 16" defaultValueString="0" syncable="YES"/>
|
||||||
|
<attribute name="defaultType_" attributeType="Integer 16" defaultValueString="17" syncable="YES"/>
|
||||||
|
<attribute name="keyID" optional="YES" attributeType="Binary" syncable="YES"/>
|
||||||
|
<attribute name="lastUsed" optional="YES" attributeType="Date" syncable="YES"/>
|
||||||
|
<attribute name="name" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="requiresExplicitMigration_" transient="YES" attributeType="Boolean" defaultValueString="NO" syncable="YES"/>
|
||||||
|
<attribute name="saveKey_" attributeType="Boolean" defaultValueString="NO">
|
||||||
|
<userInfo/>
|
||||||
|
</attribute>
|
||||||
|
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity" inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
|
||||||
|
</entity>
|
||||||
|
<elements>
|
||||||
|
<element name="MPElementEntity" positionX="160" positionY="192" width="128" height="180"/>
|
||||||
|
<element name="MPElementGeneratedEntity" positionX="160" positionY="192" width="128" height="60"/>
|
||||||
|
<element name="MPElementStoredEntity" positionX="160" positionY="192" width="128" height="60"/>
|
||||||
|
<element name="MPUserEntity" positionX="160" positionY="192" width="128" height="150"/>
|
||||||
|
</elements>
|
||||||
|
</model>
|
@ -220,67 +220,98 @@
|
|||||||
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
|
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
|
||||||
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
|
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
|
||||||
|
|
||||||
__autoreleasing NSError *error;
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
__autoreleasing NSURLResponse *response;
|
PearlAlert *activityAlert = [PearlAlert showAlertWithTitle:@"Importing" message:@"\n\n"
|
||||||
NSData *importedSitesData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url]
|
viewStyle:UIAlertViewStyleDefault initAlert:
|
||||||
returningResponse:&response error:&error];
|
^(UIAlertView *alert, UITextField *firstField) {
|
||||||
if (error)
|
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
|
||||||
err(@"While reading imported sites from %@: %@", url, error);
|
activityIndicator.center = CGPointMake(140, 90);
|
||||||
if (!importedSitesData)
|
[activityIndicator startAnimating];
|
||||||
return NO;
|
[alert addSubview:activityIndicator];
|
||||||
|
}
|
||||||
|
tappedButtonBlock:nil cancelTitle:nil otherTitles:nil];
|
||||||
|
|
||||||
NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding];
|
NSError *error;
|
||||||
[PearlAlert showAlertWithTitle:@"Import Password" message:
|
NSURLResponse *response;
|
||||||
@"Enter the master password for this export:"
|
NSData *importedSitesData = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url]
|
||||||
viewStyle:UIAlertViewStyleSecureTextInput initAlert:nil tappedButtonBlock:
|
returningResponse:&response error:&error];
|
||||||
^(UIAlertView *alert, NSInteger buttonIndex) {
|
if (error)
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
err(@"While reading imported sites from %@: %@", url, error);
|
||||||
MPImportResult result = [self importSites:importedSitesString withPassword:[alert textFieldAtIndex:0].text
|
if (!importedSitesData)
|
||||||
askConfirmation:^BOOL(NSUInteger importCount, NSUInteger deleteCount) {
|
return;
|
||||||
__block BOOL confirmation = NO;
|
|
||||||
|
|
||||||
dispatch_group_t confirmationGroup = dispatch_group_create();
|
NSString *importedSitesString = [[NSString alloc] initWithData:importedSitesData encoding:NSUTF8StringEncoding];
|
||||||
dispatch_group_enter(confirmationGroup);
|
MPImportResult result = [self importSites:importedSitesString askImportPassword:^NSString *(NSString *userName) {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
__block NSString *masterPassword = nil;
|
||||||
[PearlAlert showAlertWithTitle:@"Import Sites?"
|
|
||||||
message:PearlString(
|
|
||||||
@"Import %d sites, overwriting %d existing sites?",
|
|
||||||
importCount, deleteCount)
|
|
||||||
viewStyle:UIAlertViewStyleDefault
|
|
||||||
initAlert:nil
|
|
||||||
tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
|
|
||||||
if (buttonIndex_
|
|
||||||
!= [alert_ cancelButtonIndex])
|
|
||||||
confirmation = YES;
|
|
||||||
|
|
||||||
dispatch_group_leave(confirmationGroup);
|
dispatch_group_t importPasswordGroup = dispatch_group_create();
|
||||||
}
|
dispatch_group_enter(importPasswordGroup);
|
||||||
cancelTitle:[PearlStrings get].commonButtonCancel
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
otherTitles:@"Import", nil];
|
[PearlAlert showAlertWithTitle:@"Import File's Master Password"
|
||||||
});
|
message:PearlString(@"%@'s export was done using a different master password.\n"
|
||||||
dispatch_group_wait(
|
@"Enter that master password to unlock the exported data.", userName)
|
||||||
confirmationGroup, DISPATCH_TIME_FOREVER);
|
viewStyle:UIAlertViewStyleSecureTextInput
|
||||||
|
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
|
||||||
|
@try {
|
||||||
|
if (buttonIndex_ == [alert_ cancelButtonIndex])
|
||||||
|
return;
|
||||||
|
|
||||||
return confirmation;
|
masterPassword = [alert_ textFieldAtIndex:0].text;
|
||||||
}];
|
}
|
||||||
|
@finally {
|
||||||
|
dispatch_group_leave(importPasswordGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Unlock Import", nil];
|
||||||
|
});
|
||||||
|
dispatch_group_wait(importPasswordGroup, DISPATCH_TIME_FOREVER);
|
||||||
|
|
||||||
switch (result) {
|
return masterPassword;
|
||||||
case MPImportResultSuccess:
|
} askUserPassword:^NSString *(NSString *userName, NSUInteger importCount, NSUInteger deleteCount) {
|
||||||
case MPImportResultCancelled:
|
__block NSString *masterPassword = nil;
|
||||||
break;
|
|
||||||
case MPImportResultInternalError:
|
dispatch_group_t userPasswordGroup = dispatch_group_create();
|
||||||
[PearlAlert showError:@"Import failed because of an internal error."];
|
dispatch_group_enter(userPasswordGroup);
|
||||||
break;
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
case MPImportResultMalformedInput:
|
[PearlAlert showAlertWithTitle:PearlString(@"Master Password for\n%@", userName)
|
||||||
[PearlAlert showError:@"The import doesn't look like a Master Password export."];
|
message:PearlString(@"Imports %d sites, overwriting %d.", importCount,
|
||||||
break;
|
deleteCount)
|
||||||
case MPImportResultInvalidPassword:
|
viewStyle:UIAlertViewStyleSecureTextInput
|
||||||
[PearlAlert showError:@"Incorrect master password for the import sites."];
|
initAlert:nil tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
|
||||||
break;
|
@try {
|
||||||
}
|
if (buttonIndex_ == [alert_ cancelButtonIndex])
|
||||||
});
|
return;
|
||||||
}
|
|
||||||
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Unlock File", nil];
|
masterPassword = [alert_ textFieldAtIndex:0].text;
|
||||||
|
}
|
||||||
|
@finally {
|
||||||
|
dispatch_group_leave(userPasswordGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:@"Import", nil];
|
||||||
|
});
|
||||||
|
dispatch_group_wait(userPasswordGroup, DISPATCH_TIME_FOREVER);
|
||||||
|
|
||||||
|
return masterPassword;
|
||||||
|
}];
|
||||||
|
|
||||||
|
switch (result) {
|
||||||
|
case MPImportResultSuccess:
|
||||||
|
case MPImportResultCancelled:
|
||||||
|
break;
|
||||||
|
case MPImportResultInternalError:
|
||||||
|
[PearlAlert showError:@"Import failed because of an internal error."];
|
||||||
|
break;
|
||||||
|
case MPImportResultMalformedInput:
|
||||||
|
[PearlAlert showError:@"The import doesn't look like a Master Password export."];
|
||||||
|
break;
|
||||||
|
case MPImportResultInvalidPassword:
|
||||||
|
[PearlAlert showError:@"Incorrect master password for the import sites."];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
[activityAlert dismissAlert];
|
||||||
|
});
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
@interface MPMainViewController : UIViewController<MPTypeDelegate, UITextFieldDelegate, MPSearchResultsDelegate, UIWebViewDelegate, MFMailComposeViewControllerDelegate, UIGestureRecognizerDelegate>
|
@interface MPMainViewController : UIViewController<MPTypeDelegate, UITextFieldDelegate, MPSearchResultsDelegate, UIWebViewDelegate, MFMailComposeViewControllerDelegate, UIGestureRecognizerDelegate>
|
||||||
|
|
||||||
@property (nonatomic, assign) BOOL userNameHidden;
|
@property (nonatomic, assign) BOOL siteInfoHidden;
|
||||||
@property (strong, nonatomic) MPElementEntity *activeElement;
|
@property (strong, nonatomic) MPElementEntity *activeElement;
|
||||||
@property (strong, nonatomic) IBOutlet MPSearchDelegate *searchDelegate;
|
@property (strong, nonatomic) IBOutlet MPSearchDelegate *searchDelegate;
|
||||||
@property (weak, nonatomic) IBOutlet UITextField *contentField;
|
@property (weak, nonatomic) IBOutlet UITextField *contentField;
|
||||||
@ -28,20 +28,20 @@
|
|||||||
@property (weak, nonatomic) IBOutlet UIView *displayContainer;
|
@property (weak, nonatomic) IBOutlet UIView *displayContainer;
|
||||||
@property (weak, nonatomic) IBOutlet UIView *helpContainer;
|
@property (weak, nonatomic) IBOutlet UIView *helpContainer;
|
||||||
@property (weak, nonatomic) IBOutlet UIView *contentTipContainer;
|
@property (weak, nonatomic) IBOutlet UIView *contentTipContainer;
|
||||||
@property (weak, nonatomic) IBOutlet UIView *userNameTipContainer;
|
@property (weak, nonatomic) IBOutlet UIView *loginNameTipContainer;
|
||||||
@property (weak, nonatomic) IBOutlet UIView *alertContainer;
|
@property (weak, nonatomic) IBOutlet UIView *alertContainer;
|
||||||
@property (weak, nonatomic) IBOutlet UILabel *alertTitle;
|
@property (weak, nonatomic) IBOutlet UILabel *alertTitle;
|
||||||
@property (weak, nonatomic) IBOutlet UITextView *alertBody;
|
@property (weak, nonatomic) IBOutlet UITextView *alertBody;
|
||||||
@property (weak, nonatomic) IBOutlet UILabel *contentTipBody;
|
@property (weak, nonatomic) IBOutlet UILabel *contentTipBody;
|
||||||
@property (weak, nonatomic) IBOutlet UILabel *userNameTipBody;
|
@property (weak, nonatomic) IBOutlet UILabel *loginNameTipBody;
|
||||||
@property (weak, nonatomic) IBOutlet UIImageView *toolTipEditIcon;
|
@property (weak, nonatomic) IBOutlet UIImageView *toolTipEditIcon;
|
||||||
@property (weak, nonatomic) IBOutlet UIView *searchTipContainer;
|
@property (weak, nonatomic) IBOutlet UIView *searchTipContainer;
|
||||||
@property (weak, nonatomic) IBOutlet UIView *actionsTipContainer;
|
@property (weak, nonatomic) IBOutlet UIView *actionsTipContainer;
|
||||||
@property (weak, nonatomic) IBOutlet UIView *typeTipContainer;
|
@property (weak, nonatomic) IBOutlet UIView *typeTipContainer;
|
||||||
@property (weak, nonatomic) IBOutlet UIView *toolTipContainer;
|
@property (weak, nonatomic) IBOutlet UIView *toolTipContainer;
|
||||||
@property (weak, nonatomic) IBOutlet UILabel *toolTipBody;
|
@property (weak, nonatomic) IBOutlet UILabel *toolTipBody;
|
||||||
@property (weak, nonatomic) IBOutlet UIView *userNameContainer;
|
@property (weak, nonatomic) IBOutlet UIView *loginNameContainer;
|
||||||
@property (weak, nonatomic) IBOutlet UITextField *userNameField;
|
@property (weak, nonatomic) IBOutlet UITextField *loginNameField;
|
||||||
@property (weak, nonatomic) IBOutlet UIButton *passwordUser;
|
@property (weak, nonatomic) IBOutlet UIButton *passwordUser;
|
||||||
@property (weak, nonatomic) IBOutlet UIView *outdatedAlertContainer;
|
@property (weak, nonatomic) IBOutlet UIView *outdatedAlertContainer;
|
||||||
@property (weak, nonatomic) IBOutlet UIImageView *outdatedAlertBack;
|
@property (weak, nonatomic) IBOutlet UIImageView *outdatedAlertBack;
|
||||||
@ -54,7 +54,7 @@
|
|||||||
- (IBAction)copyContent;
|
- (IBAction)copyContent;
|
||||||
- (IBAction)incrementPasswordCounter;
|
- (IBAction)incrementPasswordCounter;
|
||||||
- (IBAction)resetPasswordCounter:(UILongPressGestureRecognizer *)sender;
|
- (IBAction)resetPasswordCounter:(UILongPressGestureRecognizer *)sender;
|
||||||
- (IBAction)editUserName:(UILongPressGestureRecognizer *)sender;
|
- (IBAction)editLoginName:(UILongPressGestureRecognizer *)sender;
|
||||||
- (IBAction)editPassword;
|
- (IBAction)editPassword;
|
||||||
- (IBAction)closeAlert;
|
- (IBAction)closeAlert;
|
||||||
- (IBAction)upgradePassword;
|
- (IBAction)upgradePassword;
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
|
|
||||||
@implementation MPMainViewController
|
@implementation MPMainViewController
|
||||||
@synthesize userNameHidden = _userNameHidden;
|
@synthesize siteInfoHidden = _siteInfoHidden;
|
||||||
@synthesize activeElement = _activeElement;
|
@synthesize activeElement = _activeElement;
|
||||||
@synthesize searchDelegate = _searchDelegate;
|
@synthesize searchDelegate = _searchDelegate;
|
||||||
@synthesize typeButton = _typeButton;
|
@synthesize typeButton = _typeButton;
|
||||||
@ -28,20 +28,20 @@
|
|||||||
@synthesize displayContainer = _displayContainer;
|
@synthesize displayContainer = _displayContainer;
|
||||||
@synthesize helpContainer = _helpContainer;
|
@synthesize helpContainer = _helpContainer;
|
||||||
@synthesize contentTipContainer = _copiedContainer;
|
@synthesize contentTipContainer = _copiedContainer;
|
||||||
@synthesize userNameTipContainer = _userNameTipContainer;
|
@synthesize loginNameTipContainer = _loginNameTipContainer;
|
||||||
@synthesize alertContainer = _alertContainer;
|
@synthesize alertContainer = _alertContainer;
|
||||||
@synthesize alertTitle = _alertTitle;
|
@synthesize alertTitle = _alertTitle;
|
||||||
@synthesize alertBody = _alertBody;
|
@synthesize alertBody = _alertBody;
|
||||||
@synthesize contentTipBody = _contentTipBody;
|
@synthesize contentTipBody = _contentTipBody;
|
||||||
@synthesize userNameTipBody = _userNameTipBody;
|
@synthesize loginNameTipBody = _loginNameTipBody;
|
||||||
@synthesize toolTipEditIcon = _contentTipEditIcon;
|
@synthesize toolTipEditIcon = _contentTipEditIcon;
|
||||||
@synthesize searchTipContainer = _searchTipContainer;
|
@synthesize searchTipContainer = _searchTipContainer;
|
||||||
@synthesize actionsTipContainer = _actionsTipContainer;
|
@synthesize actionsTipContainer = _actionsTipContainer;
|
||||||
@synthesize typeTipContainer = _typeTipContainer;
|
@synthesize typeTipContainer = _typeTipContainer;
|
||||||
@synthesize toolTipContainer = _toolTipContainer;
|
@synthesize toolTipContainer = _toolTipContainer;
|
||||||
@synthesize toolTipBody = _toolTipBody;
|
@synthesize toolTipBody = _toolTipBody;
|
||||||
@synthesize userNameContainer = _userNameContainer;
|
@synthesize loginNameContainer = _loginNameContainer;
|
||||||
@synthesize userNameField = _userNameField;
|
@synthesize loginNameField = _loginNameField;
|
||||||
@synthesize passwordUser = _passwordUser;
|
@synthesize passwordUser = _passwordUser;
|
||||||
@synthesize outdatedAlertContainer = _outdatedAlertContainer;
|
@synthesize outdatedAlertContainer = _outdatedAlertContainer;
|
||||||
@synthesize outdatedAlertBack = _outdatedAlertBack;
|
@synthesize outdatedAlertBack = _outdatedAlertBack;
|
||||||
@ -82,9 +82,9 @@
|
|||||||
|
|
||||||
[self.passwordIncrementer addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self
|
[self.passwordIncrementer addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self
|
||||||
action:@selector(resetPasswordCounter:)]];
|
action:@selector(resetPasswordCounter:)]];
|
||||||
[self.userNameContainer addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self
|
[self.loginNameContainer addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self
|
||||||
action:@selector(editUserName:)]];
|
action:@selector(editLoginName:)]];
|
||||||
[self.userNameContainer addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(copyUserName:)]];
|
[self.loginNameContainer addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(copyLoginName:)]];
|
||||||
[self.outdatedAlertBack addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self
|
[self.outdatedAlertBack addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self
|
||||||
action:@selector(infoOutdatedAlert)]];
|
action:@selector(infoOutdatedAlert)]];
|
||||||
|
|
||||||
@ -225,10 +225,10 @@
|
|||||||
[self setToolTipContainer:nil];
|
[self setToolTipContainer:nil];
|
||||||
[self setToolTipBody:nil];
|
[self setToolTipBody:nil];
|
||||||
[self setDisplayContainer:nil];
|
[self setDisplayContainer:nil];
|
||||||
[self setUserNameField:nil];
|
[self setLoginNameField:nil];
|
||||||
[self setUserNameTipContainer:nil];
|
[self setLoginNameTipContainer:nil];
|
||||||
[self setUserNameTipBody:nil];
|
[self setLoginNameTipBody:nil];
|
||||||
[self setUserNameContainer:nil];
|
[self setLoginNameContainer:nil];
|
||||||
[self setPasswordUser:nil];
|
[self setPasswordUser:nil];
|
||||||
[self setOutdatedAlertContainer:nil];
|
[self setOutdatedAlertContainer:nil];
|
||||||
[self setOutdatedAlertCloseButton:nil];
|
[self setOutdatedAlertCloseButton:nil];
|
||||||
@ -289,9 +289,9 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
self.userNameField.enabled = NO;
|
self.loginNameField.enabled = NO;
|
||||||
self.userNameField.text = self.activeElement.userName;
|
self.loginNameField.text = self.activeElement.loginName;
|
||||||
self.userNameHidden = !self.activeElement || ([[MPiOSConfig get].userNameHidden boolValue] && (self.activeElement.userName
|
self.siteInfoHidden = !self.activeElement || ([[MPiOSConfig get].siteInfoHidden boolValue] && (self.activeElement.loginName
|
||||||
== nil));
|
== nil));
|
||||||
[self updateUserHiddenAnimated:NO];
|
[self updateUserHiddenAnimated:NO];
|
||||||
}
|
}
|
||||||
@ -333,8 +333,8 @@
|
|||||||
|
|
||||||
- (void)toggleUserAnimated:(BOOL)animated {
|
- (void)toggleUserAnimated:(BOOL)animated {
|
||||||
|
|
||||||
[MPiOSConfig get].userNameHidden = PearlBool(!self.userNameHidden);
|
[MPiOSConfig get].siteInfoHidden = PearlBool(!self.siteInfoHidden);
|
||||||
self.userNameHidden = [[MPiOSConfig get].userNameHidden boolValue];
|
self.siteInfoHidden = [[MPiOSConfig get].siteInfoHidden boolValue];
|
||||||
[self updateUserHiddenAnimated:animated];
|
[self updateUserHiddenAnimated:animated];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,7 +347,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.userNameHidden) {
|
if (self.siteInfoHidden) {
|
||||||
self.displayContainer.frame = CGRectSetHeight(self.displayContainer.frame, 87);
|
self.displayContainer.frame = CGRectSetHeight(self.displayContainer.frame, 87);
|
||||||
} else {
|
} else {
|
||||||
self.displayContainer.frame = CGRectSetHeight(self.displayContainer.frame, 137);
|
self.displayContainer.frame = CGRectSetHeight(self.displayContainer.frame, 137);
|
||||||
@ -402,19 +402,19 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)showUserNameTip:(NSString *)message {
|
- (void)showLoginNameTip:(NSString *)message {
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
self.userNameTipBody.text = message;
|
self.loginNameTipBody.text = message;
|
||||||
|
|
||||||
[UIView animateWithDuration:0.3f animations:^{
|
[UIView animateWithDuration:0.3f animations:^{
|
||||||
self.userNameTipContainer.alpha = 1;
|
self.loginNameTipContainer.alpha = 1;
|
||||||
} completion:^(BOOL finished) {
|
} completion:^(BOOL finished) {
|
||||||
if (finished) {
|
if (finished) {
|
||||||
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC);
|
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC);
|
||||||
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
|
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
|
||||||
[UIView animateWithDuration:0.2f animations:^{
|
[UIView animateWithDuration:0.2f animations:^{
|
||||||
self.userNameTipContainer.alpha = 0;
|
self.loginNameTipContainer.alpha = 0;
|
||||||
}];
|
}];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -488,18 +488,18 @@
|
|||||||
nil]];
|
nil]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)copyUserName:(UITapGestureRecognizer *)sender {
|
- (IBAction)copyLoginName:(UITapGestureRecognizer *)sender {
|
||||||
|
|
||||||
if (!self.activeElement.userName)
|
if (!self.activeElement.loginName)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
inf(@"Copying user name for: %@", self.activeElement.name);
|
inf(@"Copying user name for: %@", self.activeElement.name);
|
||||||
[UIPasteboard generalPasteboard].string = [self.activeElement.content description];
|
[UIPasteboard generalPasteboard].string = [self.activeElement.content description];
|
||||||
|
|
||||||
[self showUserNameTip:@"Copied!"];
|
[self showLoginNameTip:@"Copied!"];
|
||||||
|
|
||||||
[TestFlight passCheckpoint:MPCheckpointCopyUserNameToPasteboard];
|
[TestFlight passCheckpoint:MPCheckpointCopyLoginNameToPasteboard];
|
||||||
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCopyUserNameToPasteboard
|
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCopyLoginNameToPasteboard
|
||||||
attributes:[NSDictionary dictionaryWithObjectsAndKeys:
|
attributes:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
self.activeElement.typeName, @"type",
|
self.activeElement.typeName, @"type",
|
||||||
PearlUnsignedInteger(self.activeElement.version),
|
PearlUnsignedInteger(self.activeElement.version),
|
||||||
@ -564,7 +564,7 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)editUserName:(UILongPressGestureRecognizer *)sender {
|
- (IBAction)editLoginName:(UILongPressGestureRecognizer *)sender {
|
||||||
|
|
||||||
if (sender.state != UIGestureRecognizerStateBegan)
|
if (sender.state != UIGestureRecognizerStateBegan)
|
||||||
// Only fire when the gesture was first detected.
|
// Only fire when the gesture was first detected.
|
||||||
@ -573,11 +573,11 @@
|
|||||||
if (!self.activeElement)
|
if (!self.activeElement)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
self.userNameField.enabled = YES;
|
self.loginNameField.enabled = YES;
|
||||||
[self.userNameField becomeFirstResponder];
|
[self.loginNameField becomeFirstResponder];
|
||||||
|
|
||||||
[TestFlight passCheckpoint:MPCheckpointEditUserName];
|
[TestFlight passCheckpoint:MPCheckpointEditLoginName];
|
||||||
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointEditUserName attributes:[NSDictionary dictionaryWithObjectsAndKeys:
|
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointEditLoginName attributes:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
self.activeElement.typeName,
|
self.activeElement.typeName,
|
||||||
@"type",
|
@"type",
|
||||||
PearlUnsignedInteger(self.activeElement.version),
|
PearlUnsignedInteger(self.activeElement.version),
|
||||||
@ -903,8 +903,8 @@
|
|||||||
|
|
||||||
if (textField == self.contentField)
|
if (textField == self.contentField)
|
||||||
[self.contentField resignFirstResponder];
|
[self.contentField resignFirstResponder];
|
||||||
if (textField == self.userNameField)
|
if (textField == self.loginNameField)
|
||||||
[self.userNameField resignFirstResponder];
|
[self.loginNameField resignFirstResponder];
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
@ -926,17 +926,17 @@
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (textField == self.userNameField) {
|
if (textField == self.loginNameField) {
|
||||||
self.userNameField.enabled = NO;
|
self.loginNameField.enabled = NO;
|
||||||
if (![[MPiOSConfig get].userNameTipShown boolValue]) {
|
if (![[MPiOSConfig get].loginNameTipShown boolValue]) {
|
||||||
[self showUserNameTip:@"Tap to copy or hold to edit."];
|
[self showLoginNameTip:@"Tap to copy or hold to edit."];
|
||||||
[MPiOSConfig get].userNameTipShown = PearlBool(YES);
|
[MPiOSConfig get].loginNameTipShown = PearlBool(YES);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([self.userNameField.text length])
|
if ([self.loginNameField.text length])
|
||||||
self.activeElement.userName = self.userNameField.text;
|
self.activeElement.loginName = self.loginNameField.text;
|
||||||
else
|
else
|
||||||
self.activeElement.userName = nil;
|
self.activeElement.loginName = nil;
|
||||||
|
|
||||||
[[MPAppDelegate get] saveContext];
|
[[MPAppDelegate get] saveContext];
|
||||||
}
|
}
|
||||||
|
@ -218,9 +218,15 @@
|
|||||||
self.tip.text = @"Tap and hold to delete or reset.";
|
self.tip.text = @"Tap and hold to delete or reset.";
|
||||||
[self.loadingUsersIndicator stopAnimating];
|
[self.loadingUsersIndicator stopAnimating];
|
||||||
|
|
||||||
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPUserEntity class])];
|
__block NSArray *users = nil;
|
||||||
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"lastUsed" ascending:NO]];
|
[moc performBlockAndWait:^{
|
||||||
NSArray *users = [moc executeFetchRequest:fetchRequest error:nil];
|
NSError *error = nil;
|
||||||
|
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPUserEntity class])];
|
||||||
|
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"lastUsed" ascending:NO]];
|
||||||
|
users = [moc executeFetchRequest:fetchRequest error:&error];
|
||||||
|
if (!users)
|
||||||
|
err(@"Failed to load users: %@", error);
|
||||||
|
}];
|
||||||
|
|
||||||
// Clean up avatars.
|
// Clean up avatars.
|
||||||
for (UIView *subview in [self.avatarsView subviews])
|
for (UIView *subview in [self.avatarsView subviews])
|
||||||
@ -275,8 +281,10 @@
|
|||||||
|
|
||||||
[self.avatarToUser setObject:NilToNSNull(user) forKey:[NSValue valueWithNonretainedObject:avatar]];
|
[self.avatarToUser setObject:NilToNSNull(user) forKey:[NSValue valueWithNonretainedObject:avatar]];
|
||||||
|
|
||||||
if (self.selectedUser && user == self.selectedUser)
|
if ([self.selectedUser.objectID isEqual:user.objectID]) {
|
||||||
|
self.selectedUser = user;
|
||||||
avatar.selected = YES;
|
avatar.selected = YES;
|
||||||
|
}
|
||||||
|
|
||||||
return avatar;
|
return avatar;
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,11 @@
|
|||||||
|
|
||||||
@property (nonatomic, retain) NSNumber *sendInfo;
|
@property (nonatomic, retain) NSNumber *sendInfo;
|
||||||
@property (nonatomic, retain) NSNumber *helpHidden;
|
@property (nonatomic, retain) NSNumber *helpHidden;
|
||||||
@property (nonatomic, retain) NSNumber *userNameHidden;
|
@property (nonatomic, retain) NSNumber *siteInfoHidden;
|
||||||
@property (nonatomic, retain) NSNumber *showQuickStart;
|
@property (nonatomic, retain) NSNumber *showQuickStart;
|
||||||
@property (nonatomic, retain) NSNumber *actionsTipShown;
|
@property (nonatomic, retain) NSNumber *actionsTipShown;
|
||||||
@property (nonatomic, retain) NSNumber *typeTipShown;
|
@property (nonatomic, retain) NSNumber *typeTipShown;
|
||||||
@property (nonatomic, retain) NSNumber *userNameTipShown;
|
@property (nonatomic, retain) NSNumber *loginNameTipShown;
|
||||||
|
|
||||||
+ (MPiOSConfig *)get;
|
+ (MPiOSConfig *)get;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
@implementation MPiOSConfig
|
@implementation MPiOSConfig
|
||||||
@dynamic sendInfo, helpHidden, userNameHidden, showQuickStart, actionsTipShown, typeTipShown, userNameTipShown;
|
@dynamic sendInfo, helpHidden, siteInfoHidden, showQuickStart, actionsTipShown, typeTipShown, loginNameTipShown;
|
||||||
|
|
||||||
- (id)init {
|
- (id)init {
|
||||||
|
|
||||||
@ -17,12 +17,12 @@
|
|||||||
[self.defaults registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
|
[self.defaults registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(sendInfo)),
|
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(sendInfo)),
|
||||||
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(helpHidden)),
|
[NSNumber numberWithBool:NO], NSStringFromSelector(@selector(helpHidden)),
|
||||||
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(userNameHidden)),
|
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(siteInfoHidden)),
|
||||||
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(showQuickStart)),
|
[NSNumber numberWithBool:YES], NSStringFromSelector(@selector(showQuickStart)),
|
||||||
@"510296984", NSStringFromSelector(@selector(iTunesID)),
|
@"510296984", NSStringFromSelector(@selector(iTunesID)),
|
||||||
PearlBoolNot(self.firstRun), NSStringFromSelector(@selector(actionsTipShown)),
|
PearlBoolNot(self.firstRun), NSStringFromSelector(@selector(actionsTipShown)),
|
||||||
PearlBoolNot(self.firstRun), NSStringFromSelector(@selector(typeTipShown)),
|
PearlBoolNot(self.firstRun), NSStringFromSelector(@selector(typeTipShown)),
|
||||||
PearlBool(NO), NSStringFromSelector(@selector(userNameTipShown)),
|
PearlBool(NO), NSStringFromSelector(@selector(loginNameTipShown)),
|
||||||
nil]];
|
nil]];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
@ -811,12 +811,12 @@ L4m3P4sSw0rD</string>
|
|||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" userInteractionEnabled="NO" contentMode="scaleToFill" editable="NO" id="HPZ-qz-fpL">
|
<textView clipsSubviews="YES" multipleTouchEnabled="YES" userInteractionEnabled="NO" contentMode="scaleToFill" editable="NO" id="HPZ-qz-fpL">
|
||||||
<rect key="frame" x="20" y="60" width="260" height="130"/>
|
<rect key="frame" x="20" y="52" width="260" height="108"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||||
<string key="text">Some of your sites have outdated passwords. Tap this alert for more info or to find them.
|
<string key="text">Some of your sites use outdated passwords. Tap this alert for more info or to find them.
|
||||||
|
|
||||||
You should upgrade these sites and update their account's passwords as soon as is convenient.</string>
|
These sites should be upgraded and their account's passwords updated as soon as convenient.</string>
|
||||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
|
||||||
@ -854,7 +854,7 @@ You should upgrade these sites and update their account's passwords as soon as i
|
|||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="Sfy-hx-kVU">
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="Sfy-hx-kVU">
|
||||||
<rect key="frame" x="184" y="81" width="22" height="22"/>
|
<rect key="frame" x="183" y="73" width="22" height="22"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
|
||||||
<accessibility key="accessibilityConfiguration" hint="" label="Close"/>
|
<accessibility key="accessibilityConfiguration" hint="" label="Close"/>
|
||||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
|
||||||
@ -911,10 +911,10 @@ You should upgrade these sites and update their account's passwords as soon as i
|
|||||||
<outlet property="toolTipEditIcon" destination="KEn-n3-qhX" id="zEV-tR-Egq"/>
|
<outlet property="toolTipEditIcon" destination="KEn-n3-qhX" id="zEV-tR-Egq"/>
|
||||||
<outlet property="typeButton" destination="xYM-e3-BMg" id="xvn-nR-MRV"/>
|
<outlet property="typeButton" destination="xYM-e3-BMg" id="xvn-nR-MRV"/>
|
||||||
<outlet property="typeTipContainer" destination="g55-0m-WjS" id="KZ9-KV-NMh"/>
|
<outlet property="typeTipContainer" destination="g55-0m-WjS" id="KZ9-KV-NMh"/>
|
||||||
<outlet property="userNameContainer" destination="lrZ-PV-rgu" id="tTh-fp-qaN"/>
|
<outlet property="loginNameContainer" destination="lrZ-PV-rgu" id="tTh-fp-qaN"/>
|
||||||
<outlet property="userNameField" destination="tj6-Ot-Fuh" id="oFa-xd-UEm"/>
|
<outlet property="loginNameField" destination="tj6-Ot-Fuh" id="oFa-xd-UEm"/>
|
||||||
<outlet property="userNameTipBody" destination="coX-1P-dqm" id="MRt-A5-ZMH"/>
|
<outlet property="loginNameTipBody" destination="coX-1P-dqm" id="MRt-A5-ZMH"/>
|
||||||
<outlet property="userNameTipContainer" destination="b9W-aA-93r" id="heZ-Gu-obO"/>
|
<outlet property="loginNameTipContainer" destination="b9W-aA-93r" id="heZ-Gu-obO"/>
|
||||||
<segue destination="oLN-6u-GLb" kind="push" identifier="UserProfile" id="tKN-Sw-S5J"/>
|
<segue destination="oLN-6u-GLb" kind="push" identifier="UserProfile" id="tKN-Sw-S5J"/>
|
||||||
</connections>
|
</connections>
|
||||||
</viewController>
|
</viewController>
|
||||||
@ -1890,10 +1890,10 @@ You could use the word wall for inspiration in finding a memorable master passw
|
|||||||
<relationship kind="outlet" name="toolTipEditIcon" candidateClass="UIImageView"/>
|
<relationship kind="outlet" name="toolTipEditIcon" candidateClass="UIImageView"/>
|
||||||
<relationship kind="outlet" name="typeButton" candidateClass="UIButton"/>
|
<relationship kind="outlet" name="typeButton" candidateClass="UIButton"/>
|
||||||
<relationship kind="outlet" name="typeTipContainer" candidateClass="UIView"/>
|
<relationship kind="outlet" name="typeTipContainer" candidateClass="UIView"/>
|
||||||
<relationship kind="outlet" name="userNameContainer" candidateClass="UIView"/>
|
<relationship kind="outlet" name="loginNameContainer" candidateClass="UIView"/>
|
||||||
<relationship kind="outlet" name="userNameField" candidateClass="UITextField"/>
|
<relationship kind="outlet" name="loginNameField" candidateClass="UITextField"/>
|
||||||
<relationship kind="outlet" name="userNameTipBody" candidateClass="UILabel"/>
|
<relationship kind="outlet" name="loginNameTipBody" candidateClass="UILabel"/>
|
||||||
<relationship kind="outlet" name="userNameTipContainer" candidateClass="UIView"/>
|
<relationship kind="outlet" name="loginNameTipContainer" candidateClass="UIView"/>
|
||||||
</relationships>
|
</relationships>
|
||||||
</class>
|
</class>
|
||||||
<class className="MPPreferencesViewController" superclassName="UITableViewController">
|
<class className="MPPreferencesViewController" superclassName="UITableViewController">
|
||||||
@ -1951,6 +1951,6 @@ You could use the word wall for inspiration in finding a memorable master passw
|
|||||||
<simulatedScreenMetrics key="destination"/>
|
<simulatedScreenMetrics key="destination"/>
|
||||||
</simulatedMetricsContainer>
|
</simulatedMetricsContainer>
|
||||||
<inferredMetricsTieBreakers>
|
<inferredMetricsTieBreakers>
|
||||||
<segue reference="KIl-ZW-M7G"/>
|
<segue reference="9Bs-cD-ddF"/>
|
||||||
</inferredMetricsTieBreakers>
|
</inferredMetricsTieBreakers>
|
||||||
</document>
|
</document>
|
Loading…
Reference in New Issue
Block a user