diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 00000000..e206d70d
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/.idea/projectCodeStyle.xml b/.idea/projectCodeStyle.xml
new file mode 100644
index 00000000..7b758907
--- /dev/null
+++ b/.idea/projectCodeStyle.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
diff --git a/External/Pearl b/External/Pearl
index de35f576..3cca78c6 160000
--- a/External/Pearl
+++ b/External/Pearl
@@ -1 +1 @@
-Subproject commit de35f576ee290551f282c036f43313b15b2b6594
+Subproject commit 3cca78c6ebc874ef3168e674dbb7391f9a6dec52
diff --git a/OnePassword.xcodeproj/project.pbxproj b/OnePassword.xcodeproj/project.pbxproj
index acda3b9c..a2caa33b 100644
--- a/OnePassword.xcodeproj/project.pbxproj
+++ b/OnePassword.xcodeproj/project.pbxproj
@@ -7,6 +7,15 @@
objects = {
/* Begin PBXBuildFile section */
+ DA007F5214B24DCD00251337 /* OPConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = DA007F5114B24DCD00251337 /* OPConfig.m */; };
+ DA007F5514B25EE100251337 /* ciphers.plist in Resources */ = {isa = PBXBuildFile; fileRef = DA007F5414B25EE100251337 /* ciphers.plist */; };
+ DA007F5614B26EFA00251337 /* Pearl.strings in Resources */ = {isa = PBXBuildFile; fileRef = DAC77CD41482AAD600BCF976 /* Pearl.strings */; };
+ DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */; };
+ DA34DA0D14B1BC7D00F721C1 /* OPElementStoredEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA34DA0C14B1BC7D00F721C1 /* OPElementStoredEntity.m */; };
+ DA34DA1114B1BC7E00F721C1 /* OPElementEntity.m in Sources */ = {isa = PBXBuildFile; fileRef = DA34DA1014B1BC7E00F721C1 /* OPElementEntity.m */; };
+ DA34DA1614B1BEA100F721C1 /* OPTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = DA34DA1514B1BEA100F721C1 /* OPTypes.m */; };
+ DA55B29E14B38272001131B7 /* OPContentViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA55B29D14B38272001131B7 /* OPContentViewController.m */; };
+ DA55B2A214B4EB47001131B7 /* OPSearchDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DA55B2A114B4EB46001131B7 /* OPSearchDelegate.m */; };
DA5BFA49147E415C00F98B1E /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA48147E415C00F98B1E /* UIKit.framework */; };
DA5BFA4B147E415C00F98B1E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DA5BFA4D147E415C00F98B1E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4C147E415C00F98B1E /* CoreGraphics.framework */; };
@@ -18,7 +27,37 @@
DA5BFA61147E415C00F98B1E /* MainStoryboard_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DA5BFA5F147E415C00F98B1E /* MainStoryboard_iPad.storyboard */; };
DA5BFA64147E415C00F98B1E /* OnePassword.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DA5BFA62147E415C00F98B1E /* OnePassword.xcdatamodeld */; };
DA5BFA67147E415C00F98B1E /* OPMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5BFA66147E415C00F98B1E /* OPMainViewController.m */; };
- DAC63257148679600075AEA5 /* OPSaltedCipherViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DAC63256148679600075AEA5 /* OPSaltedCipherViewController.m */; };
+ DA7C28C414AF078900491972 /* Bold_Lines.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28A514AF078900491972 /* Bold_Lines.png */; };
+ DA7C28C514AF078900491972 /* Box.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28A614AF078900491972 /* Box.png */; };
+ DA7C28C614AF078900491972 /* Dashed_Divider.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28A714AF078900491972 /* Dashed_Divider.png */; };
+ DA7C28C714AF078900491972 /* Dashed_Divider_.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28A814AF078900491972 /* Dashed_Divider_.png */; };
+ DA7C28C814AF078900491972 /* Dashed_Divider_Highlight.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28A914AF078900491972 /* Dashed_Divider_Highlight.png */; };
+ DA7C28C914AF078900491972 /* Dotted_Dividers.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28AA14AF078900491972 /* Dotted_Dividers.png */; };
+ DA7C28CA14AF078900491972 /* Doubble_Shadow_.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28AB14AF078900491972 /* Doubble_Shadow_.png */; };
+ DA7C28CB14AF078900491972 /* Double.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28AC14AF078900491972 /* Double.png */; };
+ DA7C28CC14AF078900491972 /* Double_Page.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28AD14AF078900491972 /* Double_Page.png */; };
+ DA7C28CD14AF078900491972 /* Double_Page_2.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28AE14AF078900491972 /* Double_Page_2.png */; };
+ DA7C28CE14AF078900491972 /* Double_Shadow.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28AF14AF078900491972 /* Double_Shadow.png */; };
+ DA7C28CF14AF078900491972 /* Double_With_White.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28B014AF078900491972 /* Double_With_White.png */; };
+ DA7C28D014AF078900491972 /* Double_With_White_Strong.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28B114AF078900491972 /* Double_With_White_Strong.png */; };
+ DA7C28D114AF078900491972 /* Help.rtf in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28B214AF078900491972 /* Help.rtf */; };
+ DA7C28D214AF078900491972 /* Highlight_Smooth_Divider.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28B314AF078900491972 /* Highlight_Smooth_Divider.png */; };
+ DA7C28D314AF078900491972 /* Highlight_Smooth_Divider_copy.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28B414AF078900491972 /* Highlight_Smooth_Divider_copy.png */; };
+ DA7C28D414AF078900491972 /* Highlight_StrongDivider_copy_3.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28B514AF078900491972 /* Highlight_StrongDivider_copy_3.png */; };
+ DA7C28D514AF078900491972 /* Page.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28B614AF078900491972 /* Page.png */; };
+ DA7C28D614AF078900491972 /* Rectangular.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28B714AF078900491972 /* Rectangular.png */; };
+ DA7C28D714AF078900491972 /* Rounded.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28B814AF078900491972 /* Rounded.png */; };
+ DA7C28D814AF078900491972 /* Rounded_Inverted.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28B914AF078900491972 /* Rounded_Inverted.png */; };
+ DA7C28D914AF078900491972 /* Simple.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28BA14AF078900491972 /* Simple.png */; };
+ DA7C28DA14AF078900491972 /* Simple_Divider.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28BB14AF078900491972 /* Simple_Divider.png */; };
+ DA7C28DB14AF078900491972 /* Simple_Divider_.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28BC14AF078900491972 /* Simple_Divider_.png */; };
+ DA7C28DC14AF078900491972 /* Simple_Divider__Strong.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28BD14AF078900491972 /* Simple_Divider__Strong.png */; };
+ DA7C28DD14AF078900491972 /* Simple_Divider_Strong.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28BE14AF078900491972 /* Simple_Divider_Strong.png */; };
+ DA7C28DE14AF078900491972 /* Single_Shadow.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28BF14AF078900491972 /* Single_Shadow.png */; };
+ DA7C28DF14AF078900491972 /* Single_Shadow_.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28C014AF078900491972 /* Single_Shadow_.png */; };
+ DA7C28E014AF078900491972 /* Smooth_Divider.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28C114AF078900491972 /* Smooth_Divider.png */; };
+ DA7C28E114AF078900491972 /* Square.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28C214AF078900491972 /* Square.png */; };
+ DA7C28E214AF078900491972 /* White_Rectangular.png in Resources */ = {isa = PBXBuildFile; fileRef = DA7C28C314AF078900491972 /* White_Rectangular.png */; };
DAC6325E1486805C0075AEA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DAC6326D148680650075AEA5 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA5BFA4A147E415C00F98B1E /* Foundation.framework */; };
DAC63277148680700075AEA5 /* libuicolor-utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */; };
@@ -126,6 +165,20 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
+ DA007F5014B24DCC00251337 /* OPConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OPConfig.h; sourceTree = ""; };
+ DA007F5114B24DCD00251337 /* OPConfig.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OPConfig.m; sourceTree = ""; };
+ DA007F5414B25EE100251337 /* ciphers.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = ciphers.plist; sourceTree = ""; };
+ DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
+ DA34DA0B14B1BC7D00F721C1 /* OPElementStoredEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OPElementStoredEntity.h; sourceTree = ""; };
+ DA34DA0C14B1BC7D00F721C1 /* OPElementStoredEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OPElementStoredEntity.m; sourceTree = ""; };
+ DA34DA0F14B1BC7E00F721C1 /* OPElementEntity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OPElementEntity.h; sourceTree = ""; };
+ DA34DA1014B1BC7E00F721C1 /* OPElementEntity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OPElementEntity.m; sourceTree = ""; };
+ DA34DA1414B1BEA100F721C1 /* OPTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OPTypes.h; sourceTree = ""; };
+ DA34DA1514B1BEA100F721C1 /* OPTypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OPTypes.m; sourceTree = ""; };
+ DA55B29C14B38272001131B7 /* OPContentViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OPContentViewController.h; sourceTree = ""; };
+ DA55B29D14B38272001131B7 /* OPContentViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OPContentViewController.m; sourceTree = ""; };
+ DA55B2A014B4EB46001131B7 /* OPSearchDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OPSearchDelegate.h; sourceTree = ""; };
+ DA55B2A114B4EB46001131B7 /* OPSearchDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OPSearchDelegate.m; sourceTree = ""; };
DA5BFA44147E415C00F98B1E /* OnePassword.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OnePassword.app; sourceTree = BUILT_PRODUCTS_DIR; };
DA5BFA48147E415C00F98B1E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
DA5BFA4A147E415C00F98B1E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
@@ -142,8 +195,37 @@
DA5BFA63147E415C00F98B1E /* OnePassword.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = OnePassword.xcdatamodel; sourceTree = ""; };
DA5BFA65147E415C00F98B1E /* OPMainViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OPMainViewController.h; sourceTree = ""; };
DA5BFA66147E415C00F98B1E /* OPMainViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OPMainViewController.m; sourceTree = ""; };
- DAC63255148679600075AEA5 /* OPSaltedCipherViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OPSaltedCipherViewController.h; sourceTree = ""; };
- DAC63256148679600075AEA5 /* OPSaltedCipherViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OPSaltedCipherViewController.m; sourceTree = ""; };
+ DA7C28A514AF078900491972 /* Bold_Lines.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Bold_Lines.png; sourceTree = ""; };
+ DA7C28A614AF078900491972 /* Box.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Box.png; sourceTree = ""; };
+ DA7C28A714AF078900491972 /* Dashed_Divider.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Dashed_Divider.png; sourceTree = ""; };
+ DA7C28A814AF078900491972 /* Dashed_Divider_.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Dashed_Divider_.png; sourceTree = ""; };
+ DA7C28A914AF078900491972 /* Dashed_Divider_Highlight.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Dashed_Divider_Highlight.png; sourceTree = ""; };
+ DA7C28AA14AF078900491972 /* Dotted_Dividers.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Dotted_Dividers.png; sourceTree = ""; };
+ DA7C28AB14AF078900491972 /* Doubble_Shadow_.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Doubble_Shadow_.png; sourceTree = ""; };
+ DA7C28AC14AF078900491972 /* Double.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Double.png; sourceTree = ""; };
+ DA7C28AD14AF078900491972 /* Double_Page.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Double_Page.png; sourceTree = ""; };
+ DA7C28AE14AF078900491972 /* Double_Page_2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Double_Page_2.png; sourceTree = ""; };
+ DA7C28AF14AF078900491972 /* Double_Shadow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Double_Shadow.png; sourceTree = ""; };
+ DA7C28B014AF078900491972 /* Double_With_White.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Double_With_White.png; sourceTree = ""; };
+ DA7C28B114AF078900491972 /* Double_With_White_Strong.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Double_With_White_Strong.png; sourceTree = ""; };
+ DA7C28B214AF078900491972 /* Help.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; path = Help.rtf; sourceTree = ""; };
+ DA7C28B314AF078900491972 /* Highlight_Smooth_Divider.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Highlight_Smooth_Divider.png; sourceTree = ""; };
+ DA7C28B414AF078900491972 /* Highlight_Smooth_Divider_copy.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Highlight_Smooth_Divider_copy.png; sourceTree = ""; };
+ DA7C28B514AF078900491972 /* Highlight_StrongDivider_copy_3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Highlight_StrongDivider_copy_3.png; sourceTree = ""; };
+ DA7C28B614AF078900491972 /* Page.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Page.png; sourceTree = ""; };
+ DA7C28B714AF078900491972 /* Rectangular.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Rectangular.png; sourceTree = ""; };
+ DA7C28B814AF078900491972 /* Rounded.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Rounded.png; sourceTree = ""; };
+ DA7C28B914AF078900491972 /* Rounded_Inverted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Rounded_Inverted.png; sourceTree = ""; };
+ DA7C28BA14AF078900491972 /* Simple.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Simple.png; sourceTree = ""; };
+ DA7C28BB14AF078900491972 /* Simple_Divider.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Simple_Divider.png; sourceTree = ""; };
+ DA7C28BC14AF078900491972 /* Simple_Divider_.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Simple_Divider_.png; sourceTree = ""; };
+ DA7C28BD14AF078900491972 /* Simple_Divider__Strong.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Simple_Divider__Strong.png; sourceTree = ""; };
+ DA7C28BE14AF078900491972 /* Simple_Divider_Strong.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Simple_Divider_Strong.png; sourceTree = ""; };
+ DA7C28BF14AF078900491972 /* Single_Shadow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Single_Shadow.png; sourceTree = ""; };
+ DA7C28C014AF078900491972 /* Single_Shadow_.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Single_Shadow_.png; sourceTree = ""; };
+ DA7C28C114AF078900491972 /* Smooth_Divider.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Smooth_Divider.png; sourceTree = ""; };
+ DA7C28C214AF078900491972 /* Square.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Square.png; sourceTree = ""; };
+ DA7C28C314AF078900491972 /* White_Rectangular.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = White_Rectangular.png; sourceTree = ""; };
DAC6325D1486805C0075AEA5 /* libuicolor-utilities.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libuicolor-utilities.a"; sourceTree = BUILT_PRODUCTS_DIR; };
DAC6326C148680650075AEA5 /* libjrswizzle.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libjrswizzle.a; sourceTree = BUILT_PRODUCTS_DIR; };
DAC632791486809A0075AEA5 /* JRSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JRSwizzle.h; path = External/Pearl/External/jrswizzle/JRSwizzle.h; sourceTree = SOURCE_ROOT; };
@@ -1235,6 +1317,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ DA04E33E14B1E70400ECA4F3 /* MobileCoreServices.framework in Frameworks */,
DAC632891486D9690075AEA5 /* Security.framework in Frameworks */,
DAC77CB91482929100BCF976 /* libPearl.a in Frameworks */,
DA5BFA49147E415C00F98B1E /* UIKit.framework in Frameworks */,
@@ -1276,6 +1359,7 @@
DA5BFA39147E415C00F98B1E = {
isa = PBXGroup;
children = (
+ DA04E33D14B1E70400ECA4F3 /* MobileCoreServices.framework */,
DAC632871486D95D0075AEA5 /* Security.framework */,
DA5BFA50147E415C00F98B1E /* OnePassword */,
DAC77CAF148291A600BCF976 /* Pearl */,
@@ -1311,20 +1395,25 @@
DA5BFA50147E415C00F98B1E /* OnePassword */ = {
isa = PBXGroup;
children = (
+ DA7C28A214AF02A000491972 /* Models */,
+ DA7C28A314AF02B100491972 /* Data */,
DA5BFA59147E415C00F98B1E /* OPAppDelegate.h */,
DA5BFA5A147E415C00F98B1E /* OPAppDelegate.m */,
- DA5BFA5C147E415C00F98B1E /* MainStoryboard_iPhone.storyboard */,
- DA5BFA5F147E415C00F98B1E /* MainStoryboard_iPad.storyboard */,
DA5BFA65147E415C00F98B1E /* OPMainViewController.h */,
DA5BFA66147E415C00F98B1E /* OPMainViewController.m */,
+ DA55B2A014B4EB46001131B7 /* OPSearchDelegate.h */,
+ DA55B2A114B4EB46001131B7 /* OPSearchDelegate.m */,
DAC781341482E67300BCF976 /* OPRecentViewController.h */,
DAC781351482E67300BCF976 /* OPRecentViewController.m */,
DAE2C645148247E500BA6B10 /* OPTypeViewController.h */,
DAE2C646148247E500BA6B10 /* OPTypeViewController.m */,
- DAC63255148679600075AEA5 /* OPSaltedCipherViewController.h */,
- DAC63256148679600075AEA5 /* OPSaltedCipherViewController.m */,
- DA5BFA62147E415C00F98B1E /* OnePassword.xcdatamodeld */,
+ DA55B29C14B38272001131B7 /* OPContentViewController.h */,
+ DA55B29D14B38272001131B7 /* OPContentViewController.m */,
DA5BFA51147E415C00F98B1E /* Supporting Files */,
+ DA34DA1414B1BEA100F721C1 /* OPTypes.h */,
+ DA34DA1514B1BEA100F721C1 /* OPTypes.m */,
+ DA007F5014B24DCC00251337 /* OPConfig.h */,
+ DA007F5114B24DCD00251337 /* OPConfig.m */,
);
path = OnePassword;
sourceTree = "";
@@ -1332,14 +1421,75 @@
DA5BFA51147E415C00F98B1E /* Supporting Files */ = {
isa = PBXGroup;
children = (
+ DA7C28A414AF078900491972 /* divider */,
DA5BFA52147E415C00F98B1E /* OnePassword-Info.plist */,
DA5BFA53147E415C00F98B1E /* InfoPlist.strings */,
DA5BFA56147E415C00F98B1E /* main.m */,
DA5BFA58147E415C00F98B1E /* OnePassword-Prefix.pch */,
+ DA007F5414B25EE100251337 /* ciphers.plist */,
);
name = "Supporting Files";
sourceTree = "";
};
+ DA7C28A214AF02A000491972 /* Models */ = {
+ isa = PBXGroup;
+ children = (
+ DA5BFA5C147E415C00F98B1E /* MainStoryboard_iPhone.storyboard */,
+ DA5BFA5F147E415C00F98B1E /* MainStoryboard_iPad.storyboard */,
+ DA5BFA62147E415C00F98B1E /* OnePassword.xcdatamodeld */,
+ );
+ name = Models;
+ sourceTree = "";
+ };
+ DA7C28A314AF02B100491972 /* Data */ = {
+ isa = PBXGroup;
+ children = (
+ DA34DA0F14B1BC7E00F721C1 /* OPElementEntity.h */,
+ DA34DA1014B1BC7E00F721C1 /* OPElementEntity.m */,
+ DA34DA0B14B1BC7D00F721C1 /* OPElementStoredEntity.h */,
+ DA34DA0C14B1BC7D00F721C1 /* OPElementStoredEntity.m */,
+ );
+ name = Data;
+ sourceTree = "";
+ };
+ DA7C28A414AF078900491972 /* divider */ = {
+ isa = PBXGroup;
+ children = (
+ DA7C28A514AF078900491972 /* Bold_Lines.png */,
+ DA7C28A614AF078900491972 /* Box.png */,
+ DA7C28A714AF078900491972 /* Dashed_Divider.png */,
+ DA7C28A814AF078900491972 /* Dashed_Divider_.png */,
+ DA7C28A914AF078900491972 /* Dashed_Divider_Highlight.png */,
+ DA7C28AA14AF078900491972 /* Dotted_Dividers.png */,
+ DA7C28AB14AF078900491972 /* Doubble_Shadow_.png */,
+ DA7C28AC14AF078900491972 /* Double.png */,
+ DA7C28AD14AF078900491972 /* Double_Page.png */,
+ DA7C28AE14AF078900491972 /* Double_Page_2.png */,
+ DA7C28AF14AF078900491972 /* Double_Shadow.png */,
+ DA7C28B014AF078900491972 /* Double_With_White.png */,
+ DA7C28B114AF078900491972 /* Double_With_White_Strong.png */,
+ DA7C28B214AF078900491972 /* Help.rtf */,
+ DA7C28B314AF078900491972 /* Highlight_Smooth_Divider.png */,
+ DA7C28B414AF078900491972 /* Highlight_Smooth_Divider_copy.png */,
+ DA7C28B514AF078900491972 /* Highlight_StrongDivider_copy_3.png */,
+ DA7C28B614AF078900491972 /* Page.png */,
+ DA7C28B714AF078900491972 /* Rectangular.png */,
+ DA7C28B814AF078900491972 /* Rounded.png */,
+ DA7C28B914AF078900491972 /* Rounded_Inverted.png */,
+ DA7C28BA14AF078900491972 /* Simple.png */,
+ DA7C28BB14AF078900491972 /* Simple_Divider.png */,
+ DA7C28BC14AF078900491972 /* Simple_Divider_.png */,
+ DA7C28BD14AF078900491972 /* Simple_Divider__Strong.png */,
+ DA7C28BE14AF078900491972 /* Simple_Divider_Strong.png */,
+ DA7C28BF14AF078900491972 /* Single_Shadow.png */,
+ DA7C28C014AF078900491972 /* Single_Shadow_.png */,
+ DA7C28C114AF078900491972 /* Smooth_Divider.png */,
+ DA7C28C214AF078900491972 /* Square.png */,
+ DA7C28C314AF078900491972 /* White_Rectangular.png */,
+ );
+ path = divider;
+ sourceTree = "";
+ };
DAC6325F1486805C0075AEA5 /* uicolor-utilities */ = {
isa = PBXGroup;
children = (
@@ -2678,6 +2828,39 @@
DA5BFA55147E415C00F98B1E /* InfoPlist.strings in Resources */,
DA5BFA5E147E415C00F98B1E /* MainStoryboard_iPhone.storyboard in Resources */,
DA5BFA61147E415C00F98B1E /* MainStoryboard_iPad.storyboard in Resources */,
+ DA7C28C414AF078900491972 /* Bold_Lines.png in Resources */,
+ DA7C28C514AF078900491972 /* Box.png in Resources */,
+ DA7C28C614AF078900491972 /* Dashed_Divider.png in Resources */,
+ DA7C28C714AF078900491972 /* Dashed_Divider_.png in Resources */,
+ DA7C28C814AF078900491972 /* Dashed_Divider_Highlight.png in Resources */,
+ DA7C28C914AF078900491972 /* Dotted_Dividers.png in Resources */,
+ DA7C28CA14AF078900491972 /* Doubble_Shadow_.png in Resources */,
+ DA7C28CB14AF078900491972 /* Double.png in Resources */,
+ DA7C28CC14AF078900491972 /* Double_Page.png in Resources */,
+ DA7C28CD14AF078900491972 /* Double_Page_2.png in Resources */,
+ DA7C28CE14AF078900491972 /* Double_Shadow.png in Resources */,
+ DA7C28CF14AF078900491972 /* Double_With_White.png in Resources */,
+ DA7C28D014AF078900491972 /* Double_With_White_Strong.png in Resources */,
+ DA7C28D114AF078900491972 /* Help.rtf in Resources */,
+ DA7C28D214AF078900491972 /* Highlight_Smooth_Divider.png in Resources */,
+ DA7C28D314AF078900491972 /* Highlight_Smooth_Divider_copy.png in Resources */,
+ DA7C28D414AF078900491972 /* Highlight_StrongDivider_copy_3.png in Resources */,
+ DA7C28D514AF078900491972 /* Page.png in Resources */,
+ DA7C28D614AF078900491972 /* Rectangular.png in Resources */,
+ DA7C28D714AF078900491972 /* Rounded.png in Resources */,
+ DA7C28D814AF078900491972 /* Rounded_Inverted.png in Resources */,
+ DA7C28D914AF078900491972 /* Simple.png in Resources */,
+ DA7C28DA14AF078900491972 /* Simple_Divider.png in Resources */,
+ DA7C28DB14AF078900491972 /* Simple_Divider_.png in Resources */,
+ DA7C28DC14AF078900491972 /* Simple_Divider__Strong.png in Resources */,
+ DA7C28DD14AF078900491972 /* Simple_Divider_Strong.png in Resources */,
+ DA7C28DE14AF078900491972 /* Single_Shadow.png in Resources */,
+ DA7C28DF14AF078900491972 /* Single_Shadow_.png in Resources */,
+ DA7C28E014AF078900491972 /* Smooth_Divider.png in Resources */,
+ DA7C28E114AF078900491972 /* Square.png in Resources */,
+ DA7C28E214AF078900491972 /* White_Rectangular.png in Resources */,
+ DA007F5514B25EE100251337 /* ciphers.plist in Resources */,
+ DA007F5614B26EFA00251337 /* Pearl.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2694,7 +2877,12 @@
DA5BFA67147E415C00F98B1E /* OPMainViewController.m in Sources */,
DAE2C648148247E500BA6B10 /* OPTypeViewController.m in Sources */,
DAC781361482E67300BCF976 /* OPRecentViewController.m in Sources */,
- DAC63257148679600075AEA5 /* OPSaltedCipherViewController.m in Sources */,
+ DA34DA0D14B1BC7D00F721C1 /* OPElementStoredEntity.m in Sources */,
+ DA34DA1114B1BC7E00F721C1 /* OPElementEntity.m in Sources */,
+ DA34DA1614B1BEA100F721C1 /* OPTypes.m in Sources */,
+ DA007F5214B24DCD00251337 /* OPConfig.m in Sources */,
+ DA55B29E14B38272001131B7 /* OPContentViewController.m in Sources */,
+ DA55B2A214B4EB47001131B7 /* OPSearchDelegate.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -2981,6 +3169,7 @@
DAC632671486805C0075AEA5 /* Release */,
);
defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
};
DAC63274148680650075AEA5 /* Build configuration list for PBXNativeTarget "jrswizzle" */ = {
isa = XCConfigurationList;
@@ -2989,6 +3178,7 @@
DAC63276148680650075AEA5 /* Release */,
);
defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
};
DAC77CB7148291A600BCF976 /* Build configuration list for PBXNativeTarget "Pearl" */ = {
isa = XCConfigurationList;
diff --git a/OnePassword/OPAppDelegate.h b/OnePassword/OPAppDelegate.h
index eb6afbd8..54819b7b 100644
--- a/OnePassword/OPAppDelegate.h
+++ b/OnePassword/OPAppDelegate.h
@@ -13,6 +13,9 @@
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
+@property (strong, nonatomic) NSString *keyPhrase;
+
++ (OPAppDelegate *)get;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
diff --git a/OnePassword/OPAppDelegate.m b/OnePassword/OPAppDelegate.m
index 1dd8fa39..8f8c9c0e 100644
--- a/OnePassword/OPAppDelegate.m
+++ b/OnePassword/OPAppDelegate.m
@@ -15,9 +15,57 @@
@synthesize managedObjectContext = __managedObjectContext;
@synthesize managedObjectModel = __managedObjectModel;
@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
+@synthesize keyPhrase = _keyPhrase;
-- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
-{
++ (void)initialize {
+
+ [Logger get].autoprintLevel = LogLevelDebug;
+}
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ NSString *keyPhraseHash = [OPConfig get].keyPhraseHash;
+
+ AlertViewController *keyPhraseAlert = [[AlertViewController alloc] initQuestionWithTitle:@"One Password"
+ message:keyPhraseHash? @"Unlock with your master password:": @"Choose your master password:"
+ tappedButtonBlock:
+ ^(NSInteger buttonIndex, NSString *answer) {
+ if (buttonIndex == 0)
+ exit(0);
+
+ if (![answer length]) {
+ [AlertViewController showAlertWithTitle:[PearlStrings get].commonTitleError
+ message:@"No master password entered."
+ tappedButtonBlock:
+ ^(NSInteger buttonIndex) {
+ exit(0);
+ } cancelTitle:@"Quit" otherTitles:nil];
+ }
+
+ NSString *answerHash = [[answer hashWith:PearlDigestSHA1] encodeHex];
+ if (keyPhraseHash) {
+ if (![keyPhraseHash isEqualToString:answerHash]) {
+ [AlertViewController showAlertWithTitle:[PearlStrings get].commonTitleError
+ message:@"Incorrect master password."
+ tappedButtonBlock:
+ ^(NSInteger buttonIndex) {
+ exit(0);
+ } cancelTitle:@"Quit" otherTitles:nil];
+
+ return;
+ }
+ } else
+ [OPConfig get].keyPhraseHash = answerHash;
+
+ self.keyPhrase = answer;
+ } cancelTitle:@"Quit" otherTitles:@"Unlock", nil];
+ keyPhraseAlert.alertField.autocapitalizationType = UITextAutocapitalizationTypeNone;
+ keyPhraseAlert.alertField.autocorrectionType = UITextAutocorrectionTypeNo;
+ keyPhraseAlert.alertField.secureTextEntry = YES;
+ [keyPhraseAlert showAlert];
+ });
+
// Override point for customization after application launch.
return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@@ -58,6 +106,11 @@
[self saveContext];
}
++ (OPAppDelegate *)get {
+
+ return (OPAppDelegate *)[super get];
+}
+
- (void)saveContext
{
NSError *error = nil;
@@ -106,6 +159,7 @@
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"OnePassword" withExtension:@"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
+
return __managedObjectModel;
}
@@ -124,7 +178,12 @@
NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
- if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
+ if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL
+ options:[NSDictionary dictionaryWithObjectsAndKeys:
+ (id)kCFBooleanTrue, NSMigratePersistentStoresAutomaticallyOption,
+ (id)kCFBooleanTrue, NSInferMappingModelAutomaticallyOption,
+ nil]
+ error:&error])
{
/*
Replace this implementation with code to handle the error appropriately.
@@ -149,9 +208,14 @@
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
- NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
- abort();
- }
+ err(@"Unresolved error %@, %@", error, [error userInfo]);
+#if DEBUG
+ wrn(@"Deleted datastore: %@", storeURL);
+ [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
+#endif
+ @throw [NSException exceptionWithName:error.domain reason:error.localizedDescription
+ userInfo:[NSDictionary dictionaryWithObject:error forKey:@"cause"]];
+ }
return __persistentStoreCoordinator;
}
diff --git a/OnePassword/OPConfig.h b/OnePassword/OPConfig.h
new file mode 100644
index 00000000..fb6c88a7
--- /dev/null
+++ b/OnePassword/OPConfig.h
@@ -0,0 +1,16 @@
+//
+// OPConfig.h
+// OnePassword
+//
+// Created by Maarten Billemont on 02/01/12.
+// Copyright (c) 2012 Lyndir. All rights reserved.
+//
+
+@interface OPConfig : Config
+
+@property (nonatomic, retain) NSNumber *dataStoreError;
+@property (nonatomic, retain) NSString *keyPhraseHash;
+
++ (OPConfig *)get;
+
+@end
diff --git a/OnePassword/OPConfig.m b/OnePassword/OPConfig.m
new file mode 100644
index 00000000..7d2f9c7c
--- /dev/null
+++ b/OnePassword/OPConfig.m
@@ -0,0 +1,34 @@
+//
+// OPConfig.m
+// OnePassword
+//
+// Created by Maarten Billemont on 02/01/12.
+// Copyright (c) 2012 Lyndir. All rights reserved.
+//
+
+#import "OPConfig.h"
+
+@implementation OPConfig
+
+@dynamic dataStoreError, keyPhraseHash;
+
+
+-(id) init {
+
+ if(!(self = [super init]))
+ return self;
+
+ [self.defaults registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithBool:NO], NSStringFromSelector(@selector(dataStoreError)),
+
+ nil]];
+
+ return self;
+}
+
++ (OPConfig *)get {
+
+ return (OPConfig *)[super get];
+}
+
+@end
diff --git a/OnePassword/OPContentViewController.h b/OnePassword/OPContentViewController.h
new file mode 100644
index 00000000..2bb67307
--- /dev/null
+++ b/OnePassword/OPContentViewController.h
@@ -0,0 +1,16 @@
+//
+// OPContentViewController.h
+// OnePassword
+//
+// Created by Maarten Billemont on 03/01/12.
+// Copyright (c) 2012 Lyndir. All rights reserved.
+//
+
+#import
+#import "OPElementEntity.h"
+
+@interface OPContentViewController : UIViewController
+
+@property (nonatomic, weak) OPElementEntity *activeElement;
+
+@end
diff --git a/OnePassword/OPContentViewController.m b/OnePassword/OPContentViewController.m
new file mode 100644
index 00000000..7343b1ef
--- /dev/null
+++ b/OnePassword/OPContentViewController.m
@@ -0,0 +1,22 @@
+//
+// OPContentViewController.m
+// OnePassword
+//
+// Created by Maarten Billemont on 03/01/12.
+// Copyright (c) 2012 Lyndir. All rights reserved.
+//
+
+#import "OPContentViewController.h"
+
+@implementation OPContentViewController
+@synthesize activeElement = _activeElement;
+
+#pragma mark - View lifecycle
+
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
+
+ // Return YES for supported orientations
+ return (interfaceOrientation == UIInterfaceOrientationPortrait);
+}
+
+@end
diff --git a/OnePassword/OPElementEntity.h b/OnePassword/OPElementEntity.h
new file mode 100644
index 00000000..ff477240
--- /dev/null
+++ b/OnePassword/OPElementEntity.h
@@ -0,0 +1,26 @@
+//
+// OPElementEntity.h
+// OnePassword
+//
+// Created by Maarten Billemont on 02/01/12.
+// Copyright (c) 2012 Lyndir. All rights reserved.
+//
+
+#import
+#import
+
+
+@interface OPElementEntity : NSManagedObject
+
+@property (nonatomic, retain) NSString *name;
+@property (nonatomic) int16_t type;
+@property (nonatomic) int16_t uses;
+@property (nonatomic) NSTimeInterval lastUsed;
+@property (nonatomic, retain) NSString *contentUTI;
+@property (nonatomic) int16_t contentType;
+
+- (void)use;
+- (id)content;
+- (NSString *)contentDescription;
+
+@end
diff --git a/OnePassword/OPElementEntity.m b/OnePassword/OPElementEntity.m
new file mode 100644
index 00000000..52355361
--- /dev/null
+++ b/OnePassword/OPElementEntity.m
@@ -0,0 +1,45 @@
+//
+// OPElementEntity.m
+// OnePassword
+//
+// Created by Maarten Billemont on 02/01/12.
+// Copyright (c) 2012 Lyndir. All rights reserved.
+//
+
+#import "OPElementEntity.h"
+#import "OPAppDelegate.h"
+
+
+@implementation OPElementEntity
+
+@dynamic name;
+@dynamic type;
+@dynamic uses;
+@dynamic lastUsed;
+@dynamic contentUTI;
+@dynamic contentType;
+
+- (void)use {
+
+ ++self.uses;
+ self.lastUsed = [[NSDate date] timeIntervalSinceReferenceDate];
+}
+
+- (id)content {
+
+ if (![self.name length])
+ return nil;
+
+ if (self.type & OPElementTypeCalculated)
+ return OPCalculateContent(self.type, self.name, [OPAppDelegate get].keyPhrase);
+
+ @throw [NSException exceptionWithName:NSInternalInconsistencyException
+ reason:[NSString stringWithFormat:@"Unsupported type: %d", self.type] userInfo:nil];
+}
+
+- (NSString *)contentDescription {
+
+ return [[self content] description];
+}
+
+@end
diff --git a/OnePassword/OPElementStoredEntity.h b/OnePassword/OPElementStoredEntity.h
new file mode 100644
index 00000000..4b5f8bf2
--- /dev/null
+++ b/OnePassword/OPElementStoredEntity.h
@@ -0,0 +1,18 @@
+//
+// OPElementStoredEntity.h
+// OnePassword
+//
+// Created by Maarten Billemont on 02/01/12.
+// Copyright (c) 2012 Lyndir. All rights reserved.
+//
+
+#import
+#import
+#import "OPElementEntity.h"
+
+
+@interface OPElementStoredEntity : OPElementEntity
+
+@property (nonatomic, retain) id contentObject;
+
+@end
diff --git a/OnePassword/OPElementStoredEntity.m b/OnePassword/OPElementStoredEntity.m
new file mode 100644
index 00000000..c2b357b5
--- /dev/null
+++ b/OnePassword/OPElementStoredEntity.m
@@ -0,0 +1,23 @@
+//
+// OPElementStoredEntity.m
+// OnePassword
+//
+// Created by Maarten Billemont on 02/01/12.
+// Copyright (c) 2012 Lyndir. All rights reserved.
+//
+
+#import "OPElementStoredEntity.h"
+
+
+@implementation OPElementStoredEntity
+
+@dynamic contentObject;
+
+- (id)content {
+
+ assert(self.type & OPElementTypeStored);
+
+ return self.contentObject;
+}
+
+@end
diff --git a/OnePassword/OPMainViewController.h b/OnePassword/OPMainViewController.h
index e10216c8..eec06956 100644
--- a/OnePassword/OPMainViewController.h
+++ b/OnePassword/OPMainViewController.h
@@ -6,8 +6,19 @@
// Copyright (c) 2011 Lyndir. All rights reserved.
//
-@interface OPMainViewController : UITableViewController
+#import "OPTypeViewController.h"
+#import "OPElementEntity.h"
+#import "OPSearchDelegate.h"
-@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
+@interface OPMainViewController : UITableViewController
+
+@property (strong, nonatomic) OPElementEntity *activeElement;
+@property (strong, nonatomic) IBOutlet OPSearchDelegate *searchResultsController;
+@property (weak, nonatomic) IBOutlet UITextField *contentField;
+@property (weak, nonatomic) IBOutlet UITextView *contentTextView;
+@property (weak, nonatomic) IBOutlet UILabel *typeLabel;
+@property (weak, nonatomic) IBOutlet UISegmentedControl *contentType;
+
+- (IBAction)didChangeContentType:(UISegmentedControl *)sender;
@end
diff --git a/OnePassword/OPMainViewController.m b/OnePassword/OPMainViewController.m
index e1390464..42464420 100644
--- a/OnePassword/OPMainViewController.m
+++ b/OnePassword/OPMainViewController.m
@@ -7,67 +7,140 @@
//
#import "OPMainViewController.h"
+#import "OPAppDelegate.h"
+#import "OPContentViewController.h"
+
+#import
+
+
+@interface OPMainViewController (Private)
+
+- (void)updateAnimated:(BOOL)animated;
+- (void)updateWasAnimated:(BOOL)animated;
+
+@end
@implementation OPMainViewController
-
-@synthesize managedObjectContext = _managedObjectContext;
-
-- (void)didReceiveMemoryWarning
-{
- [super didReceiveMemoryWarning];
- // Release any cached data, images, etc that aren't in use.
-}
+@synthesize activeElement = _activeElement;
+@synthesize searchResultsController = _searchResultsController;
+@synthesize typeLabel = _typeLabel;
+@synthesize contentType = _contentType;
+@synthesize contentField = _contentField;
+@synthesize contentTextView = _contentTextView;
#pragma mark - View lifecycle
-- (void)viewDidLoad
-{
- [super viewDidLoad];
- // Do any additional setup after loading the view, typically from a nib.
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
+
+ return [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad || interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown;
}
-- (void)viewDidUnload
-{
- [super viewDidUnload];
- // Release any retained subviews of the main view.
- // e.g. self.myOutlet = nil;
-}
-
-- (void)viewWillAppear:(BOOL)animated
-{
- [super viewWillAppear:animated];
-}
-
-- (void)viewDidAppear:(BOOL)animated
-{
- [super viewDidAppear:animated];
-}
-
-- (void)viewWillDisappear:(BOOL)animated
-{
- [super viewWillDisappear:animated];
-}
-
-- (void)viewDidDisappear:(BOOL)animated
-{
- [super viewDidDisappear:animated];
-}
-
-- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
-{
- // Return YES for supported orientations
- if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
- return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
- } else {
- return YES;
- }
-}
-
-- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
-{
- if ([[segue identifier] isEqualToString:@"showAlternate"]) {
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+
+ if ([[segue identifier] isEqualToString:@"OP_Main_ChooseType"])
[[segue destinationViewController] setDelegate:self];
- }
+ if ([[segue identifier] isEqualToString:@"OP_Main_Content"])
+ ((OPContentViewController *)[segue destinationViewController]).activeElement = self.activeElement;
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+
+ [super viewWillAppear:animated];
+
+ [self updateAnimated:NO];
+ [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:animated];
+}
+
+- (void)viewDidLoad {
+
+ // Because IB's edit button doesn't auto-toggle self.editable like editButtonItem does.
+ self.navigationItem.rightBarButtonItem = self.editButtonItem;
+
+ [super viewDidLoad];
+}
+
+- (void)viewDidUnload {
+
+ [self setContentField:nil];
+ [self setTypeLabel:nil];
+
+ [self setContentType:nil];
+ [self setContentTextView:nil];
+ [self setSearchResultsController:nil];
+ [super viewDidUnload];
+}
+
+- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
+
+ [super setEditing:editing animated:animated];
+
+ [self updateAnimated:animated];
+}
+
+- (void)updateAnimated:(BOOL)animated {
+
+ [[OPAppDelegate get] saveContext];
+
+ if (animated)
+ [UIView animateWithDuration:0.2 animations:^{
+ [self updateWasAnimated:YES];
+ }];
+ else
+ [self updateWasAnimated:NO];
+}
+
+- (void)updateWasAnimated:(BOOL)animated {
+
+ self.typeLabel.text = self.activeElement? NSStringFromOPElementType(self.activeElement.type): @"moo";
+
+ self.contentTextView.alpha = self.contentType.selectedSegmentIndex == OPElementContentTypeNote? 1: 0;
+ self.contentTextView.editable = self.editing && self.activeElement.type & OPElementTypeStored;
+
+ self.contentType.alpha = self.editing && self.activeElement.type & OPElementTypeStored? 1: 0;
+ self.contentType.selectedSegmentIndex = self.activeElement.contentType;
+
+ self.contentField.alpha = self.contentType.selectedSegmentIndex == OPElementContentTypePassword? 1: 0;
+ self.contentField.enabled = self.editing && self.activeElement.type & OPElementTypeStored;
+ self.contentField.clearButtonMode = self.contentField.enabled? UITextFieldViewModeAlways: UITextFieldViewModeNever;
+ self.contentField.text = @"...";
+
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
+ NSString *contentDescription = self.activeElement.contentDescription;
+ if (contentDescription)
+ [self.activeElement use];
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ self.contentField.text = contentDescription;
+ });
+ });
+}
+
+#pragma mark - Protocols
+
+- (IBAction)didChangeContentType:(UISegmentedControl *)sender {
+
+ self.activeElement.contentType = self.contentType.selectedSegmentIndex;
+ [self updateAnimated:YES];
+}
+
+- (void)didSelectType:(OPElementType)type {
+
+ self.activeElement.type = type;
+ [self updateAnimated:YES];
+}
+
+- (void)didSelectElement:(OPElementEntity *)element {
+
+ self.activeElement = element;
+ [self updateAnimated:YES];
+
+ [self.searchDisplayController setActive:NO animated:YES];
+ self.searchDisplayController.searchBar.text = self.activeElement.name;
+}
+
+- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
+
+ [self updateAnimated:YES];
}
@end
diff --git a/OnePassword/OPRecentViewController.m b/OnePassword/OPRecentViewController.m
index 4f2cb78d..ae6b7ca2 100644
--- a/OnePassword/OPRecentViewController.m
+++ b/OnePassword/OPRecentViewController.m
@@ -11,51 +11,10 @@
@implementation OPRecentViewController
@dynamic tableView;
-- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
-{
- self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
- if (self) {
- // Custom initialization
- }
- return self;
-}
-
-- (void)didReceiveMemoryWarning
-{
- // Releases the view if it doesn't have a superview.
- [super didReceiveMemoryWarning];
-
- // Release any cached data, images, etc that aren't in use.
-}
-
-#pragma mark - View lifecycle
-
-/*
- // Implement loadView to create a view hierarchy programmatically, without using a nib.
- - (void)loadView
- {
- }
- */
-
-/*
- // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- }
- */
-
-- (void)viewDidUnload
-{
- [super viewDidUnload];
- // Release any retained subviews of the main view.
- // e.g. self.myOutlet = nil;
-}
-
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
- return (interfaceOrientation == UIInterfaceOrientationPortrait);
+ return YES;
}
@end
diff --git a/OnePassword/OPSaltedCipherViewController.h b/OnePassword/OPSaltedCipherViewController.h
deleted file mode 100644
index 83bef9e2..00000000
--- a/OnePassword/OPSaltedCipherViewController.h
+++ /dev/null
@@ -1,15 +0,0 @@
-//
-// OPSaltedCipherViewController.h
-// OnePassword
-//
-// Created by Maarten Billemont on 30/11/11.
-// Copyright (c) 2011 Lyndir. All rights reserved.
-//
-
-#import
-
-@interface OPSaltedCipherViewController : UITableViewController
-
-@property(nonatomic,retain) IBOutlet UITableView *tableView;
-
-@end
diff --git a/OnePassword/OPSaltedCipherViewController.m b/OnePassword/OPSaltedCipherViewController.m
deleted file mode 100644
index ee4d149c..00000000
--- a/OnePassword/OPSaltedCipherViewController.m
+++ /dev/null
@@ -1,61 +0,0 @@
-//
-// OPSaltedCipherViewController.m
-// OnePassword
-//
-// Created by Maarten Billemont on 30/11/11.
-// Copyright (c) 2011 Lyndir. All rights reserved.
-//
-
-#import "OPSaltedCipherViewController.h"
-
-@implementation OPSaltedCipherViewController
-@dynamic tableView;
-
-- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
-{
- self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
- if (self) {
- // Custom initialization
- }
- return self;
-}
-
-- (void)didReceiveMemoryWarning
-{
- // Releases the view if it doesn't have a superview.
- [super didReceiveMemoryWarning];
-
- // Release any cached data, images, etc that aren't in use.
-}
-
-#pragma mark - View lifecycle
-
-/*
-// Implement loadView to create a view hierarchy programmatically, without using a nib.
-- (void)loadView
-{
-}
-*/
-
-/*
-// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
-- (void)viewDidLoad
-{
- [super viewDidLoad];
-}
-*/
-
-- (void)viewDidUnload
-{
- [super viewDidUnload];
- // Release any retained subviews of the main view.
- // e.g. self.myOutlet = nil;
-}
-
-- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
-{
- // Return YES for supported orientations
- return (interfaceOrientation == UIInterfaceOrientationPortrait);
-}
-
-@end
diff --git a/OnePassword/OPSearchDelegate.h b/OnePassword/OPSearchDelegate.h
new file mode 100644
index 00000000..7e0c90aa
--- /dev/null
+++ b/OnePassword/OPSearchDelegate.h
@@ -0,0 +1,27 @@
+//
+// OPSearchDelegate.h
+// OnePassword
+//
+// Created by Maarten Billemont on 04/01/12.
+// Copyright (c) 2012 Lyndir. All rights reserved.
+//
+
+#import
+#import "OPElementEntity.h"
+
+@protocol OPSearchResultsDelegate
+
+- (void)didSelectElement:(OPElementEntity *)element;
+
+@end
+
+@interface OPSearchDelegate : NSObject
+
+@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
+
+@property (weak, nonatomic) IBOutlet id delegate;
+@property (weak, nonatomic) IBOutlet UISearchDisplayController *searchDisplayController;
+
+- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;
+
+@end
diff --git a/OnePassword/OPSearchDelegate.m b/OnePassword/OPSearchDelegate.m
new file mode 100644
index 00000000..45374f55
--- /dev/null
+++ b/OnePassword/OPSearchDelegate.m
@@ -0,0 +1,204 @@
+//
+// OPSearchDelegate.m
+// OnePassword
+//
+// Created by Maarten Billemont on 04/01/12.
+// Copyright (c) 2012 Lyndir. All rights reserved.
+//
+
+#import "OPSearchDelegate.h"
+#import "OPAppDelegate.h"
+
+@interface OPSearchDelegate (Private)
+
+- (NSManagedObjectContext *)managedObjectContext;
+- (void)update;
+
+@end
+
+@implementation OPSearchDelegate
+@synthesize fetchedResultsController;
+@synthesize delegate;
+@synthesize searchDisplayController;
+
+- (NSManagedObjectContext *)managedObjectContext {
+
+ return [(OPAppDelegate *)[UIApplication sharedApplication].delegate managedObjectContext];
+}
+
+- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
+
+ [self.searchDisplayController.searchResultsTableView setEditing:self.searchDisplayController.searchContentsController.editing animated:NO];
+ [self update];
+}
+
+- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
+
+ [self update];
+
+ return YES;
+}
+
+- (void)update {
+
+ NSString *text = self.searchDisplayController.searchBar.text;
+ if (!text)
+ text = @"";
+
+ NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([OPElementEntity class])];
+ [fetchRequest setSortDescriptors:
+ [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses" ascending:NO]]];
+ [fetchRequest setPredicate:
+ [NSPredicate predicateWithFormat:@"name BEGINSWITH[cd] %@", text]];
+
+ self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
+ managedObjectContext:[self managedObjectContext]
+ sectionNameKeyPath:nil cacheName:nil];
+ self.fetchedResultsController.delegate = self;
+
+ NSError *error;
+ if (![self.fetchedResultsController performFetch:&error])
+ err(@"Couldn't fetch elements: %@", error);
+}
+
+- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
+
+ [self.searchDisplayController.searchResultsTableView beginUpdates];
+}
+
+- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
+
+ indexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section + 1];
+ newIndexPath = [NSIndexPath indexPathForRow:newIndexPath.row inSection:newIndexPath.section + 1];
+
+ switch(type) {
+
+ case NSFetchedResultsChangeInsert:
+ [self.searchDisplayController.searchResultsTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
+ break;
+
+ case NSFetchedResultsChangeDelete:
+ [self.searchDisplayController.searchResultsTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
+ break;
+
+ case NSFetchedResultsChangeUpdate:
+ [self configureCell:[self.searchDisplayController.searchResultsTableView cellForRowAtIndexPath:indexPath]
+ atIndexPath:indexPath];
+ break;
+
+ case NSFetchedResultsChangeMove:
+ [self.searchDisplayController.searchResultsTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
+ withRowAnimation:UITableViewRowAnimationFade];
+ [self.searchDisplayController.searchResultsTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
+ withRowAnimation:UITableViewRowAnimationFade];
+ break;
+ }
+}
+
+
+- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id )sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
+
+ ++sectionIndex;
+
+ switch(type) {
+
+ case NSFetchedResultsChangeInsert:
+ [self.searchDisplayController.searchResultsTableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
+ withRowAnimation:UITableViewRowAnimationFade];
+ break;
+
+ case NSFetchedResultsChangeDelete:
+ [self.searchDisplayController.searchResultsTableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
+ withRowAnimation:UITableViewRowAnimationFade];
+ break;
+ }
+}
+
+- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
+
+ [self.searchDisplayController.searchResultsTableView endUpdates];
+}
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
+
+ return [[self.fetchedResultsController sections] count] + 1;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+
+ if (--section == -1)
+ return 1;
+
+ return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+
+ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"OPElementSearch"];
+ if (!cell)
+ cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"OPElementSearch"];
+
+ [self configureCell:cell atIndexPath:indexPath];
+
+ return cell;
+}
+
+- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
+
+ indexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section - 1];
+ if (indexPath.section == -1) {
+ cell.textLabel.text = self.searchDisplayController.searchBar.text;
+ cell.detailTextLabel.text = @"New";
+ } else {
+ OPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
+
+ cell.textLabel.text = element.name;
+ cell.detailTextLabel.text = [NSString stringWithFormat:@"%d", element.uses];
+ }
+}
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+
+ OPElementEntity *element;
+ indexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section - 1];
+ if (indexPath.section == -1) {
+ element = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([OPElementEntity class])
+ inManagedObjectContext:[self managedObjectContext]];
+ element.name = self.searchDisplayController.searchBar.text;
+ } else
+ element = [self.fetchedResultsController objectAtIndexPath:indexPath];
+
+ [self.delegate didSelectElement:element];
+}
+
+- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
+
+ if (--section == -1)
+ return @"";
+
+ return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
+}
+
+- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
+
+ return [self.fetchedResultsController sectionIndexTitles];
+}
+
+- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
+
+ return [self.fetchedResultsController sectionForSectionIndexTitle:title atIndex:index];
+}
+
+- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
+
+ indexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section - 1];
+
+ if (editingStyle == UITableViewCellEditingStyleDelete) {
+ OPElementEntity *element = [self.fetchedResultsController objectAtIndexPath:indexPath];
+
+ [[self managedObjectContext] deleteObject:element];
+ }
+}
+
+
+@end
diff --git a/OnePassword/OPTypeViewController.h b/OnePassword/OPTypeViewController.h
index ec7e7a8f..b2f874ae 100644
--- a/OnePassword/OPTypeViewController.h
+++ b/OnePassword/OPTypeViewController.h
@@ -8,6 +8,14 @@
#import
-@interface OPTypeViewController : UITableViewController
+@protocol OPTypeDelegate
+
+- (void)didSelectType:(OPElementType)type;
+
+@end
+
+@interface OPTypeViewController : UITableViewController
+
+@property (nonatomic, weak) id delegate;
@end
diff --git a/OnePassword/OPTypeViewController.m b/OnePassword/OPTypeViewController.m
index 2ec9d7ef..64a0efc2 100644
--- a/OnePassword/OPTypeViewController.m
+++ b/OnePassword/OPTypeViewController.m
@@ -9,43 +9,71 @@
#import "OPTypeViewController.h"
@implementation OPTypeViewController
-
-- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
-{
- self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
- if (self) {
- // Custom initialization
- }
- return self;
-}
-
-- (void)didReceiveMemoryWarning
-{
- // Releases the view if it doesn't have a superview.
- [super didReceiveMemoryWarning];
-
- // Release any cached data, images, etc that aren't in use.
-}
+@synthesize delegate;
#pragma mark - View lifecycle
-- (void)viewDidLoad
-{
- [super viewDidLoad];
- // Do any additional setup after loading the view from its nib.
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
+
+ return YES;
}
-- (void)viewDidUnload
-{
- [super viewDidUnload];
- // Release any retained subviews of the main view.
- // e.g. self.myOutlet = nil;
-}
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+
+ assert(self.navigationController.topViewController == self);
-- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
-{
- // Return YES for supported orientations
- return (interfaceOrientation == UIInterfaceOrientationPortrait);
+ OPElementType type;
+ switch (indexPath.section) {
+ case 0: {
+ // Calculated
+ switch (indexPath.row) {
+ case 0:
+ type = OPElementTypeCalculatedLong;
+ break;
+ case 1:
+ type = OPElementTypeCalculatedMedium;
+ break;
+ case 2:
+ type = OPElementTypeCalculatedShort;
+ break;
+ case 3:
+ type = OPElementTypeCalculatedBasic;
+ break;
+ case 4:
+ type = OPElementTypeCalculatedPIN;
+ break;
+
+ default:
+ [NSException raise:NSInternalInconsistencyException
+ format:@"Unsupported row: %d, when selecting calculated element type.", indexPath.row];
+ }
+ break;
+ }
+
+ case 1: {
+ // Stored
+ switch (indexPath.row) {
+ case 0:
+ type = OPElementTypeStoredPersonal;
+ break;
+ case 1:
+ type = OPElementTypeStoredDevicePrivate;
+ break;
+
+ default:
+ [NSException raise:NSInternalInconsistencyException
+ format:@"Unsupported row: %d, when selecting stored element type.", indexPath.row];
+ }
+ break;
+ }
+
+ default:
+ [NSException raise:NSInternalInconsistencyException
+ format:@"Unsupported section: %d, when selecting element type.", indexPath.section];
+ }
+
+ [delegate didSelectType:type];
+ [self.navigationController popViewControllerAnimated:YES];
}
@end
diff --git a/OnePassword/OPTypes.h b/OnePassword/OPTypes.h
new file mode 100644
index 00000000..fba3949e
--- /dev/null
+++ b/OnePassword/OPTypes.h
@@ -0,0 +1,34 @@
+//
+// OPTypes.h
+// OnePassword
+//
+// Created by Maarten Billemont on 02/01/12.
+// Copyright (c) 2012 Lyndir. All rights reserved.
+//
+
+#import
+
+typedef enum {
+ OPElementContentTypePassword,
+ OPElementContentTypeNote,
+ OPElementContentTypePicture,
+} OPElementContentType;
+
+typedef enum {
+ OPElementTypeCalculated = 2 << 7,
+ OPElementTypeStored = 2 << 8,
+} OPElementTypeClass;
+
+typedef enum {
+ OPElementTypeCalculatedLong = OPElementTypeCalculated | 0x01,
+ OPElementTypeCalculatedMedium = OPElementTypeCalculated | 0x02,
+ OPElementTypeCalculatedShort = OPElementTypeCalculated | 0x03,
+ OPElementTypeCalculatedBasic = OPElementTypeCalculated | 0x04,
+ OPElementTypeCalculatedPIN = OPElementTypeCalculated | 0x05,
+
+ OPElementTypeStoredPersonal = OPElementTypeStored | 0x01,
+ OPElementTypeStoredDevicePrivate = OPElementTypeStored | 0x02,
+} OPElementType;
+
+NSString *NSStringFromOPElementType(OPElementType type);
+NSString *OPCalculateContent(OPElementType type, NSString *name, NSString *keyPhrase);
\ No newline at end of file
diff --git a/OnePassword/OPTypes.m b/OnePassword/OPTypes.m
new file mode 100644
index 00000000..d55ac89e
--- /dev/null
+++ b/OnePassword/OPTypes.m
@@ -0,0 +1,72 @@
+//
+// OPTypes.m
+// OnePassword
+//
+// Created by Maarten Billemont on 02/01/12.
+// Copyright (c) 2012 Lyndir. All rights reserved.
+//
+
+#import "OPTypes.h"
+
+
+NSString *NSStringFromOPElementType(OPElementType type) {
+
+ switch (type) {
+ case OPElementTypeCalculatedLong:
+ return @"Long";
+
+ case OPElementTypeCalculatedMedium:
+ return @"Medium";
+
+ case OPElementTypeCalculatedShort:
+ return @"Short";
+
+ case OPElementTypeCalculatedBasic:
+ return @"Basic";
+
+ case OPElementTypeCalculatedPIN:
+ return @"PIN";
+
+ case OPElementTypeStoredPersonal:
+ return @"Personal";
+
+ case OPElementTypeStoredDevicePrivate:
+ return @"Device Private";
+
+ default:
+ [NSException raise:NSInternalInconsistencyException format:@"Type not supported: %d", type];
+ }
+}
+
+static NSDictionary *OPTypes_ciphers = nil;
+NSString *OPCalculateContent(OPElementType type, NSString *name, NSString *keyPhrase) {
+
+ assert(type & OPElementTypeCalculated);
+
+ if (OPTypes_ciphers == nil)
+ OPTypes_ciphers = [NSDictionary dictionaryWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"ciphers"
+ withExtension:@"plist"]];
+
+ // Determine the hash whose bytes will be used for calculating a password: md4(name-keyPhrase)
+ assert(name && keyPhrase);
+ NSData *keyHash = [[NSString stringWithFormat:@"%@-%@", name, keyPhrase] hashWith:PearlDigestMD4];
+ const char *keyBytes = keyHash.bytes;
+
+ // Determine the cipher from the first hash byte.
+ assert([keyHash length]);
+ NSArray *typeCiphers = [[OPTypes_ciphers valueForKey:@"OPElementTypeCalculated"] valueForKey:NSStringFromOPElementType(type)];
+ NSString *cipher = [typeCiphers objectAtIndex:keyBytes[0] % [typeCiphers count]];
+
+ // Encode the content, character by character, using subsequent hash bytes and the cipher.
+ assert([keyHash length] >= [cipher length] + 1);
+ NSMutableString *content = [NSMutableString stringWithCapacity:[cipher length]];
+ for (NSUInteger c = 0; c < [cipher length]; ++c) {
+ const char keyByte = keyBytes[c + 1];
+ NSString *cipherClass = [cipher substringWithRange:NSMakeRange(c, 1)];
+ NSString *cipherClassCharacters = [[OPTypes_ciphers valueForKey:@"OPCharacterClasses"] valueForKey:cipherClass];
+
+ [content appendString:[cipherClassCharacters substringWithRange:NSMakeRange(keyByte % [cipherClassCharacters length], 1)]];
+ }
+
+ return content;
+}
\ No newline at end of file
diff --git a/OnePassword/OnePassword-Info.plist b/OnePassword/OnePassword-Info.plist
index 99be8854..4271177b 100644
--- a/OnePassword/OnePassword-Info.plist
+++ b/OnePassword/OnePassword-Info.plist
@@ -26,6 +26,8 @@
1.0
LSRequiresIPhoneOS
+ UIApplicationExitsOnSuspend
+
UIMainStoryboardFile
MainStoryboard_iPhone
UIMainStoryboardFile~ipad
diff --git a/OnePassword/OnePassword-Prefix.pch b/OnePassword/OnePassword-Prefix.pch
index 5cefa42b..e04af3cc 100644
--- a/OnePassword/OnePassword-Prefix.pch
+++ b/OnePassword/OnePassword-Prefix.pch
@@ -14,4 +14,13 @@
#import
#endif
-#import "Pearl-Prefix.pch"
\ No newline at end of file
+#define PEARL
+#define PEARL_CRYPTO
+#define PEARL_UIKIT
+
+#import "Pearl.h"
+#import "Pearl-Crypto.h"
+#import "Pearl-UIKit.h"
+
+#import "OPTypes.h"
+#import "OPConfig.h"
diff --git a/OnePassword/OnePassword.xcdatamodeld/OnePassword.xcdatamodel/contents b/OnePassword/OnePassword.xcdatamodeld/OnePassword.xcdatamodel/contents
index 193f33c9..ef43b69d 100644
--- a/OnePassword/OnePassword.xcdatamodeld/OnePassword.xcdatamodel/contents
+++ b/OnePassword/OnePassword.xcdatamodeld/OnePassword.xcdatamodel/contents
@@ -1,4 +1,19 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OnePassword/ciphers.plist b/OnePassword/ciphers.plist
new file mode 100644
index 00000000..e44d2506
--- /dev/null
+++ b/OnePassword/ciphers.plist
@@ -0,0 +1,55 @@
+
+
+
+
+ OPElementTypeCalculated
+
+ Long
+
+ CvcvCvcvnoCvcv
+ CvcvnoCvcvCvcv
+ CvcvCvcvCvcvno
+
+ Medium
+
+ CvcnoCvc
+ CvcCvcno
+
+ Short
+
+ Cvcn
+
+ Basic
+
+ aaanaaan
+ aannaaan
+ aaannaaa
+
+ PIN
+
+ nnnn
+
+
+ OPCharacterClasses
+
+ V
+ AEIOU
+ C
+ BCDFGHJKLMNPQRSTVWXYZ
+ v
+ aeiou
+ c
+ bcdfghjklmnpqrstvwxyz
+ A
+ AEIOUBCDFGHJKLMNPQRSTVWXYZ
+ a
+ AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz
+ n
+ 0123456789
+ o
+ !@#$%^&*()
+ X
+ AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()
+
+
+
diff --git a/OnePassword/divider/Bold_Lines.png b/OnePassword/divider/Bold_Lines.png
new file mode 100644
index 00000000..654ac5e8
Binary files /dev/null and b/OnePassword/divider/Bold_Lines.png differ
diff --git a/OnePassword/divider/Box.png b/OnePassword/divider/Box.png
new file mode 100644
index 00000000..a9fc92e1
Binary files /dev/null and b/OnePassword/divider/Box.png differ
diff --git a/OnePassword/divider/Dashed_Divider.png b/OnePassword/divider/Dashed_Divider.png
new file mode 100644
index 00000000..324757f8
Binary files /dev/null and b/OnePassword/divider/Dashed_Divider.png differ
diff --git a/OnePassword/divider/Dashed_Divider_.png b/OnePassword/divider/Dashed_Divider_.png
new file mode 100644
index 00000000..9a9d7113
Binary files /dev/null and b/OnePassword/divider/Dashed_Divider_.png differ
diff --git a/OnePassword/divider/Dashed_Divider_Highlight.png b/OnePassword/divider/Dashed_Divider_Highlight.png
new file mode 100644
index 00000000..da3d4d1d
Binary files /dev/null and b/OnePassword/divider/Dashed_Divider_Highlight.png differ
diff --git a/OnePassword/divider/Dotted_Dividers.png b/OnePassword/divider/Dotted_Dividers.png
new file mode 100644
index 00000000..8de5314d
Binary files /dev/null and b/OnePassword/divider/Dotted_Dividers.png differ
diff --git a/OnePassword/divider/Doubble_Shadow_.png b/OnePassword/divider/Doubble_Shadow_.png
new file mode 100644
index 00000000..78c264c6
Binary files /dev/null and b/OnePassword/divider/Doubble_Shadow_.png differ
diff --git a/OnePassword/divider/Double.png b/OnePassword/divider/Double.png
new file mode 100644
index 00000000..34517a06
Binary files /dev/null and b/OnePassword/divider/Double.png differ
diff --git a/OnePassword/divider/Double_Page.png b/OnePassword/divider/Double_Page.png
new file mode 100644
index 00000000..78bcef71
Binary files /dev/null and b/OnePassword/divider/Double_Page.png differ
diff --git a/OnePassword/divider/Double_Page_2.png b/OnePassword/divider/Double_Page_2.png
new file mode 100644
index 00000000..19a2f9bc
Binary files /dev/null and b/OnePassword/divider/Double_Page_2.png differ
diff --git a/OnePassword/divider/Double_Shadow.png b/OnePassword/divider/Double_Shadow.png
new file mode 100644
index 00000000..559c254c
Binary files /dev/null and b/OnePassword/divider/Double_Shadow.png differ
diff --git a/OnePassword/divider/Double_With_White.png b/OnePassword/divider/Double_With_White.png
new file mode 100644
index 00000000..fc1a1144
Binary files /dev/null and b/OnePassword/divider/Double_With_White.png differ
diff --git a/OnePassword/divider/Double_With_White_Strong.png b/OnePassword/divider/Double_With_White_Strong.png
new file mode 100644
index 00000000..ac1b3ec4
Binary files /dev/null and b/OnePassword/divider/Double_With_White_Strong.png differ
diff --git a/OnePassword/divider/Help.rtf b/OnePassword/divider/Help.rtf
new file mode 100644
index 00000000..5da8ad68
--- /dev/null
+++ b/OnePassword/divider/Help.rtf
@@ -0,0 +1,11 @@
+{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf350
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\margl1440\margr1440\vieww9000\viewh8400\viewkind0
+\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural
+
+\f0\fs24 \cf0 Hello,\
+Thank you for purchasing my item. \
+To use the dividers, just drag and drop the folder containing the divider you want to use. If you want to expand the divider you can resize it. \
+If you want to change the color of a divider you can use the color overlay filter. \
+Thanks again, if you need help please contact me via GraphicRiver. }
\ No newline at end of file
diff --git a/OnePassword/divider/Highlight_Smooth_Divider.png b/OnePassword/divider/Highlight_Smooth_Divider.png
new file mode 100644
index 00000000..5cbb2275
Binary files /dev/null and b/OnePassword/divider/Highlight_Smooth_Divider.png differ
diff --git a/OnePassword/divider/Highlight_Smooth_Divider_copy.png b/OnePassword/divider/Highlight_Smooth_Divider_copy.png
new file mode 100644
index 00000000..bfeafb5e
Binary files /dev/null and b/OnePassword/divider/Highlight_Smooth_Divider_copy.png differ
diff --git a/OnePassword/divider/Highlight_StrongDivider_copy_3.png b/OnePassword/divider/Highlight_StrongDivider_copy_3.png
new file mode 100644
index 00000000..d1f512c8
Binary files /dev/null and b/OnePassword/divider/Highlight_StrongDivider_copy_3.png differ
diff --git a/OnePassword/divider/Page.png b/OnePassword/divider/Page.png
new file mode 100644
index 00000000..64e47e12
Binary files /dev/null and b/OnePassword/divider/Page.png differ
diff --git a/OnePassword/divider/Rectangular.png b/OnePassword/divider/Rectangular.png
new file mode 100644
index 00000000..d360d9d8
Binary files /dev/null and b/OnePassword/divider/Rectangular.png differ
diff --git a/OnePassword/divider/Rounded.png b/OnePassword/divider/Rounded.png
new file mode 100644
index 00000000..5652958b
Binary files /dev/null and b/OnePassword/divider/Rounded.png differ
diff --git a/OnePassword/divider/Rounded_Inverted.png b/OnePassword/divider/Rounded_Inverted.png
new file mode 100644
index 00000000..58406c9b
Binary files /dev/null and b/OnePassword/divider/Rounded_Inverted.png differ
diff --git a/OnePassword/divider/Simple.png b/OnePassword/divider/Simple.png
new file mode 100644
index 00000000..96201dd4
Binary files /dev/null and b/OnePassword/divider/Simple.png differ
diff --git a/OnePassword/divider/Simple_Divider.png b/OnePassword/divider/Simple_Divider.png
new file mode 100644
index 00000000..aa812f52
Binary files /dev/null and b/OnePassword/divider/Simple_Divider.png differ
diff --git a/OnePassword/divider/Simple_Divider_.png b/OnePassword/divider/Simple_Divider_.png
new file mode 100644
index 00000000..3fd3d110
Binary files /dev/null and b/OnePassword/divider/Simple_Divider_.png differ
diff --git a/OnePassword/divider/Simple_Divider_Strong.png b/OnePassword/divider/Simple_Divider_Strong.png
new file mode 100644
index 00000000..cf3dbcc3
Binary files /dev/null and b/OnePassword/divider/Simple_Divider_Strong.png differ
diff --git a/OnePassword/divider/Simple_Divider__Strong.png b/OnePassword/divider/Simple_Divider__Strong.png
new file mode 100644
index 00000000..3b3c3579
Binary files /dev/null and b/OnePassword/divider/Simple_Divider__Strong.png differ
diff --git a/OnePassword/divider/Single_Shadow.png b/OnePassword/divider/Single_Shadow.png
new file mode 100644
index 00000000..6fde493e
Binary files /dev/null and b/OnePassword/divider/Single_Shadow.png differ
diff --git a/OnePassword/divider/Single_Shadow_.png b/OnePassword/divider/Single_Shadow_.png
new file mode 100644
index 00000000..3ed722ff
Binary files /dev/null and b/OnePassword/divider/Single_Shadow_.png differ
diff --git a/OnePassword/divider/Smooth_Divider.png b/OnePassword/divider/Smooth_Divider.png
new file mode 100644
index 00000000..b000d774
Binary files /dev/null and b/OnePassword/divider/Smooth_Divider.png differ
diff --git a/OnePassword/divider/Square.png b/OnePassword/divider/Square.png
new file mode 100644
index 00000000..bf3dc06f
Binary files /dev/null and b/OnePassword/divider/Square.png differ
diff --git a/OnePassword/divider/White_Rectangular.png b/OnePassword/divider/White_Rectangular.png
new file mode 100644
index 00000000..36e02a00
Binary files /dev/null and b/OnePassword/divider/White_Rectangular.png differ
diff --git a/OnePassword/en.lproj/MainStoryboard_iPhone.storyboard b/OnePassword/en.lproj/MainStoryboard_iPhone.storyboard
index 286b57e7..1414a889 100644
--- a/OnePassword/en.lproj/MainStoryboard_iPhone.storyboard
+++ b/OnePassword/en.lproj/MainStoryboard_iPhone.storyboard
@@ -5,212 +5,33 @@
-
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
-
-
-
+
+
+
+
-
+
-
-
-
+
+
+
-
-
+
+
+
-
-
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Passwords of this type are encrypted and stored. They are not tied to a certain algorithm but if you loose the storage, you loose the passwords.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -419,49 +207,118 @@
-
-
+
+
-
-
-
+
-
-
-
-
-
-
+
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
@@ -472,281 +329,37 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -757,30 +370,37 @@
+
-
+
+
+
+
-
-
-
-
+
+
+
+
+
+
-
-
+
+
-
+
+
diff --git a/OnePassword/types.c b/OnePassword/types.c
new file mode 100644
index 00000000..71a1946d
--- /dev/null
+++ b/OnePassword/types.c
@@ -0,0 +1,9 @@
+//
+// types.c
+// OnePassword
+//
+// Created by Maarten Billemont on 02/01/12.
+// Copyright (c) 2012 Lyndir. All rights reserved.
+//
+
+#include