2
0

Compare commits

...

405 Commits

Author SHA1 Message Date
Maarten Billemont
d35434705c Minor change. 2014-07-18 22:44:41 -04:00
Maarten Billemont
512f6faf84 Deprecating iCloud on Mac. 2014-07-18 22:04:10 -04:00
Maarten Billemont
82195ee090 Site: Leaning laptop main image. 2014-07-18 09:43:40 -04:00
Maarten Billemont
eb2e070fe3 Site: known issues. 2014-07-17 14:37:15 -04:00
Maarten Billemont
14311dfe66 Fix weirdly added excess statement... 2014-07-02 00:00:12 -04:00
Maarten Billemont
10838aad00 Remove stale Love Lyndir references. 2014-07-01 23:56:44 -04:00
Maarten Billemont
d340278ec5 Did Travis CI fix their shell escaping? 2014-07-01 23:46:42 -04:00
Maarten Billemont
2eb074be87 Some fixes to the Java GUI. Thanks cuardin!
[UPDATED]   Allow lookup by short name.
[FIXED]     GUI only supports generated types, only show generated types in its list.
[UPDATED]   Update site password when type changes.
[FIXED]     Exceptions on illegal input arguments for generation, eg. empty site name.
2014-07-01 12:41:35 -04:00
Maarten Billemont
b84c9b79c8 Travis fix attempt. 2014-07-01 01:13:16 -04:00
Maarten Billemont
c367d5e6cb Small tip tweak. 2014-06-30 22:56:18 -04:00
Maarten Billemont
f8973d6c52 Added some general usage tips. 2014-06-30 21:32:17 -04:00
Maarten Billemont
beaf4e67e7 Small UI tweaks. 2014-06-30 21:12:37 -04:00
Maarten Billemont
06a150792d Catch commands when sites table is active.
[REMOVED]   Love Lyndir, just linking to http://thanks.lhunath.com now.
[UPDATED]   PearlString -> strf
[ADDED]     Catching commands when the sites table view is active too (enter/esc/..)
2014-06-30 21:00:25 -04:00
Maarten Billemont
9816e783e7 Fixed a sizing issue with the new icons. 2014-06-30 00:23:02 -04:00
Maarten Billemont
8b26c301cf Updated icon. 2014-06-30 00:17:03 -04:00
Maarten Billemont
6ddd608a3f Provisioning profiles update. 2014-06-29 23:30:00 -04:00
Maarten Billemont
f1a72d8160 Initial window improvements, reveal and reset master password.
[FIXED]     Initial intro window didn't always show up reliably.
[ADDED]     Ability to temporarily reveal master password while typing it.
[IMPROVED]  When you go down the sites list, fade out the fade-out gradient to prevent the selection from becoming invisible.
[ADDED]     Ability to reset your master password.
[UPDATED]   Initial screenshot of Master Password for Mac and iPhone.
2014-06-29 23:18:25 -04:00
Maarten Billemont
6d4d57441b Usage tip on hide passwords. 2014-06-29 00:29:05 -04:00
Maarten Billemont
971538d6b5 Remove dialog & add import/export
[REMOVED]   Mac password Dialog.
[ADDED]     Mac sites import / export.
[FIXED]     Copying of hidden passwords.
2014-06-28 23:45:06 -04:00
Maarten Billemont
34d8dc375f Update screen capture code to accurately capture the active display only. 2014-06-28 00:04:40 -04:00
Maarten Billemont
f294a8c9f5 hidePasswords, preferences, UI improvements.
[ADDED]     hidePasswords to Mac app for hiding the passwords in the large passwords display, hold alt to reveal.
[ADDED]     Way to easily open the Mac app's preferences.
[IMPROVED]  Use transparent main window to improve the blur effect.
[ADDED]     Key equivalent coach marks when holding alt.
[FIXED]     Don't change sites table when site text field loses focus.
2014-06-26 23:13:21 -04:00
Maarten Billemont
2bd4d57869 Mention IRC channel on site. 2014-06-26 01:59:09 -04:00
Maarten Billemont
c7344dbb0c Small usage tip. 2014-06-26 01:44:53 -04:00
Maarten Billemont
97809a1bc7 Added fancy password display. 2014-06-26 01:35:05 -04:00
Maarten Billemont
5056f9e2e4 Add missing features to new Mac UI: changing password type, setting custom passwords, deleting sites. 2014-06-26 01:19:42 -04:00
Maarten Billemont
150304941c UI changes to the results table. 2014-06-25 14:14:56 -04:00
Maarten Billemont
ff36f6ce87 The search for a background that works on all screens ... 2014-06-24 22:00:33 -04:00
Maarten Billemont
6422084fa0 UI improvements to the Mac app. 2014-06-24 20:30:15 -04:00
Maarten Billemont
651a398798 More Mac GUI work. 2014-06-24 10:47:04 -04:00
Maarten Billemont
31b667c7f7 More work on the experimental new Mac gui. 2014-06-24 00:55:08 -04:00
Maarten Billemont
10affd615c Remove TestFlight. 2014-06-21 23:12:14 -04:00
Maarten Billemont
126c962a98 Disable cloudSwitch when iCloud is unavailable. 2014-06-21 23:04:56 -04:00
Maarten Billemont
2d6a298095 Provisioning profile update. 2014-06-21 22:16:19 -04:00
Maarten Billemont
cc086e2dff A step-by-step guide, fix setup appearance + fix capitalization of master password.
[ADDED]     A new step-by-step guide which uses images and text to explain the basics of Master Password.
[FIXED]     The setup flow didn't appear anymore.
[FIXED]     When creating a new user, the master password field was auto-capitalized.
2014-06-21 22:00:27 -04:00
Maarten Billemont
c5fc87b7b5 An experimental new mac ui that blurs the whole screen. 2014-06-21 21:56:28 -04:00
Maarten Billemont
1433c0851e Crashlytics update. 2014-06-15 20:26:07 -04:00
Maarten Billemont
c60780a197 Hide passwords, placeholder visibility, cancel search, copy login and dark keyboard.
[ADDED]     Option to hide passwords and reveal with long-touch.
[IMPROVED]  More visible placeholder text.
[ADDED]     Cancel button on search field.
[ADDED]     Ability to copy user name.
[UPDATED]   Use dark style keyboard throughout to avoid flickery switches.
[FIXED]     Smaller ui fixes.
2014-06-15 19:51:03 -04:00
Maarten Billemont
bb48771989 Small main context fix. 2014-06-15 11:56:29 -04:00
Maarten Billemont
5466e48629 Allow leaving the master password empty in the config file for the GUI. 2014-06-15 00:05:45 -04:00
Maarten Billemont
d4969a776a Update GUI jar on site. 2014-06-14 23:37:07 -04:00
Maarten Billemont
bb81f5bd5b Merge branch 'master' of github.com:Lyndir/MasterPassword 2014-06-14 23:35:38 -04:00
Maarten Billemont
c38920f238 Improve reliability with regards to bad config files. 2014-06-14 23:33:00 -04:00
Maarten Billemont
be0ae7ff45 UI improvements for the Java GUI. 2014-06-11 09:16:24 -04:00
Maarten Billemont
6808016ab7 Added support for the C CLI's ~/.mpw config file to speed up sign-in to the GUI. 2014-06-11 01:45:31 -04:00
Maarten Billemont
d3c2698790 Add FreeBSD CLI binary. 2014-06-10 16:33:12 -04:00
Maarten Billemont
d1cc9481c3 Small C build and script fixes. 2014-06-10 16:26:24 -04:00
Maarten Billemont
cced75cdfe Update site with different Master Password options. 2014-06-08 23:49:49 -04:00
Maarten Billemont
b74bc79699 A basic cross-platform GUI for the Master Password generation algorithm. 2014-06-08 16:39:26 -04:00
Maarten Billemont
585268eb0f Update AdHoc provisioning. 2014-06-07 20:16:06 -04:00
Maarten Billemont
a713a639cd Added "delete user", fixed some minor UI issues. 2014-06-07 20:13:53 -04:00
Maarten Billemont
113c3790fb Added OS X precompiled binary package. 2014-06-07 15:53:41 -04:00
Maarten Billemont
d732b03828 Finished the C implementation & CLI tool. Providing an OS X binary. 2014-06-07 15:51:11 -04:00
Maarten Billemont
cf9dabcc82 Closed Mac beta due to overwhelming demand! 2014-06-07 13:03:12 -04:00
Maarten Billemont
2bc357cee6 WIP - Initial complete C implementation that's still buggy and generates broken passwords, yay. 2014-06-07 01:27:18 -04:00
Maarten Billemont
c4dca14800 Merge branch 'crashlytics-196' 2014-06-05 22:41:44 -04:00
Maarten Billemont
d8e2707ac0 Fixed crash when scrolling to first element of transient site.
[FIXED]     The first cell of the transient site isn't a Delete button, this caused a crash due to it being rendered with an unexpected type.
2014-06-05 22:41:28 -04:00
Maarten Billemont
25df56f90a Merge branch 'crashlytics-198'
Conflicts:
	External/Pearl
2014-06-05 22:03:32 -04:00
Maarten Billemont
2006e382d4 Hopefully fixed issue with rendering maximum security cells re-used from "new site" cells.
[FIXED]     When a "new site" cell gets recycled as a "maximum security" entity's cell, we may not be able to scroll to the cell index for the type because the collection view's cell indexes weren't updated yet.
2014-06-05 22:00:20 -04:00
Maarten Billemont
98bffa3755 Merge branch 'master' of github.com:Lyndir/MasterPassword 2014-06-05 21:44:23 -04:00
Maarten Billemont
789aa26066 Fix infinite loop when enabling iCloud.
[FIXED]     When enabling iCloud and setting the local user defaults, we re-started enabling iCloud and updating local user defaults.
2014-06-05 21:43:06 -04:00
Maarten Billemont
773058da78 WIP - remove dependency on ciphers.plist. 2014-06-05 17:49:16 -04:00
Maarten Billemont
339ef8d1bc Small improvements to the Internet Defense League code snippet. 2014-06-05 17:48:07 -04:00
Maarten Billemont
db55634ab2 Update logo. 2014-06-04 00:21:07 -04:00
Maarten Billemont
c3364bbbef Fix link opening and popup dismissal bugs. 2014-06-03 23:58:16 -04:00
Maarten Billemont
74e8001506 Site style, description and link updates. 2014-06-03 23:57:39 -04:00
Maarten Billemont
c1c15ddb89 Clean up old UI.
[ADDED]     Password strength to type cells.
[FIXED]     Lots of misc UI fixes.
[ADDED]     Footer links in pull-down.
2014-06-03 21:04:22 -04:00
Maarten Billemont
c8eb2fdde7 Saved passwords login.
[FIXED]     Some crashes.
[ADDED]     Support for saved passwords login.
2014-06-01 22:45:29 -04:00
Maarten Billemont
da7abf1030 Try to fix login item code signing. 2014-05-20 01:20:03 -04:00
Maarten Billemont
8250e9b2c4 Update provisioning profile and sign mac adhoc with dev too (adhoc doesn't allow icloud apps). 2014-05-19 15:13:47 -04:00
Maarten Billemont
e97d6bded4 Project configuration update. 2014-05-19 14:41:45 -04:00
Maarten Billemont
8805a411ba Show all when empty and fix UI updates.
[FIXED]     Updating UI when changing entity model.
[UPDATED]   Show all recent sites when query is empty.
2014-05-19 14:37:05 -04:00
Maarten Billemont
a1ca633aaf Test for TestFlight Application Token. 2014-05-18 08:39:11 -04:00
Maarten Billemont
78d5fc0904 Fix a bunch of warnings... 2014-05-18 00:19:36 -04:00
Maarten Billemont
d9e251c2cd Updated profiles. 2014-05-17 23:53:41 -04:00
Maarten Billemont
fe2b6024bc Remove Localytics and Google+ entirely. 2014-05-17 23:52:51 -04:00
Maarten Billemont
1be65c0969 Merge branch 'new-storyboard'
Conflicts:
	External/LoveLyndir
	External/Pearl
2014-05-17 20:13:51 -04:00
Maarten Billemont
557eb95c7e Login name fixes and coachmark improvements.
[IMPROVED]  Coachmark improvement and animation.
[UPDATED]   Password cell hierarchy refactoring and improvements.
[FIXED]     Login name button.
2014-05-17 20:12:59 -04:00
Maarten Billemont
9941dba008 Clean up classes after removing the small password cell. 2014-05-13 22:56:06 -04:00
Maarten Billemont
fa57b8817b Bugfixes with regards to swiping password types. 2014-05-13 07:27:11 -04:00
Maarten Billemont
943c378206 Delete site WIP. 2014-05-10 21:42:11 -04:00
Maarten Billemont
b53de7a648 Rotation and marquee link.
[UPDATED]   Different Crashlytics for Mac/iOS.
[UPDATED]   Mac build fixes.
[FIXED]     Layout on rotation.  WIP.
[ADDED]     Link on marquee to thanks.lhunath.com.
2014-05-10 09:18:46 -04:00
Maarten Billemont
09afe61a4c Fix .mpw parsing. 2014-05-06 17:21:12 -04:00
Maarten Billemont
7e96496614 Merge branch 'master' of github.com:Lyndir/MasterPassword 2014-05-05 11:18:19 -04:00
Maarten Billemont
d43c19a749 Add C implementation of Master Password. 2014-05-05 11:16:59 -04:00
Maarten Billemont
989cafda71 Add "Internet Defense League" snippet. 2014-05-05 11:15:57 -04:00
Maarten Billemont
e165c6941d Merge branch 'new-storyboard' of github.com:Lyndir/MasterPassword into new-storyboard 2014-04-26 23:24:29 -04:00
Maarten Billemont
9105055ff4 Hopefully fixed an odd PearlLogger bug. 2014-04-26 16:29:13 -04:00
Maarten Billemont
6345899783 Fixed a crash on enumerateCloudStores if iCloud is disabled. 2014-04-26 15:01:24 -04:00
Maarten Billemont
b1daeaf8ed Type fixes. 2014-04-26 14:35:38 -04:00
Maarten Billemont
9fee4a2bbe Fixed critical issue with storing passwords & inconsistency recovery + dictation support.
[FIXED]     Fixed an issue that caused stored passwords to be saved without encryption.
[ADDED]     Logic to check for any data inconsistencies and fix them.
[ADDED]     Support for using dictation in site search box.
2014-04-26 14:03:44 -04:00
Maarten Billemont
fc82790b8c Mac fixes + enabled stored default types. 2014-04-25 20:02:58 -04:00
Maarten Billemont
d95e5ec263 Bump TestFlightSDK to 3.0.0 2014-04-24 22:17:40 -04:00
Maarten Billemont
99456a35ab Remove Google+, DCIntrospect. 2014-04-24 22:12:18 -04:00
Maarten Billemont
b4e052fc9d Small type fixes. 2014-04-24 22:03:23 -04:00
Maarten Billemont
d3852dc78c Small type fix. 2014-04-24 22:00:38 -04:00
Maarten Billemont
f41b7813f9 Code signing configuration update. 2014-04-24 21:59:06 -04:00
Maarten Billemont
6df4a13d93 Remove DCIntrospect now that we have Reveal. 2014-04-24 21:54:05 -04:00
Maarten Billemont
aa461b73c8 Fixed sending emails when the key window is an alert window + added coachmarks. 2014-04-24 21:43:47 -04:00
Maarten Billemont
e070082f4a Restructured passwords UI a bit for a saner nav bar. 2014-04-21 23:35:29 -04:00
Maarten Billemont
079434d62b Fixed pull-down, added sections for settings and logs. 2014-04-20 11:09:49 -04:00
Maarten Billemont
f57de77545 Permanent IDs are now properly generated before save. 2014-04-15 01:07:46 -04:00
Maarten Billemont
18657271ba Fixed MOC hierarchy, saving and permanent object ID resolution. 2014-04-15 00:26:13 -04:00
Maarten Billemont
11d1dc711d Remove status bar from login screen. 2014-04-13 15:45:08 -04:00
Maarten Billemont
965d5efe7f Dismiss emergency generator when deactivated. 2014-04-13 14:06:33 -04:00
Maarten Billemont
87b01fcaaf Operational emergency generator. 2014-04-13 13:04:18 -04:00
Maarten Billemont
b2624c7572 Emergency generator, avatar change, improvements.
[ADDED]     Ability to change avatar while creating new user.
[FIXED]     Transition oddness.
[IMPROVED]  Remove passwordsVC while not needed.
[ADDED]     Emergency generator.
2014-04-12 14:43:41 -04:00
Maarten Billemont
bd37f1d6a7 Completed password cell handling and misc UI and moc update improvements.
[UPDATED]   Make private moc parent of all private blocks to avoid blocking the main thread for writes, update the main moc on private moc updates.
[FIXED]     Don't cause a crash on elements with a bad type.
[UPDATED]   Improved cell handling and UI update handling.
[UPDATED]   Replace FontReplacer with moarfonts to fix issues in UICollectionViewCells.
2014-04-06 23:34:18 -04:00
Maarten Billemont
f475c15360 Dismiss search when tapped outside. 2014-03-20 16:49:33 -04:00
Maarten Billemont
d3d4aeea41 Fix avatar item size to collection view size. 2014-03-20 08:42:15 -04:00
Maarten Billemont
5913ce80e5 full-height avatar collection view + iphone 4 height/keyboard fix. 2014-03-20 08:13:06 -04:00
Maarten Billemont
4c8bed2826 New passwords display in collection view. 2014-03-20 07:15:37 -04:00
Maarten Billemont
d036b43d6f Updated animations for activation of the passwords VC and fancier focussed user. 2014-03-19 20:09:25 -04:00
Maarten Billemont
318aca4d8f WIP - new UI for Master Password. 2014-03-15 20:38:14 -04:00
Maarten Billemont
060c9f91f3 "gmail.com" in guide search bar, iCloud description and tip tooltip.
[UPDATED]   Layout of setup on 4" iPhones.
[UPDATED]   iCloud description text.
[UPDATED]   Show "gmail.com" in the guide's search bar.
[ADDED]     A tooltip on the tip button.
2014-03-08 16:37:36 -05:00
Maarten Billemont
4184f609d6 Fixed updating search results when query is no match or element deleted.
[FIXED]     Make search results empty when no results.
[FIXED]     Update search results upon deletion.
2014-02-28 20:44:29 -05:00
Maarten Billemont
658d710847 Cloud and initial window improvements.
[ADDED]     Advanced option to mark self as corrupt.
[ADDED]     Tell user initial cloud sync can take a moment.
[IMPROVED]  Initial window now visible on full-screen spaces.
[FIXED]     User name label.
2014-02-22 18:27:14 -05:00
Maarten Billemont
3fa9843855 Improved site operations UI.
[IMPROVED]  New UI for site operations.
[ADDED]     Ability to delete a site.
2014-02-21 00:19:24 -05:00
Maarten Billemont
de3f51b447 Merge branch 'master' of github.com:Lyndir/MasterPassword 2014-02-20 07:29:27 -05:00
Maarten Billemont
43c32e0f4c Improved input handling. 2014-02-20 07:29:05 -05:00
Maarten Billemont
775a6fd4ea Collection-view for elements and swipe to modify.
[ADDED]     NSCollectionView for navigating between elements.
[ADDED]     Mac: Functional buttons for changing type, loginName and counter.
2014-02-19 00:59:57 -05:00
Maarten Billemont
4f594c8c1d Merge branch 'master' of github.com:Lyndir/MasterPassword 2014-02-13 17:53:42 -05:00
Maarten Billemont
ebadac8cd8 "Get it for" on new site pages. 2014-02-13 17:53:06 -05:00
Maarten Billemont
c48bed5ebd Add license to site. 2014-02-13 07:44:02 -05:00
Maarten Billemont
4f3efde6f0 Rewrite Mac UI for better multiple site handling. 2014-02-12 00:13:12 -05:00
Maarten Billemont
5b4e86a90a iOSPorts is no longer a requirement + fix some Pearl API. 2014-02-11 08:28:45 -05:00
Maarten Billemont
2be83752db Merge branch 'master' of github.com:Lyndir/MasterPassword 2014-02-10 22:45:13 -05:00
Maarten Billemont
bd1a0f4e25 Fix Mac provisioning. 2014-02-10 22:45:05 -05:00
Maarten Billemont
70cd397591 Get it links on the site. 2014-02-10 09:25:35 -05:00
Maarten Billemont
1120529e34 Added an FAQ page to the homepage.
[ADDED]     FAQ: Answers common questions, most importantly, how to pick a master password.
2014-02-09 22:26:12 -05:00
Maarten Billemont
f57415a08b Security page improvements.
[ADDED]     Table of contents.
[FIXED]     Inline header style fixes.
[ADDED]     Trade-offs.
2014-02-09 17:57:20 -05:00
Maarten Billemont
f9da568bfd Security page improvements.
[UPDATED]   Linguistic improvements to security page.
[ADDED]     Explanation why MP is cryptographically secure.
[ADDED]     Paragraph about Silent Circle and Lavabit to trust section.
[ADDED]     Summary of MP's security features.
[ADDED]     Brief prelude about account security.
2014-02-09 15:44:12 -05:00
Maarten Billemont
39c9f8c5a0 Explain all the security properties of the Master Password solution.
[ADDED]     security.html to the site.
2014-02-07 01:02:43 -05:00
Maarten Billemont
a645e22973 Bump Crashlytics. 2014-01-26 18:57:26 -05:00
Maarten Billemont
eaf86d3348 Use gittip.com instead of Love Lyndir. 2014-01-26 18:55:08 -05:00
Maarten Billemont
2565321a4a Bump TestFlightSDK. 2014-01-26 18:48:05 -05:00
Maarten Billemont
ec828a82fd Build Master Password iOS scheme. 2014-01-26 12:14:33 -05:00
Maarten Billemont
411aa41226 Remove private 'Press' repo. 2014-01-26 12:09:36 -05:00
Maarten Billemont
00b164058d Check out dependencies using script, not git submodule init directly. 2014-01-26 12:03:23 -05:00
Maarten Billemont
9808613c75 Prepare for Travis-CI. 2014-01-26 11:57:57 -05:00
Maarten Billemont
1d20d81652 Bump libraries. 2013-12-23 10:31:06 -05:00
Maarten Billemont
f5c66ff35a Merge branch 'master' of github.com:Lyndir/MasterPassword
Conflicts:
	.gitmodules
2013-12-19 08:17:29 -05:00
Maarten Billemont
4c3d3234f5 Fixed submodule path for LoveLyndir. 2013-12-19 08:16:39 -05:00
Maarten Billemont
d543173b18 API and libraries bump. 2013-12-16 09:07:01 -05:00
Maarten Billemont
d8578e0162 USM fix and misc fixes.
[UPDATED]   UbiquityStoreManager to fix "bad file descriptor" errors.
[FIXED]     Crashlytics script when plist is empty.
[FIXED]     Missing DCIntrospect in updateDependencies.
[UPDATED]   Project configuration.
2013-12-03 20:34:48 -05:00
Maarten Billemont
d665833eba Add masterpassword CLI tool to website. 2013-12-03 20:29:26 -05:00
Maarten Billemont
33e25a5fed CLI tool install script.
[UPDATED]   Templates are now in ciphers.plist.
[ADDED]     Install script for Java-based mpw CLI tool.
[UPDATED]   Java tool is now bundled in a single executable self-containing JAR.
2013-12-03 08:16:32 -05:00
Maarten Billemont
c0737de939 Fix LoveLyndir submodule checkout. 2013-11-29 20:43:19 -05:00
Maarten Billemont
a18679eba8 Fix typo. 2013-11-17 12:49:15 -05:00
Maarten Billemont
ce321aeceb Make sure symbols of libs still exist in .app.
[FIXED]     Don't strip libs, only .app.
2013-11-16 16:36:46 -05:00
Maarten Billemont
6074547f64 Small fixes and privacy policy.
[UPDATED]   Reload users if the selected user can't be found.
[ADDED]     Privacy policy to the website.
[UPDATED]   Pearl - PearlOverlay from main thread.
2013-11-16 16:35:14 -05:00
Maarten Billemont
8432932cb7 Improved icons. 2013-11-09 21:14:23 -05:00
Maarten Billemont
f8dccc04d7 Minor versions 0-padded to 2 digits.
[FIXED]     Automatic app version calculator broke for minor versions < 10... moar hacks.
2013-11-09 21:04:47 -05:00
Maarten Billemont
b38ef59c93 Cleaner iOS icon for iOS 7. 2013-11-09 20:50:53 -05:00
Maarten Billemont
c1162c76d3 LoveLyndir & USM fixes.
[IMPROVED]      Sped up emergency display.
[UPDATED]       LoveLyndir and USM bump for fixes.
2013-11-09 20:18:36 -05:00
Maarten Billemont
231426d5b3 Add LoveLyndir module. 2013-11-09 19:54:55 -05:00
Maarten Billemont
783eb95438 LoveLyndir bump. 2013-11-07 22:07:46 -05:00
Maarten Billemont
7bdc3e153d Removed NSURL+UbiquityStoreManager from USM. 2013-11-07 22:06:06 -05:00
Maarten Billemont
28460d4576 Handle StoreUUID conflicts and new (offline) devices. 2013-11-07 22:03:34 -05:00
Maarten Billemont
396f6fa7bd Navbar overlap in all-sites VC.
[FIXED]     Navbar hack in all-sites causing overlap on device in iOS 7.
[UPDATED]   iCloud defaults to off.
2013-11-04 08:22:30 -05:00
Maarten Billemont
e39eafee7f Importing sites, activity in iOS 7, wipe cloud, love lyndir.
[FIXED]     Bugs when importing mpsites when the user doesn't exist yet.
[FIXED]     Activity now displayed using PearlOverlay, PearlAlert broke in iOS 7 for activity.
[ADDED]     Advanced option to wipe cloud container.
[UPDATED]   Love Lyndir completion.
2013-10-30 23:37:12 -04:00
Maarten Billemont
f1549fe922 Explain other solutions to the iCloud sites problem.
[UPDATED]   Site explains other solutions to iCloud sites disappearing.
2013-10-18 11:13:02 -04:00
Maarten Billemont
b16c539607 Initial LoveLyndir integration. 2013-10-18 01:16:26 -04:00
Maarten Billemont
b11b33da5f Fix potential crash due to reloading of main view and gesture recognizers.
[MOVED]     Search delegates and controllers and gesture recognizers are now fully handled by the storyboard.
2013-10-17 08:15:29 -04:00
Maarten Billemont
6e9cd5a1f5 Fixed app review URL.
[FIXED]     Review button from within app wasn't working anymore on iOS 7.
2013-10-05 21:25:11 -04:00
Maarten Billemont
b67132671a Modernized Obj-C syntax.
[UPDATED]   Modernized Obj-C syntax.
2013-09-27 21:23:52 -04:00
Maarten Billemont
14e34e8e7a Debug an issue with iOS 6 -> iOS 7 cloud store migration. 2013-09-27 20:06:07 -04:00
Maarten Billemont
16f5ab29fa Fix EXCLUDED_SOURCE_FILE_NAMES. 2013-09-22 23:58:21 -04:00
Maarten Billemont
2af717fe5e Bump USM. 2013-09-22 23:56:19 -04:00
Maarten Billemont
c5be6bd742 Fixed local store migration and possible crash.
[FIXED]     Migration to local store.
[FIXED]     Potential crash when enumerating sheets to dismiss.
2013-09-22 23:46:06 -04:00
Maarten Billemont
693eddb578 Bump libraries. 2013-09-22 01:12:19 -04:00
Maarten Billemont
46e5bc2cbf Bump Pearl. 2013-09-21 22:13:32 -04:00
Maarten Billemont
f11afaaa45 Bump Pearl. 2013-09-21 10:46:27 -04:00
Maarten Billemont
cf64ce96f2 Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-09-21 10:44:04 -04:00
Maarten Billemont
b1eae1b06a Bump libs. 2013-09-21 10:43:39 -04:00
Maarten Billemont
d19af3aba8 Fixes for 64-bit and ubiquity logging.
[ADDED]     Debugging with DCIntrospect and Reveal.
[REMOVED]   A bunch of google+ files that are no longer necessary.
[FIXED]     Type and formatting fixes for 64-bit platform types.
[UPDATED]   Production logging of what StoreManager is doing to help people with trouble out.
[ADDED]     Log reason for ubiquity error to checkpoint.
2013-09-21 10:34:48 -04:00
Maarten Billemont
ece5341e27 Cloud store recovery procedure.
[ADDED]     Describe the procedure to recover cloud stores on the website.
2013-09-20 19:25:53 -04:00
Maarten Billemont
7f9aaf4642 Submodule fixes.
[UPDATED]   InAppSettingsKit now uses the lhunath repo.
[UPDATED]   Fix to updating submodule repo URLs in updateDependencies.
[UPDATED]   Minor fix to PearlEmail.
2013-09-19 11:27:47 -04:00
Maarten Billemont
d59c3690d4 Bump Pearl. 2013-09-18 00:22:47 -04:00
Maarten Billemont
37070e482d Fixed a bunch of UI quirks, iOS 6 & 7.
[FIXED]     UI Quirks in iOS 6 and iOS 7.
2013-09-18 00:21:52 -04:00
Maarten Billemont
7fd322a5c6 Fixed icon and version references in Info.plist.
[FIXED]     Remove obsolete icon Info.plist keys.
[FIXED]     Auto-generated CFBundleVersion hash->decimal must be 9 digits long or version bump may end up lowering version number.
2013-09-17 00:13:21 -04:00
Maarten Billemont
07dd98823f Fixes to migration of local store from old Master Password model persistence models. 2013-09-16 23:18:01 -04:00
Maarten Billemont
40d6019f71 Improvements to store migration.
[IMPROVED]  Don't ask to migrate store when there's no sites in it.
2013-09-15 23:14:51 -04:00
Maarten Billemont
32ec0038b6 Bump USM. 2013-09-14 20:24:07 -04:00
Maarten Billemont
99a1d505d3 Fix a deadlock.
[FIXED]     Deadlock when NSUserDefaultsDidChange is handled on the main queue when the main queue is waiting for the persistence queue.
[FIXED]     Logging of cloudEnabled.
[REMOVED]   Debug NSLogs.
2013-09-14 20:21:25 -04:00
Maarten Billemont
62076d8170 Bump USM. 2013-09-14 14:05:47 -04:00
Maarten Billemont
009b1ff996 Fixes to cloud store switching.
[UPDATED]   Log out when user is no longer available.
[UPDATED]   Re-enabled cloud store switching using new USM store enumeration facilities.
[UPDATED]   Lower log level for test and crash logs so we can see why stuff fails.
2013-09-14 14:04:06 -04:00
Maarten Billemont
27870c7420 Fix positioning of toggles.
[FIXED]     Positioning of on/off toggles.
2013-09-14 00:10:12 -04:00
Maarten Billemont
7a16b47e37 Fading improvement, re-login fixed, UI tweaks.
[IMPROVED]  Fading of share/tip delayed, nicer effect.
[FIXED]     No automatic re-login when store changes and saveKey is YES for the current user.
[UPDATED]   Misc UI improvements.
[REMOVED]   Unassigned app icons and launch images.
2013-09-13 23:58:00 -04:00
Maarten Billemont
48324735e1 Fixed counter issue, status bar issue and updated app icons.
[FIXED]     Counter should default to 1, not 0.
[FIXED]     Some issues with the status bar in the MPMainViewController.
[UPDATED]   AppIcons and LaunchImages converted to asset catalog.
[ADDED]     New iOS 7 size app icon images.
2013-09-13 22:32:32 -04:00
Maarten Billemont
f0dcc4c34c Fixed queuing of password generation logic.
[IMPROVED]  Removed password logic out of MPEntities so that it can be backgrounded without relying on the persistence layer staying up.
[IMPROVED]  Some workload removed from the main thread.
2013-09-13 08:14:58 -04:00
Maarten Billemont
36386c3213 iOS 7 cloud loading. 2013-09-08 10:42:28 -04:00
Maarten Billemont
8ea0f00cf0 Improved cloud store enumeration.
[ADDED]     Stores now enumerated in a TVC.
2013-09-07 10:08:49 -04:00
Maarten Billemont
0921796136 Log VC, iCloud toggling, iOS 7 fixes.
[UPDATED]   Show users and sites in cloud stores of log VC.
[ADDED]     Ability to turn off iCloud if corruption happens.
[ADDED]     When switching iCloud on/off, provide user the option to migrate his current sites.
[ADDED]     Ability to get to settings & logs from unlock VC.
2013-09-05 23:52:12 -04:00
Maarten Billemont
ab360066e5 More robust migration.
[FIXED]     Better recovery from failure to migrate local store.
[FIXED]     Ability to migrate outdated local store models.
2013-08-31 12:29:56 -04:00
Maarten Billemont
34645c9433 Theming for iOS 6, updated status hiding and more exception handling.
[ADDED]     More verbose log printing when trace enabled.
[ADDED]     More exception handling on application launch; we can't allow any of this to keep us from being able to open the emergency generator.
[UPDATED]   Only apply UI theming on iOS 6-.
[ADDED]     Modern way of hiding the status bar on iOS 7.
2013-08-27 23:28:51 -04:00
Maarten Billemont
b2a608824c Merge branch 'master' into ios7
Conflicts:
	MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj
2013-08-27 22:18:40 -04:00
Maarten Billemont
af56920fd9 Show all release checks that fail at once. 2013-08-27 22:15:45 -04:00
Maarten Billemont
784b741b60 Fix documentation of LocalyticsSession.h 2013-08-27 22:05:16 -04:00
Maarten Billemont
ea066bd828 Fix some warnings in Pearl. 2013-08-27 21:56:47 -04:00
Maarten Billemont
c5d88bd5c7 Bumping libraries and project configuration updates.
[UPDATED]   TestFlight SDK -> 2.0.0
[UPDATED]   USM to deal with exceptions better.
[UPDATED]   Project configuration.
2013-08-27 21:51:56 -04:00
Maarten Billemont
a8115fdced Bump USM. 2013-08-27 20:49:02 -04:00
Maarten Billemont
c0406888fc Fix storyboard inconsistencies.
[FIXED]     Storyboard had multiple resource references with the same name.
2013-08-26 23:25:03 -04:00
Maarten Billemont
c7f04f8449 Merge branch 'master' into ios7 2013-08-26 23:20:28 -04:00
Maarten Billemont
ae4be86ecf UI fix for iOS 7.
[FIXED]     New ActionSheet doesn't deal well with spacing in items.
[FIXED]     UI now works on iOS 7.
2013-08-26 23:20:19 -04:00
Maarten Billemont
d188985823 Revert "UI fix for iOS 7."
This reverts commit ac0d412123.
2013-08-26 23:20:08 -04:00
Maarten Billemont
ac0d412123 UI fix for iOS 7.
[FIXED]     New ActionSheet doesn't deal well with spacing in items.
[FIXED]     UI now works on iOS 7.
2013-08-26 23:19:44 -04:00
Maarten Billemont
19e35dbccd Unclutter the UI and revert to no news. 2013-08-26 23:18:04 -04:00
Maarten Billemont
3086baf523 Fix MPAppsVC pager positioning on 4".
[FIXED]     Manually added pager VC added to wrong superview.
2013-08-26 23:17:02 -04:00
Maarten Billemont
e3d8d3c31c statusbar/navbar visibility & news.html
[FIXED]     Handle statusbar/navbar visibility only from viewWillAppear.
[FIXED]     URL to news.html.
2013-08-26 21:43:34 -04:00
Maarten Billemont
7589b3a048 Revert Xcode 5 change to storyboard. 2013-08-25 18:50:17 -04:00
Maarten Billemont
72f0d69a71 Don't use Localytics or Crashlytics when disabled. 2013-08-25 18:49:13 -04:00
Maarten Billemont
2399156ee4 Conditionally enable crash/analytics. 2013-08-25 15:38:38 -04:00
Maarten Billemont
3d3f08da9b Add a release checking script to prevent bad releases. 2013-08-15 22:18:17 -04:00
Maarten Billemont
2a0abf0da7 Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-08-15 19:38:16 -04:00
Maarten Billemont
2d8146edbd Fixed potential crashed due to rare nil values at checkpoints.
[FIXED]     Avoid nil values at checkpoints since they will cause crashes.
2013-08-15 19:38:05 -04:00
Maarten Billemont
dad198f5e1 Update radials in site to support other browsers. 2013-08-15 09:53:08 -04:00
Maarten Billemont
0a5329fe17 Email/support un news.
[UPDATED]   Refresh news whenever the app opens.
[UPDATED]   Email and support links in news.html
2013-08-11 16:20:56 -04:00
Maarten Billemont
64d9f09cf6 Minor USM bump. 2013-08-11 15:40:44 -04:00
Maarten Billemont
d583d12099 Option to turn off iCloud on corruption.
[ADDED]     Option to turn off iCloud when store is broken.
2013-08-11 15:37:51 -04:00
Maarten Billemont
17bb5706f8 Fixed some minor crash cases.
[FIXED]     Crash when changing iCloud store.
[FIXED]     Use main thread when holding down on a user.
2013-08-11 15:30:01 -04:00
Maarten Billemont
d583bdfd3c Added support page to site.
[ADDED]     Site support page.
2013-08-11 14:11:19 -04:00
Maarten Billemont
9eb9667163 Make sure CFBundleVersion is always higher, try 2... 2013-08-11 00:23:45 -04:00
Maarten Billemont
a315a9dfc3 Make sure CFBundleVersion is always higher... 2013-08-11 00:20:10 -04:00
Maarten Billemont
8375808cdc Bump External dependencies. 2013-08-11 00:08:25 -04:00
Maarten Billemont
77439af486 Bump Crashlytics SDK. 2013-08-10 23:49:43 -04:00
Maarten Billemont
76f4a00738 Revert Storyboard back to Xcode 4 compatible format. 2013-08-10 23:32:33 -04:00
Maarten Billemont
9d615b2d4c Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-07-07 21:17:00 -04:00
Maarten Billemont
aaffc0297e Profile bump.
[UPDATED]   Master Password Ad Hoc profile.
2013-07-07 21:15:57 -04:00
Maarten Billemont
5dc5885582 Site updates.
[UPDATED]   Mention the value of passwords never leaving your device.
[UPDATED]   Added some emphasis in the algorithm section.
2013-06-28 09:07:53 -04:00
Maarten Billemont
7389f5bf45 Fix queue of observer/notification blocks.
[FIXED]     Make sure all notification and observer blocks that expect the main thread are scheduled on it.
2013-06-26 20:23:02 -04:00
Maarten Billemont
b06d461a36 Fix code active signing profile. 2013-06-16 20:27:53 -04:00
Maarten Billemont
802f57878b Bump Press. 2013-06-16 20:25:11 -04:00
Maarten Billemont
bccf35d057 More clear master password creation tip.
[IMPROVED]  Word wall tip.
2013-06-16 19:31:09 -04:00
Maarten Billemont
137a1c531c Legacy icon set. 2013-06-16 15:09:33 -04:00
Maarten Billemont
e96df9f990 Xcode 4 build fixes. 2013-06-16 15:08:05 -04:00
Maarten Billemont
691670cc43 Fix Xcode 4 issues & double type trigger. 2013-06-16 14:22:36 -04:00
Maarten Billemont
bd64bfec67 Password window improvements.
[FIXED]     Password window closes initially.
[FIXED]     Site label more visible.
2013-06-16 13:48:51 -04:00
Maarten Billemont
0813fb40d0 Retire use of confinement concurrency type.
[FIXED]     Confinement concurrency type is just all sorts of buggy.
2013-06-16 12:39:52 -04:00
Maarten Billemont
3cb8215d5a Migrate to xcassets for app icon. 2013-06-16 11:26:32 -04:00
Maarten Billemont
a7fe11e8db Press bump. 2013-06-16 01:01:53 -04:00
Maarten Billemont
4a9fc66b5a Fix new analysis and compiler warnings. 2013-06-16 01:00:57 -04:00
Maarten Billemont
fb81cd61a9 More project configuration. 2013-06-16 00:49:44 -04:00
Maarten Billemont
13034b4184 Project configuration improvements and warning fixes.
[UPDATED]   Fixed some warnings by explicitly type-casting NSNotFound checks.
[UPDATED]   Fixed some Xcode 5 warnings by doing project configuration improvements.
2013-06-16 00:47:33 -04:00
Maarten Billemont
b2345da9f3 Type selection for Mac.
[ADDED]     Mac: Type selection for site passwords.
[UPDATED]   Type changing refactored to be OS independant.
2013-06-15 01:39:49 -04:00
Maarten Billemont
08d3d9ad30 Improve lock/unlock assurance flow.
[FIXED]     Bug that caused the window to sometimes re-open when closed.
2013-06-09 19:03:54 -04:00
Maarten Billemont
797060f609 Add a space to the OS X wrapper name. 2013-06-08 20:37:53 -04:00
Maarten Billemont
ea09116929 Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-06-08 18:13:20 -04:00
Maarten Billemont
86758b498c Open at Login and initial window improvements.
[ADDED]     Mac: Open at Login.
[UPDATED]   Mac: Mark users menu item when no user selected.
[ADDED]     Mac: Toggle open-at-login and enable-cloud from initial window.
2013-06-08 18:12:49 -04:00
Maarten Billemont
9115b56a42 Update updateDependencies. 2013-06-05 09:09:23 -04:00
Maarten Billemont
c400868026 Activate before no-user alert.
[FIXED]     Also activate app before no-user alert.
2013-06-04 21:31:02 -04:00
Maarten Billemont
b4dbb15853 Submodule maintenance. 2013-06-04 08:25:32 -04:00
Maarten Billemont
195f70db53 Menu and first-launch improvements.
[ADDED]     On first start, show the status item by highlighting and opening it.
[UPDATED]   Using RHStatusItemView for status item so we can highlight it programmatically.
[FIXED]     Activate app on startup so apps window shows.
[ADDED]     NSAlert when trying to open password window with no user selected.
[UPDATED]   Crisper menu icon.
2013-06-04 00:56:19 -04:00
Maarten Billemont
f3248f446c Missing news site causes error message in MP.
[ADDED]     Dummy news.html.
2013-06-04 00:52:29 -04:00
Maarten Billemont
80cb2c8a4f Based site on HTML5 boilerplate. 2013-06-02 19:12:25 -04:00
Maarten Billemont
35a600080b iCloud availability check.
[UPDATED]   Disable iCloud preference when iCloud is unavailable.
[FIXED]     Username in incorrect-mp error popup.
2013-05-31 00:14:04 -04:00
Maarten Billemont
af1efe7bc6 iCloud no longer required for Mac.
[UPDATED]   Mac: Allow iCloud to be disabled.
2013-05-30 00:16:03 -04:00
Maarten Billemont
8219ef10f5 New website. 2013-05-30 00:14:51 -04:00
Maarten Billemont
35411c3261 Added new website. 2013-05-26 01:06:44 -04:00
Maarten Billemont
e8bab69ed7 Mac: iOS App Advertisement + bug fixes.
[ADDED]     Window to advertise iOS app.
[FIXED]     Under some conditions, quit didn't work reliably.
[UPDATED]   Mac UI improvements.
[UPDATED]   Mac Executable Name 'Master Password'.
2013-05-19 16:55:43 -04:00
Maarten Billemont
9904fb2d57 Alert display issues fixed.
[FIXED]     Alert display issues.
[FIXED]     Access to activeUser from a different thread.
2013-05-16 00:59:32 -04:00
Maarten Billemont
d7f369350b Store loading and locking modal alerts.
[ADDED]     Waiting until the store is loaded.
[UPDATED]   Hide or lock password window when locked.
2013-05-16 00:19:50 -04:00
Maarten Billemont
0df322f648 Fixed saveKey getting unset and some MOC threading issues.
[FIXED]     Don't unset saveKey when loading the key fails.
            This causes saveKey to fail as soon as it's synced to a device that hasn't saved the key yet.
[FIXED]     A bunch of threading violation issues with thread-confined MOCs.
2013-05-15 22:42:21 -04:00
Maarten Billemont
cb860cec96 Prepare for new site. 2013-05-13 21:11:58 -04:00
Maarten Billemont
14c0b2dd27 Resource clean-up.
[REMOVED]   Unused resources removed from .app.
[DELETED]   Guide pages aren't used anymore.
[UPDATED]   pngcrush'ed all PNGs to reduce their size.
2013-05-13 00:22:24 -04:00
Maarten Billemont
a2521483c2 Fix orientation bug in lock screen.
[FIXED]     When navigating back from oriented main vc, lock vc isn't rotated back to portrait.
2013-05-12 16:48:54 -04:00
Maarten Billemont
fa4b2a9e54 Ability to select a different cloud store.
[ADDED]     Advanced feature to allow selecting a different cloud store.
2013-05-12 14:08:45 -04:00
Maarten Billemont
e3963a72ad Press bump. 2013-05-11 20:05:07 -04:00
Maarten Billemont
cefe8d144d Import fix, password type change fix, fancier generator appearance.
[FIXED]     Import of ubiquity changes was using wrong delegate method and MOC.
[FIXED]     Password type change broken when password type causes a class change.
[IMPROVED]  Fancier animation of emergency generator appearance.
2013-05-11 19:43:41 -04:00
Maarten Billemont
076cfb1257 MOC saving improvements, Mac app activation, loading overlay, USM update.
[MOVED]     iOS code from MPAppDelegate_Shared to MPiOSAppDelegate.
[FIXED]     Perform MOC saving in MOC perform blocks.
[FIXED]     Mac: Activate app when showing password window and not active.
[FIXED]     Hide overlay while corruption dialog is up.
[FIXED]     Hide corruption dialog when reloading store.
2013-05-11 08:55:09 -04:00
Maarten Billemont
71e3f44c8c Improved migration, file-based StoreUUID, Mac fixes.
[ADDED]     Migration to file-based StoreUUID.
[IMPROVED]  Cleaner, more modular, migration code.
[FIXED]     Don't hook activation to show password window: too annoying when focus shifts.
[FIXED]     Don't set the active user when just importing ubiquity changes, it causes a log-out.
[ADDED]     Mac: Ability to rebuild iCloud.
[REMOVED]   Mac: wasRunning logic to avoid password window appearance on first activation.
[FIXED]     Mac: Retrieve siteName from main thread.
2013-05-10 11:13:55 -04:00
Maarten Billemont
c36f34346d Output info level logs when sendInfo is enabled to aid in debugging. 2013-05-07 16:16:33 -04:00
Maarten Billemont
cd6b83ffe8 iPhone 5 alignment issue in unlock VC.
[FIXED]     Deselect new user avatar if MOC is unavailable when tapping it.
[FIXED]     Position of avatars & spinner on iPhone 5.
[IMPROVED]  Issue button in review dialog.
2013-05-07 13:25:05 -04:00
Maarten Billemont
d110fd18c1 Started checkpoint and executable name revert.
[ADDED]     "Started" checkpoint that logs some platform environment properties.
[REVERTED]  Executable/app name back to just MasterPassword.
2013-05-07 11:22:01 -04:00
Maarten Billemont
e45b9985c2 Mac: New sites.
[MOVED]     Creation of new elements moved to shared code.
[FIXED]     When switching user, unset active key.
[FIXED]     Synchronize content calculation to avoid race issues while typing.
[ADDED]     Ability to create new sites.
[FIXED]     Unset active element when hitting backspace or escape.
2013-05-07 00:48:48 -04:00
Maarten Billemont
8f4eb6df84 Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-05-03 23:50:57 -04:00
Maarten Billemont
809bd60169 Info.plist fixes.
[FIXED]     Add extensions to Icon as well to CFBundleIconFiles because Xcode doesn't seem to listen to the Apple docs.
[FIXED]     Removed newsstand metadata: this is not a newsstand app.
2013-05-03 11:29:38 -04:00
Maarten Billemont
802c5949da More compatible way of specifying icon files.
[FIXED]     Add extensions to Icon as well to CFBundleIconFiles because Xcode doesn't seem to listen to the Apple docs.
2013-05-03 10:15:27 -04:00
Maarten Billemont
407c5528ee Fix sign comparison of enum. 2013-05-02 22:03:53 -04:00
Maarten Billemont
fed3a2bc10 Fix sign comparison of enum. 2013-05-02 22:03:53 -04:00
Maarten Billemont
7329353c6c Work-around for a weird Core Data bug. 2013-05-02 22:01:18 -04:00
Maarten Billemont
a7c861d1b0 Work-around for a weird Core Data bug. 2013-05-02 22:01:18 -04:00
Maarten Billemont
9af8ab3360 Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-05-02 20:41:46 -04:00
Maarten Billemont
ddb5328019 Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-05-02 20:41:46 -04:00
Maarten Billemont
96d97d95e1 New user on Mac.
[ADDED]     Mac: Support for creating a new user.
2013-05-02 20:40:12 -04:00
Maarten Billemont
ab15694d9a Safer migration, boolean description fix.
[ADDED]     Safer store migration: don't delete the old store, allowing the client to downgrade.
[ADDED]     Log checkpoints and send to TestFlight too.
[FIXED]     Describe booleans as YES/NO, not 1/0.
2013-05-02 11:19:34 -04:00
Maarten Billemont
81312e3ff4 Safer migration, boolean description fix.
[ADDED]     Safer store migration: don't delete the old store, allowing the client to downgrade.
[ADDED]     Log checkpoints and send to TestFlight too.
[FIXED]     Describe booleans as YES/NO, not 1/0.
2013-05-02 11:19:34 -04:00
Maarten Billemont
5e1e88bdeb Fancier password dialog.
[ADDED]     Mac: Shadows on labels so they're easier to read in regular mode.
[ADDED]     Mac: Some "subtle" bling on the password.
2013-04-30 21:10:52 -04:00
Maarten Billemont
9882bf408c Content generation fix.
[UPDATED]   For safer MOC usage API.
[FIXED]     Actually set the active element so that content is generated.
2013-04-30 20:49:42 -04:00
Maarten Billemont
40f34f3d77 Avoid using object.managedObjectContext - when no strong reference exists to the MOC, it may yield nil.
[FIXED]     Unexpected nil MOCs.
2013-04-30 01:49:53 -04:00
Maarten Billemont
0ee1e176ed Don't use temporary objectIDs for state.
[FIXED]     Make sure we have permanent ObjectIDs before storing them in state.
[FIXED]     MP-14
2013-04-30 00:32:30 -04:00
Maarten Billemont
c73f89e4a1 App versioning update.
[UPDATED]   App versioning: version is now: decimal short commit hash, short version is now tag+commit number.
2013-04-29 21:24:45 -04:00
Maarten Billemont
fe9a1cdbc4 Log Inspector and trace mode.
[ADDED]     Log Inspector, shake on preference screen to open log.
[ADDED]     Trace Mode: Log at trace level.
[FIXED]     Log messages weren't being recorded for inclusion in feedback.
2013-04-29 21:15:14 -04:00
Maarten Billemont
8a4eecd9fa Removed volume button.
[REMOVED]   Volume button in guide - there is no voice-over.
2013-04-28 00:46:08 -04:00
Maarten Billemont
d27a0fdbad Core Data context fixes and migration fixes.
[FIXED]     More careful Core Data threading and context usage.
[FIXED]     iOS bug when migrating, now using USM's copy migration.
[ADDED]     Better handling of store changes while in Main VC and Element List VCs.
2013-04-28 00:35:32 -04:00
Maarten Billemont
07e44a46ae Remove Facebook App ID & add icon to archive. 2013-04-27 17:53:54 -04:00
Maarten Billemont
dfda47bca0 Warn when secret data is unavailable so we notice when it is. 2013-04-27 17:39:31 -04:00
Maarten Billemont
6fb36035c2 TestFlight now uses an "Application Token". 2013-04-27 17:17:51 -04:00
Maarten Billemont
a6e3b83ebb Dumped Google+ SDK.
[UPDATED]   Google+ SDK.
2013-04-27 17:14:05 -04:00
Maarten Billemont
dc3c30a2f7 Localytics update.
[UPDATED]   Localytics update.
[ADDED]     When sendInfo is enabled, set the user identifier on Localytics.
2013-04-27 16:37:32 -04:00
Maarten Billemont
3219fc764f Fixed and updated InAppSettingsKit.
[UPDATED]   InAppSettingsKit
[IMPROVED]  Text in Settings.bundle.
2013-04-27 16:01:31 -04:00
Maarten Billemont
5d5e9395b3 Threading fixes for Mac, spinner fix for iOS.
[UPDATED]   TestFlight.
[FIXED]     Mac: References to MPAppDelegate that should be OS-independant now use MPAppDelegate_Shared.
[FIXED]     Mac: Threading and content UI updates.
[FIXED]     iOS: Spinner was showing when going back to unlock VC.
2013-04-27 00:34:28 -04:00
Maarten Billemont
291b408995 More workspace fixes to avoid iOS/Mac confusion by IDE.
[RENAMED]   MPAppDelegate -> MPiOSAppDelegate for iOS to avoid class name confusion in workspace.
2013-04-24 21:26:04 -04:00
Maarten Billemont
ceb0333fcf Active user switching for for password window.
[RENAMED]   MPAppDelegate -> MPMacAppDelegate for Mac to avoid class name confusion in workspace.
[FIXED]     Window behavior when switching user.
2013-04-24 21:23:53 -04:00
Maarten Billemont
44b4e5430a Password window style.
[ADDED]     Ability to change style of password window.
[FIXED]     Some window activation oddities (WIP).
[UPDATED]   Renamed executable iOS/Mac specific in the hopes of helping with IDE conflicts.
2013-04-24 00:25:51 -04:00
Maarten Billemont
cb7e145e83 Fixed a bunch of OS X issues.
[FIXED]     Don't create a moc when the main moc is unset.
[FIXED]     Load the MPUserEntity into the moc when doing selectUser:
[FIXED]     Remove KVO on activeUserObjectID, isn't used anymore.  Instead, override setActiveUser:
[FIXED]     Don't show the password window on launch.
[FIXED]     Don't force unlock of the key whenever unset - only when the window pops.
[REMOVED]   Migration - this app is not ready for explicit migration, additionally, this block appears to cause a lock-up of the PSC.
2013-04-23 20:38:56 -04:00
Maarten Billemont
35ef2b0789 Icon file restructuring. 2013-04-22 00:57:17 -04:00
Maarten Billemont
e34adae8f0 OS X build fixes. 2013-04-21 17:05:59 -04:00
Maarten Billemont
5137cbf14d Checkpoint for opening emergency generator. 2013-04-21 13:34:33 -04:00
Maarten Billemont
32fb52f48f Update emergencyContentTipContainer in storyboard. 2013-04-20 19:53:54 -04:00
Maarten Billemont
95d5d8b40c Reformat. 2013-04-20 14:11:19 -04:00
Maarten Billemont
c0d57b5561 MPCheckpoint
[UPDATED]   Refactoring of checkpoints.
2013-04-20 13:51:37 -04:00
Maarten Billemont
efcfbe2584 Fixed popup appearance.
[FIXED]     Appearance of popup when copying emergency password.
2013-04-20 12:14:44 -04:00
Maarten Billemont
eeac1d0dd3 Initial page-flip other apps, emergency password copy and marquee hint.
[ADDED]     Initial page-flip animation on opening of other apps VC to make it clear to the user that pages can be flipped.
[ADDED]     Copying of password from emergency generator.
[ADDED]     Marquee animate the bottom tip to also hint about the emergency generator.
2013-04-20 11:44:26 -04:00
Maarten Billemont
ac1358a0ec Emergency generator, action pictograms.
[ADDED]     Emergency Generator!
[ADDED]     Easier method for just using the master password algorithm bare.
[UPDATED]   Pictograms in action popup and centering of text.
2013-04-19 00:43:01 -04:00
Maarten Billemont
c31df49599 activeUser refactor, tool tip hiding and dismiss when logout.
[UPDATED]   Made activeUser access follow same pattern as activeElement which makes it more clear what the thread model is like.
[FIXED]     Save after update of all elements.
[UPDATED]   Tool tips hidden in IB now; makes it less cluttered.
[FIXED]     Dismissing view controllers when logging out.
2013-04-17 22:00:15 -04:00
Maarten Billemont
ee93412dd1 Search & AllSites improvements, sort by recency, rememberLogin setup.
[UPDATED]   Simplified AllSites VC in IB (removed the unused navVC).
[UPDATED]   Outdated sites are now shown in the AllSites VC.
[ADDED]     An update-all-sites button when showing outdated sites in the AllSites VC.
[REMOVED]   Search scopes.
[ADDED]     Sorting elements by recency and usage count now.
[FIXED]     Initial positioning of help container.
[ADDED]     Setup VC for rememberLogin.
2013-04-15 00:04:16 -04:00
Maarten Billemont
7cf2c7f5c6 Setup and guide.
[FIXED]     Setup wasn't showing up on app load.
[FIXED]     More temporary moc fixes and main thread fixes.
[IMPROVED]  Guide now plays an introduction animation.
[FIXED]     Setup iCloud switch is now functional.
2013-04-14 10:26:34 -04:00
Maarten Billemont
5bf8842031 More fixes of temporary moc accesses. 2013-04-13 14:03:50 -04:00
Maarten Billemont
abe874cda3 Temporary moc fix, setup & new guide.
[FIXED]     Pass along temporary mocs, they appear to be stored __weak in the object and we can't rely on them not being nil.
[ADDED]     Setup flow for initially setting the iCloud preference.
[ADDED]     New guide.
[IMPROVED]  Hierarchy and flow of unlock -> main.
2013-04-13 13:40:17 -04:00
Maarten Billemont
036c04f65f Migration cleanup and improvements.
[IMPROVED]  Migration code cleanup.
[FIXED]     When local store migration fails, fall back to opening the old local store if possible.
[FIXED]     Better migration of cloud preferences.
[FIXED]     Better checking of when to perform cloud store migration.
[FIXED]     Always migrate the local store, even when the cloud store is enabled.
[UPDATED]   Removed the loading indicator in favor of a loading overlay.
[UPDATED]   Sorted the file references lexicographically.
2013-04-07 19:43:14 -04:00
Maarten Billemont
418411769d Migration fixes.
[FIXED]     Moved migration into the persistence queue by performing it on willLoadStore.
[FIXED]     Re-enabled cloud after migration.
[UPDATED]   Allow rebuilding the old cloud store if it got deleted locally.
2013-04-06 19:41:20 -04:00
Maarten Billemont
12804984ba Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-04-05 00:33:10 -04:00
Maarten Billemont
de36cf8645 Fixes for new properties in MPAppDelegate_Store
[FIXED]     Properties in categories aren't synthesized.  Using fancy new PearlAssociateObjectProperty from Pearl now to make a fake property.
[FIXED]     Show overlay on UI thread.
[FIXED]     ONLY_ACTIVE_ARCH = NO because weird codesign errors happen on second build with it set to YES.
	modified:   External/Pearl
2013-04-05 00:31:05 -04:00
Maarten Billemont
922230c54e Remove iCloudStoreManager.
[REMOVED]   iCloudStoreManager was replaced by UbiquityStoreManager.
2013-04-04 14:16:33 -04:00
Maarten Billemont
e0e548c611 Merge branch 'master' of github.com:Lyndir/MasterPassword 2013-04-04 10:54:07 -04:00
Maarten Billemont
5e40258f54 Updated for new UbiquityStoreManager API.
[UPDATED]   New and improved UbiquityStoreManager with better API.
2013-04-03 19:25:15 -04:00
Maarten Billemont
2f17639eeb Revert "Temporary build fix: Disable iCloudStoreManager integration."
This reverts commit b301d0bdd6.
2013-04-01 22:03:28 -04:00
Maarten Billemont
e22be0f97c Build fixes. 2013-03-30 11:53:26 -04:00
Maarten Billemont
0a394265fa Update Mac project after file restructuring. 2013-03-29 20:24:06 -04:00
Maarten Billemont
9c10a2c4e3 Xcode workspace
[UPDATED]   Crashlytics.
2013-03-29 17:41:22 -04:00
Maarten Billemont
93a672b22f Update build scripts for new paths.
[FIXED]     After relocation, the build scripts need path updates.
2013-03-29 12:10:01 -04:00
Maarten Billemont
b301d0bdd6 Temporary build fix: Disable iCloudStoreManager integration. 2013-03-29 12:03:31 -04:00
Maarten Billemont
1c79545245 Serious houskeeping: Better file structure & preparation for Xcode workspace. 2013-03-29 11:59:47 -04:00
Maarten Billemont
02b323d640 Keep track of some todos. 2013-03-29 09:07:01 -04:00
Maarten Billemont
4b8d30ac28 Initial android artifact.
[ADDED]     Added initial stub for an android MP app.
2013-03-29 09:05:15 -04:00
Maarten Billemont
cd475580ff iCloudStoreManager is now UbiquityStoreManager 2013-03-29 09:05:03 -04:00
Maarten Billemont
f937792fc2 Typo correction in site. 2013-03-28 10:19:30 -04:00
Maarten Billemont
31d4d5b6c6 Extract common code from SearchVC and AllVC.
[ADDED]     A more generic element listing controller, now used by the
            search controller and all elements listing controller.
[IMPROVED]  Improved change detection and UI handling in the element
            listing controllers.
[FIXED]     Bug with previewing generated password types for
            non-generated elements.
2013-02-10 15:28:58 -05:00
Maarten Billemont
d7d91d13c6 UI updates: site search & type change
[ADDED]     Display the password type when searching for sites.
[ADDED]     Indicate the strength of a password type by time to crack.
[ADDED]     Display a password prediction below each password type on
            the type selection screen.
[MOVED]     Moved the Short type below the Basic type because it's less
            secure.
[FIXED]     Some font regression bugs.
2013-02-08 18:11:24 -05:00
Maarten Billemont
16a7b87d2a Update content font to Source Code Pro.
[UPDATE]    Font of element content and loginName to Source Code Pro for
            improved legibility and distinguishment between O and 0.
[REMOVED]   Unused fonts from the bundle to save space.
2013-02-02 14:17:35 -05:00
Maarten Billemont
21f1e7ee49 New element fix and statusbar experimentation.
[FIXED]     Set lastUsed when creating a new site since elements can't
            be saved without that value set.
[UPDATED]   Configuration for tinting of status bar.
            Doesn't work yet with the custom navbar container image:
            Should check if last row of that image's pixels isn't too
            dark.  iOS 6 apparently averages it for the tint color.
2013-02-02 01:38:11 -05:00
Maarten Billemont
ad8317a7a0 All sites add button.
[ADDED]     An add site button in the all sites VC.
2013-02-02 00:45:30 -05:00
Maarten Billemont
820be14845 Add missing dependencies to updateDependencies. 2013-02-01 16:45:35 -05:00
Maarten Billemont
b7d3b2d02c Ignore IDE preferences of Java implementation. 2013-02-01 12:54:57 -05:00
Maarten Billemont
a710765336 Bump Java dependencies to release.
[UPDATED]   Java: property-list to 2.0.0
2013-02-01 12:53:17 -05:00
Maarten Billemont
9a68cbf533 Listing all sites now with bookmark button and modal VC.
[ADDED]     Modal VC to show all sites.
[UPDATED]   All sites button on search bar now uses bookmark button.
[REMOVED]   Query string hack for search results button.
2013-02-01 01:13:45 -05:00
Maarten Billemont
2bb0e2e3ef Icon update.
[UPDATED]   Icon graphics updated.
2013-01-31 20:58:27 -05:00
Maarten Billemont
17c47269a3 Startup UI improvements.
[IMPROVED]  Fade-in effect when opening Master Password.
[IMPROVED]  Shade of circular shadow fixed between launch image and
            background image.
2013-01-31 18:58:56 -05:00
Maarten Billemont
6c23134e47 Update Google+ integration.
[UPDATED]   Google+ SDK to 1.1.0.
2013-01-31 16:33:46 -05:00
Maarten Billemont
cc015ada1b Delete stale reference to facebook-ios-sdk
[REMOVED]   Stale reference to facebook-ios-sdk submodule.
2013-01-31 12:29:24 -05:00
Maarten Billemont
acd52e8ef6 Bump Pearl and TestFlight for iOS 6 fixes.
[UPDATED]   Pearl for iOS 6 compilation fixes.
[UPDATED]   TestFlight for close_file bugfix.
2013-01-31 12:25:17 -05:00
Maarten Billemont
f2ee139db6 Social update, CoreData overhaul & iOS6/rotation fixes.
[REMOVED]   Facebook SDK.
[ADDED]     Social framework integration for Twitter & Facebook.
[MOVED]     User migration warning state moved into MainVC, out of
            data model.
[UPDATED]   Major overhaul of Core Data integration.  Multiple contexts
            and making sure we're on the right thread and the right
            context even for read access.
[FIXED]     Some iOS 6 deprecation fixes.
[FIXED]     Some VC rotation issues.
2013-01-31 00:42:32 -05:00
Maarten Billemont
725da285da Minor code improvement.
[FIXED]     Some minor code fixes thanks to inspections.
[FIXED]     Some iOS6 deprecation issues.
[IMPROVED]  Cleanup with regards to store migration.
2013-01-27 16:27:49 -05:00
Maarten Billemont
1b3f5f5d25 Added a few missing resources.
[ADDED]     Mac: Missing menu icon.
[UPDATED]   Sketch source file for iOS app icon and Mac menu icon.
2013-01-27 01:02:41 -05:00
Maarten Billemont
ecd03ecf42 Update of iOS code for updated API of UbiquityStoreManager.
[UPDATED]   UbiquityStoreManager's new API uses cloudEnabled instead of iCloudEnabled.
2013-01-27 00:54:54 -05:00
Maarten Billemont
d5bffd86d6 Mac fixes and improvements to usability.
[FIXED]     Mac: Locking shouldn't unset the active user.
[IMPROVED]  Mac: Behavior of auto-completing site-name field improved.
[ADDED]     Mac: Alert when MP is incorrect when unlocking.
2013-01-26 22:12:34 -05:00
Maarten Billemont
b07298e203 Fixed migration of old store to new store + don't hold references to CoreData objects.
[FIXED]     Working migration of old store to new store.
[FIXED]     We shouldn't be holding references to CoreData objects anywhere.
            In that light, the user NSMenuItems have been fixed.
2013-01-25 01:05:31 -05:00
Maarten Billemont
4c19a29897 Mac support for user handling and iCloud improvements.
[MOVED]     Extract user migration out of iOS specific codebase.
[UPDATED]   iCloud persistence manager.
[ADDED]     Mac: Hotkey for signing the user out.
[IMPROVED]  Mac: Menu item handling and usability.
2013-01-17 00:37:20 -05:00
Maarten Billemont
32f870406c Mac UI fixes.
[FIXED]     Behavior of the Mac menu item and appearance of the password
            window.
[ADDED]     Disabling menu items while not usable and explaining
            disabled items with tooltips.
2012-11-01 10:55:11 -04:00
Maarten Billemont
05ab38b998 Facebook updates + Mac fixes.
[UPDATED]   Facebook integration bumped for iOS 6.
[FIXED]     Bringing Mac version back up to date.  Compiles again and
            runs with UI bugs.
[ADDED]     Mac: User selection.
2012-10-30 22:54:34 -04:00
Maarten Billemont
678545cc26 Make parent pom resolvable.
[FIXED]     Java: Make the parent POM resolvable for people that don't
            have the snapshot version of it.
2012-10-23 09:21:33 -04:00
Maarten Billemont
4c3e0f0c97 Site updates.
[ADDED]     Smart App Banner added to site.
[UPDATED]   Available-on-App-Store resource updated.
2012-10-09 09:58:44 +02:00
Maarten Billemont
a8752b5f28 Disable TestFlight's feedback dialog.
[REMOVED]   TestFlight's feedback dialog.  It's ugly and it doesn't
            allow log sending.
2012-09-23 17:38:05 +02:00
Maarten Billemont
f75f5c1b30 Signing profile bump. 2012-09-22 17:48:35 +02:00
Maarten Billemont
735a75df92 News file referenced by the new version. 2012-09-22 17:38:05 +02:00
Maarten Billemont
d8414aaab9 Fix the URL of the news page to point to the web. 2012-09-22 10:23:21 +02:00
Maarten Billemont
02a5d48ce4 Added a news view.
[ADDED]     A news view on the unlock screen.
2012-09-22 10:14:41 +02:00
Maarten Billemont
cdee54a0f7 TestFlight update to 1.1 2012-09-22 08:53:55 +02:00
Maarten Billemont
b1f0f70849 Localytics SDK update because of startup issue. 2012-09-21 19:42:18 +02:00
Maarten Billemont
850978cbe3 Fixed bug with scroll view in iOS5.
[FIXED]     On iOS5, the app crashed because gesture recognizers of a
            scrollview were being replaced.  Now properly adding the
            desired gesture recognizer to the scroll view preserving the
            existing gesture recognizers.
2012-09-21 16:45:57 +02:00
Maarten Billemont
e8c00296bd TestFligt identifier + Localytics crash.
[IMPROVED]  Use correct device identifier for TestFlight depending on
            whether we're in AdHoc mode or not.
[FIXED]     Crash when sending nil config values to Localytics.
2012-09-21 10:31:48 +02:00
Maarten Billemont
52b8033c37 Fixed issue with logs in feedback message.
[FIXED]     Including logs in the feedback message caused failure to
            parse attachments.
2012-09-20 21:37:58 +02:00
Maarten Billemont
6f2bc83806 Revert the renameID change to see if it causes model incompatibilties. 2012-09-20 21:19:44 +02:00
Maarten Billemont
2a48c9d272 Fixed some rare crashes.
[FIXED]     Crash for users with no name.
[FIXED]     Crash when copying an element with no content.
2012-09-20 21:16:34 +02:00
Maarten Billemont
27d0373a6e Add TestFlight back. 2012-09-19 23:52:23 +02:00
Maarten Billemont
96b50f7ef0 Not ready yet for ARMv7s.
[REVERTED]  Still too many of our dependant libs have no ARMv7s symbols.
2012-09-19 23:46:39 +02:00
Maarten Billemont
dc7ff5f668 Bump for ARMv7s Pearl libs. 2012-09-19 23:43:15 +02:00
Maarten Billemont
0c9c9737d9 Only show TestFlight feedback in Adhoc mode. 2012-09-19 23:34:17 +02:00
Maarten Billemont
8ef099d707 Signing configuration update. 2012-09-19 23:31:46 +02:00
Maarten Billemont
6da15306b0 Work-around for iOS 6 bug.
[FIXED]     iOS 6 SDK seems to crash on iOS 5 devices when doing
            scrollEnabled.
2012-09-19 23:29:21 +02:00
Maarten Billemont
699d0869fc ARMv7s
[UPDATED]   Project configuration update for ARMv7s support.
2012-09-19 22:11:16 +02:00
Maarten Billemont
83efa853fc Binary libraries only support armv7.
[FIXED]     Crashlytics only supports armv7 so force armv7 for now.
2012-09-13 00:48:45 +02:00
Maarten Billemont
75de4b443f iPhone 5 compatibility.
[ADDED]     Taller iPhone 5-size launch image.
[FIXED]     Missing PSC in MOC.
[IMPROVED]  Slower fade-in of unlock UI.
[FIXED]     Properly set enableHTTPS in Localytics.
2012-09-13 00:38:15 +02:00
Maarten Billemont
42c7fb446e Localytics project configuration update. 2012-09-12 16:07:36 +02:00
Maarten Billemont
bce6b96417 Tag screens in Localytics + email fix + psc fix
[FIXED]     Sending email with no recipient caused a crash.
[FIXED]     Duplicate persistence coordinator.
[UPDATED]   Crashlytics and Localytics SDKs.
[UPDATED]   Don't continue the Localytics session when device locked.
[UPDATED]   Put Localytics communication on HTTPS for confidentiality.
[ADDED]     Tagging screens in Localytics.
2012-09-12 16:02:02 +02:00
Maarten Billemont
6f82cf7f15 Fixed crashes related to over-released gesture recognizers.
[FIXED]     Memory warnings caused Master Password to crash due to
            gesture recognizers and an iOS 5 bug.
2012-09-07 23:55:12 +02:00
Maarten Billemont
fac419dd94 Fixes related to review feedback. 2012-09-02 21:16:16 +02:00
Maarten Billemont
c03d547ad8 Font improvements and copy-login fix.
[FIXED]     Login name copies content instead of login name.
[IMPROVED]  Font of password and login name improved for better
            differentiation between capital and lower-case letters.
2012-09-02 13:14:09 +02:00
Maarten Billemont
e2bf8cefa2 Migration of saved passwords.
[ADDED]     Migrate saved passwords when master password changes.
[IMPROVED]  UI improvements to apps.
2012-09-01 22:14:57 +02:00
Maarten Billemont
d75ec5c689 Added "Other Apps".
[REMOVED]   Cleaned up some check points that weren't really useful.
[ADDED]     Added a few new checkpoints with new functionality.
[ADDED]     An "other apps" page that introduces Gorillas and DeBlock.
[IMPROVED]  Help is now toggled with a drag handle instead of an action
            button.
2012-09-01 14:57:55 +02:00
Maarten Billemont
aa2d9eb202 Bump Pearl. 2012-08-31 16:30:05 +02:00
Maarten Billemont
ac52f38612 Disabled custom button title font because of odd iOS bug.
[FIXED]     Odd bug that causes imageViews to get oddly stretched.
2012-08-31 11:47:50 +02:00
Maarten Billemont
332808027f Make user name entry required.
[FIXED]     Prevent the ability to create a new user without user name.
2012-08-30 22:47:33 +02:00
Maarten Billemont
cd64bff5ef Layout Core Data model graph. 2012-08-30 22:30:42 +02:00
Maarten Billemont
7813ddee38 Fade unlock VC + search bar responder fix.
[ADDED]     Fade effect to unlock view.
[UPDATED]   Signing profiles.
[FIXED]     A rare bug that caused the search bar to remain first responder without making it take input or dismissable (hopefully fixed, at least).
2012-08-28 00:13:46 +02:00
Maarten Billemont
af744235bc Status bar issue.
[FIXED]     Status bar issue.
[FIXED]     Review dialog link and buttons.
2012-08-27 00:14:33 +02:00
Maarten Billemont
ca9cbc9fd1 Follow on social networks.
[UPDATED]   Migrated from MFMailComposeViewController to PearlEMail.
[ADDED]     Social network "follow" button.
2012-08-26 17:40:32 +02:00
Maarten Billemont
5e7b6ed60e Sharing on Facebook, Twitter and Google+
[FIXED]     Font of navbar.
[FIXED]     A few compile fixes.
[IMPROVED]  Made properties nonatomic.
[ADDED]     Support for facebook, twitter and google+ sharing.
2012-08-25 12:55:07 +02:00
Maarten Billemont
b9ccee398e Fixed a few crashes.
[UPDATED]   A nil type is never OK.  Crash early if it is so.
[UPDATED]   Set crashlytics identifiers using its userIdentifier and userName property for good metadata.
[FIXED]     Make sure the MOC has a PSC with stores when returning it.
[FIXED]     Don't reset the store for just any open error! Only if it's actually incompatible.
[IMPROVED]  Remove timestamps from Crashlytics and TestFlight logs, they already provide them.
[FIXED]     Avoid crashes in some odd cases where there's no type set.
2012-08-24 10:12:15 +02:00
Maarten Billemont
7921734740 Modernize ObjC syntax.
[IMPROVED]  Migrate to modern ObjC syntax for type boxing.
2012-08-19 20:02:23 +02:00
Maarten Billemont
9d883b6ff7 UserName -> LoginName 2012-08-19 19:54:06 +02:00
Maarten Billemont
75ef15bb4d 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.
2012-08-19 09:34:49 +02:00
Maarten Billemont
479d357bd1 Fixed importing with a different key and entity access after MOC changes.
[FIXED]   Importing stored content when not logged in with the same key.
[FIXED]   Holding entities is a bad idea when MOCs can change.  Holding ObjectIDs instead now.
2012-08-18 15:37:24 +02:00
Maarten Billemont
d429044f64 Remove debugging "Save" button + fix keybaord appearance.
[FIXED]     Keyboard didn't appear when app is reactivated.
[REMOVED]   "Save" option in user menu on lock screen was for debugging.
2012-08-05 11:40:50 +02:00
Maarten Billemont
b38e8d9ea6 Fix appearance of the Guide on start-up.
[FIXED]     When the unlock VC shows, the guide's appearance is aborted.
2012-08-05 11:18:58 +02:00
1318 changed files with 43481 additions and 24066 deletions

16
.gitignore vendored
View File

@@ -2,6 +2,7 @@
.DS_Store
# IntelliJ
/MasterPassword/Java/.idea
/.idea/*
!/.idea/encodings.xml
!/.idea/inspectionProfiles
@@ -12,13 +13,8 @@
/*.iws
# Xcode IDE
/*.xcodeproj/*
!/*.xcodeproj/*.pbxproj
!/*.xcodeproj/xcshareddata
!/*.xcodeproj/xcshareddata/*
!/*.xcodeproj/project.xcworkspace
!/*.xcodeproj/project.xcworkspace/*
/*.xcodeproj/project.xcworkspace/xcuserdata
xcuserdata/
/DerivedData/
# Media
Press/Background.png
@@ -31,3 +27,9 @@ Press/MasterPassword_PressKit/MasterPassword_pressrelease_*.pdf
# Java
MasterPassword/Java/**/target
# C
MasterPassword/C/*.o
MasterPassword/C/mpw
MasterPassword/C/lib/*/*
!MasterPassword/C/lib/*/.source

14
.gitmodules vendored
View File

@@ -3,10 +3,10 @@
url = git://github.com/Lyndir/Pearl.git
[submodule "External/InAppSettingsKit"]
path = External/InAppSettingsKit
url = git://github.com/futuretap/InAppSettingsKit.git
[submodule "External/iCloudStoreManager"]
path = External/iCloudStoreManager
url = git://github.com/lhunath/iCloudStoreManager.git
[submodule "External/FontReplacer"]
path = External/FontReplacer
url = git://github.com/0xced/FontReplacer.git
url = git://github.com/lhunath/InAppSettingsKit.git
[submodule "External/UbiquityStoreManager"]
path = External/UbiquityStoreManager
url = git://github.com/lhunath/UbiquityStoreManager.git
[submodule "External/RHStatusItemView"]
path = External/RHStatusItemView
url = git://github.com/lhunath/RHStatusItemView.git

View File

@@ -3,9 +3,15 @@
<option name="myName" value="Project Default" />
<option name="myLocal" value="false" />
<inspection_tool class="FunctionImplicitDeclarationInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ImplicitIntegerAndEnumConversion" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="LossyEncoding" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="MethodIsLaterInTheScope" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="OCNotLocalizedStringInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="OCUnusedMacroInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="OCUnusedMethodInspection" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="SignednessMismatch" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnavailableInDeploymentTarget" enabled="true" level="INFO" enabled_by_default="true" />
<inspection_tool class="UnusedLocalVariable" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnusedParameter" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

7
.travis.yml Normal file
View File

@@ -0,0 +1,7 @@
language: objective-c
xcode_workspace: MasterPassword.xcworkspace
xcode_scheme: MasterPassword iOS (Development)
xcode_sdk: iphonesimulator
git:
submodules: false
before_install: ./Scripts/updateDependencies

View File

@@ -1 +0,0 @@
../../../run

View File

@@ -1,15 +0,0 @@
#!/usr/bin/ruby
#
# WARNING: DO NOT MODIFY THIS FILE.
#
# Crashlytics
# Crashlytics Version: 1.0.0.1
#
# Copyright Crashlytics, Inc. 2012. All rights reserved.
#
require 'pathname'
path = Pathname.new(__FILE__).parent
`#{path}/../../../run`

Binary file not shown.

Submodule External/FontReplacer deleted from 4e3dea0870

Binary file not shown.

View File

@@ -2,17 +2,17 @@
// Crashlytics.h
// Crashlytics
//
// Copyright 2012 Crashlytics, Inc. All rights reserved.
// Copyright 2013 Crashlytics, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
*
* The CLS_LOG macro provides as easy way to gather more information in your log messages that are
* sent with your crash data. CLS_LOG prepends your custom log message with the function name and
* line number where the macro was used. If your app was built with the DEBUG preprocessor macro
* defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog.
* The CLS_LOG macro provides as easy way to gather more information in your log messages that are
* sent with your crash data. CLS_LOG prepends your custom log message with the function name and
* line number where the macro was used. If your app was built with the DEBUG preprocessor macro
* defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog.
* If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only.
*
* Example output:
@@ -26,41 +26,30 @@
*
**/
#ifdef DEBUG
#define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif
/**
*
*
* Add logging that will be sent with your crash data. This logging will not show up in the system.log
* and will only be visible in your Crashlytics dashboard.
*
**/
void CLSLog(NSString *format, ...);
OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
/**
*
* Add logging that will be sent with your crash data. This logging will show up in the system.log
* and your Crashlytics dashboard. It is not reccomended for Release builds.
* and your Crashlytics dashboard. It is not recommended for Release builds.
*
**/
void CLSNSLog(NSString *format, ...);
OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
@protocol CrashlyticsDelegate;
@interface Crashlytics : NSObject {
@private
NSString *_apiKey;
NSString *_dataDirectory;
NSString *_bundleIdentifier;
BOOL _installed;
NSMutableDictionary *_customAttributes;
id _user;
NSInteger _sendButtonIndex;
NSInteger _alwaysSendButtonIndex;
NSObject <CrashlyticsDelegate> *_delegate;
}
@interface Crashlytics : NSObject
@property (nonatomic, readonly, copy) NSString *apiKey;
@property (nonatomic, readonly, copy) NSString *version;
@@ -73,7 +62,7 @@ void CLSNSLog(NSString *format, ...);
* The recommended way to install Crashlytics into your application is to place a call
* to +startWithAPIKey: in your -application:didFinishLaunchingWithOptions: method.
*
* This delay defaults to 1 second in order to generally give the application time to
* This delay defaults to 1 second in order to generally give the application time to
* fully finish launching.
*
**/
@@ -105,21 +94,21 @@ void CLSNSLog(NSString *format, ...);
/**
*
* Many of our customers have requested the ability to tie crashes to specific end-users of their
* application in order to facilitate responses to support requests or permit the ability to reach
* out for more information. We allow you to specify up to three separate values for display within
* Many of our customers have requested the ability to tie crashes to specific end-users of their
* application in order to facilitate responses to support requests or permit the ability to reach
* out for more information. We allow you to specify up to three separate values for display within
* the Crashlytics UI - but please be mindful of your end-user's privacy.
*
* We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record
* in your system. This could be a database id, hash, or other value that is meaningless to a
* We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record
* in your system. This could be a database id, hash, or other value that is meaningless to a
* third-party observer but can be indexed and queried by you.
*
* Optionally, you may also specify the end-user's name or username, as well as email address if you
* Optionally, you may also specify the end-user's name or username, as well as email address if you
* do not have a system that works well with obscured identifiers.
*
* Pursuant to our EULA, this data is transferred securely throughout our system and we will not
* disseminate end-user data unless required to by law. That said, if you choose to provide end-user
* contact information, we strongly recommend that you disclose this in your application's privacy
* Pursuant to our EULA, this data is transferred securely throughout our system and we will not
* disseminate end-user data unless required to by law. That said, if you choose to provide end-user
* contact information, we strongly recommend that you disclose this in your application's privacy
* policy. Data privacy is of our utmost concern.
*
**/
@@ -148,10 +137,55 @@ void CLSNSLog(NSString *format, ...);
@end
/**
* The CLSCrashReport protocol exposes methods that you can call on crash report objects passed
* to delegate methods. If you want these values or the entire object to stay in memory retain
* them or copy them.
**/
@protocol CLSCrashReport <NSObject>
@required
/**
* Returns the session identifier for the crash report.
**/
@property (nonatomic, readonly) NSString *identifier;
/**
* Returns the custom key value data for the crash report.
**/
@property (nonatomic, readonly) NSDictionary *customKeys;
/**
* Returns the CFBundleVersion of the application that crashed.
**/
@property (nonatomic, readonly) NSString *bundleVersion;
/**
* Returns the CFBundleShortVersionString of the application that crashed.
**/
@property (nonatomic, readonly) NSString *bundleShortVersionString;
/**
* Returns the date that the application crashed at.
**/
@property (nonatomic, readonly) NSDate *crashedOnDate;
/**
* Returns the os version that the application crashed on.
**/
@property (nonatomic, readonly) NSString *OSVersion;
/**
* Returns the os build version that the application crashed on.
**/
@property (nonatomic, readonly) NSString *OSBuildVersion;
@end
/**
*
* The CrashlyticsDelegate protocol provides a mechanism for your application to take
* action on events that occur in the Crashlytics crash reporting system. You can make
* action on events that occur in the Crashlytics crash reporting system. You can make
* use of these calls by assigning an object to the Crashlytics' delegate property directly,
* or through the convenience startWithAPIKey:delegate:... methods.
*
@@ -161,7 +195,7 @@ void CLSNSLog(NSString *format, ...);
/**
*
* Called once a Crashlytics instance has determined that the last execution of the
* Called once a Crashlytics instance has determined that the last execution of the
* application ended in a crash. This is called some time after the crash reporting
* process has begun. If you have specified a delay in one of the
* startWithAPIKey:... calls, this will take at least that long to be invoked.
@@ -169,4 +203,15 @@ void CLSNSLog(NSString *format, ...);
**/
- (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics;
/**
*
* Just like crashlyticsDidDetectCrashDuringPreviousExecution this delegate method is
* called once a Crashlytics instance has determined that the last execution of the
* application ended in a crash. A CLSCrashReport is passed back that contains data about
* the last crash report that was generated. See the CLSCrashReport protocol for method details.
* This method is called after crashlyticsDidDetectCrashDuringPreviousExecution.
*
**/
- (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id <CLSCrashReport>)crash;
@end

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>Crashlytics</string>
<key>CFBundleIdentifier</key>
<string>com.crashlytics.sdk.mac</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Crashlytics</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.1.2</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>macosx</string>
</array>
<key>CFBundleVersion</key>
<string>9</string>
<key>DTPlatformName</key>
<string>macosx</string>
<key>MinimumOSVersion</key>
<string>10.6</string>
</dict>
</plist>

BIN
External/Mac/Crashlytics.framework/run vendored Executable file

Binary file not shown.

2
External/Pearl vendored

1
External/RHStatusItemView vendored Submodule

1
External/Reveal.framework/Headers vendored Symbolic link
View File

@@ -0,0 +1 @@
Versions/Current/Headers

1
External/Reveal.framework/Reveal vendored Symbolic link
View File

@@ -0,0 +1 @@
Versions/Current/Reveal

View File

@@ -0,0 +1,17 @@
//
// Copyright (c) 2013 Itty Bitty Apps. All rights reserved.
#import <Foundation/Foundation.h>
extern NSString * const IBARevealLoaderRequestStartNotification;
extern NSString * const IBARevealLoaderRequestStopNotification;
extern NSString * const IBARevealLoaderSetOptionsNotification;
extern NSString * const IBARevealLoaderOptionsLogLevelMaskKey;
@interface IBARevealLoader : NSObject
+ (void)startServer;
+ (void)stopServer;
@end

View File

@@ -0,0 +1,57 @@
// Copyright (c) 2013 Itty Bitty Apps Pty Ltd. All rights reserved.
//
#import <Foundation/Foundation.h>
CF_EXTERN_C_BEGIN
/*!
\brief The Reveal Log level bit flags.
\discussion These flags are additive. i.e. you should bitwise OR them together.
\seealso IBARevealLoggerSetLevelMask
\seealso IBARevealLoggerGetLevelMask
Example:
// Enable Error, Warning and Info logger levels.
IBARevealLoggerSetLevelMask(IBARevealLogLevelError|IBARevealLogLevelWarn|IBARevealLogLevelInfo);
*/
typedef NS_OPTIONS(int32_t, IBARevealLogLevel)
{
IBARevealLogLevelNone = 0,
IBARevealLogLevelDebug = (1 << 0),
IBARevealLogLevelInfo = (1 << 1),
IBARevealLogLevelWarn = (1 << 2),
IBARevealLogLevelError = (1 << 3)
};
/*!
\brief Set the Reveal logger level mask.
\param mask A bit mask which is a combination of the IBARevealLogLevel enum options.
\discussion If you do not wish to see log messages from Reveal you should call this function with an appropriate level mask as early in your application's lifecycle as possible. For example in your application's main() function.
Example:
// Enable Error, Warning and Info logger levels.
IBARevealLoggerSetLevelMask(IBARevealLogLevelError|IBARevealLogLevelWarn|IBARevealLogLevelInfo);
*/
CF_EXPORT void IBARevealLoggerSetLevelMask(int32_t mask);
/*!
\brief Get the current Reveal logger level mask.
\return A bit mask representing the levels at which Reveal is currently logging.
\discussion The default Reveal Logger level mask is IBARevealLogLevelError|IBARevealLogLevelWarn|IBARevealLogLevelInfo.
Example:
// Turn off the Info log level.
IBARevealLoggerSetLevelMask(IBARevealLoggerGetLevelMask() & ~IBARevealLogLevelInfo);
*/
CF_EXPORT int32_t IBARevealLoggerGetLevelMask(void);
CF_EXTERN_C_END

View File

@@ -0,0 +1,5 @@
// Copyright (c) 2013 Itty Bitty Apps Pty Ltd. All rights reserved.
//
#import "IBARevealLogger.h"
#import "IBARevealLoader.h"

Binary file not shown.

View File

@@ -0,0 +1 @@
A

View File

@@ -0,0 +1 @@
Versions/Current/Crashlytics

View File

@@ -0,0 +1 @@
Versions/Current/Headers

View File

@@ -0,0 +1 @@
Versions/Current/Resources

Binary file not shown.

View File

@@ -0,0 +1,217 @@
//
// Crashlytics.h
// Crashlytics
//
// Copyright 2013 Crashlytics, Inc. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
*
* The CLS_LOG macro provides as easy way to gather more information in your log messages that are
* sent with your crash data. CLS_LOG prepends your custom log message with the function name and
* line number where the macro was used. If your app was built with the DEBUG preprocessor macro
* defined CLS_LOG uses the CLSNSLog function which forwards your log message to NSLog and CLSLog.
* If the DEBUG preprocessor macro is not defined CLS_LOG uses CLSLog only.
*
* Example output:
* -[AppDelegate login:] line 134 $ login start
*
* If you would like to change this macro, create a new header file, unset our define and then define
* your own version. Make sure this new header file is imported after the Crashlytics header file.
*
* #undef CLS_LOG
* #define CLS_LOG(__FORMAT__, ...) CLSNSLog...
*
**/
#ifdef DEBUG
#define CLS_LOG(__FORMAT__, ...) CLSNSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define CLS_LOG(__FORMAT__, ...) CLSLog((@"%s line %d $ " __FORMAT__), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif
/**
*
* Add logging that will be sent with your crash data. This logging will not show up in the system.log
* and will only be visible in your Crashlytics dashboard.
*
**/
OBJC_EXTERN void CLSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
/**
*
* Add logging that will be sent with your crash data. This logging will show up in the system.log
* and your Crashlytics dashboard. It is not recommended for Release builds.
*
**/
OBJC_EXTERN void CLSNSLog(NSString *format, ...) NS_FORMAT_FUNCTION(1,2);
@protocol CrashlyticsDelegate;
@interface Crashlytics : NSObject
@property (nonatomic, readonly, copy) NSString *apiKey;
@property (nonatomic, readonly, copy) NSString *version;
@property (nonatomic, assign) BOOL debugMode;
@property (nonatomic, assign) NSObject <CrashlyticsDelegate> *delegate;
/**
*
* The recommended way to install Crashlytics into your application is to place a call
* to +startWithAPIKey: in your -application:didFinishLaunchingWithOptions: method.
*
* This delay defaults to 1 second in order to generally give the application time to
* fully finish launching.
*
**/
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey;
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey afterDelay:(NSTimeInterval)delay;
/**
*
* If you need the functionality provided by the CrashlyticsDelegate protocol, you can use
* these convenience methods to activate the framework and set the delegate in one call.
*
**/
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject <CrashlyticsDelegate> *)delegate;
+ (Crashlytics *)startWithAPIKey:(NSString *)apiKey delegate:(NSObject <CrashlyticsDelegate> *)delegate afterDelay:(NSTimeInterval)delay;
/**
*
* Access the singleton Crashlytics instance.
*
**/
+ (Crashlytics *)sharedInstance;
/**
*
* The easiest way to cause a crash - great for testing!
*
**/
- (void)crash;
/**
*
* Many of our customers have requested the ability to tie crashes to specific end-users of their
* application in order to facilitate responses to support requests or permit the ability to reach
* out for more information. We allow you to specify up to three separate values for display within
* the Crashlytics UI - but please be mindful of your end-user's privacy.
*
* We recommend specifying a user identifier - an arbitrary string that ties an end-user to a record
* in your system. This could be a database id, hash, or other value that is meaningless to a
* third-party observer but can be indexed and queried by you.
*
* Optionally, you may also specify the end-user's name or username, as well as email address if you
* do not have a system that works well with obscured identifiers.
*
* Pursuant to our EULA, this data is transferred securely throughout our system and we will not
* disseminate end-user data unless required to by law. That said, if you choose to provide end-user
* contact information, we strongly recommend that you disclose this in your application's privacy
* policy. Data privacy is of our utmost concern.
*
**/
- (void)setUserIdentifier:(NSString *)identifier;
- (void)setUserName:(NSString *)name;
- (void)setUserEmail:(NSString *)email;
+ (void)setUserIdentifier:(NSString *)identifier;
+ (void)setUserName:(NSString *)name;
+ (void)setUserEmail:(NSString *)email;
/**
*
* Set a value for a key to be associated with your crash data.
*
**/
- (void)setObjectValue:(id)value forKey:(NSString *)key;
- (void)setIntValue:(int)value forKey:(NSString *)key;
- (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
- (void)setFloatValue:(float)value forKey:(NSString *)key;
+ (void)setObjectValue:(id)value forKey:(NSString *)key;
+ (void)setIntValue:(int)value forKey:(NSString *)key;
+ (void)setBoolValue:(BOOL)value forKey:(NSString *)key;
+ (void)setFloatValue:(float)value forKey:(NSString *)key;
@end
/**
* The CLSCrashReport protocol exposes methods that you can call on crash report objects passed
* to delegate methods. If you want these values or the entire object to stay in memory retain
* them or copy them.
**/
@protocol CLSCrashReport <NSObject>
@required
/**
* Returns the session identifier for the crash report.
**/
@property (nonatomic, readonly) NSString *identifier;
/**
* Returns the custom key value data for the crash report.
**/
@property (nonatomic, readonly) NSDictionary *customKeys;
/**
* Returns the CFBundleVersion of the application that crashed.
**/
@property (nonatomic, readonly) NSString *bundleVersion;
/**
* Returns the CFBundleShortVersionString of the application that crashed.
**/
@property (nonatomic, readonly) NSString *bundleShortVersionString;
/**
* Returns the date that the application crashed at.
**/
@property (nonatomic, readonly) NSDate *crashedOnDate;
/**
* Returns the os version that the application crashed on.
**/
@property (nonatomic, readonly) NSString *OSVersion;
/**
* Returns the os build version that the application crashed on.
**/
@property (nonatomic, readonly) NSString *OSBuildVersion;
@end
/**
*
* The CrashlyticsDelegate protocol provides a mechanism for your application to take
* action on events that occur in the Crashlytics crash reporting system. You can make
* use of these calls by assigning an object to the Crashlytics' delegate property directly,
* or through the convenience startWithAPIKey:delegate:... methods.
*
**/
@protocol CrashlyticsDelegate <NSObject>
@optional
/**
*
* Called once a Crashlytics instance has determined that the last execution of the
* application ended in a crash. This is called some time after the crash reporting
* process has begun. If you have specified a delay in one of the
* startWithAPIKey:... calls, this will take at least that long to be invoked.
*
**/
- (void)crashlyticsDidDetectCrashDuringPreviousExecution:(Crashlytics *)crashlytics;
/**
*
* Just like crashlyticsDidDetectCrashDuringPreviousExecution this delegate method is
* called once a Crashlytics instance has determined that the last execution of the
* application ended in a crash. A CLSCrashReport is passed back that contains data about
* the last crash report that was generated. See the CLSCrashReport protocol for method details.
* This method is called after crashlyticsDidDetectCrashDuringPreviousExecution.
*
**/
- (void)crashlytics:(Crashlytics *)crashlytics didDetectCrashDuringPreviousExecution:(id <CLSCrashReport>)crash;
@end

View File

@@ -2,8 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>11E53</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
@@ -17,38 +15,16 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.1.5</string>
<key>CFBundleSignature</key>
<string>????</string>
<string>2.2.1</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>0101.05.00</string>
<key>CrashlyticsAPIKey</key>
<string>0d10c90776f5ef5acd01ddbeaca9a6cba4814560</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>8H7</string>
<string>35</string>
<key>DTPlatformName</key>
<string>iphoneos</string>
<key>DTPlatformVersion</key>
<string>4.3</string>
<key>DTSDKBuild</key>
<string>8H7</string>
<key>DTSDKName</key>
<string>iphoneos4.3</string>
<key>DTXcode</key>
<string>0410</string>
<key>DTXcodeBuild</key>
<string>4B110</string>
<key>MinimumOSVersion</key>
<string>3.1</string>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
</array>
<string>4.0</string>
</dict>
</plist>

View File

@@ -0,0 +1 @@
A

BIN
External/iOS/Crashlytics.framework/run vendored Executable file

Binary file not shown.

BIN
External/iOS/Crashlytics.framework/submit vendored Executable file

Binary file not shown.

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Key.development</key>
<string>e6238ceba8ec92832e77b1b-9ccd60bc-c39b-11e0-06e4-007f58cb3154</string>
<key>Key.distribution</key>
<string></string>
</dict>
</plist>

View File

@@ -1,57 +0,0 @@
//
// LocalyticsDatabase.h
// LocalyticsDemo
//
// Created by jkaufman on 5/26/11.
// Copyright 2011 Localytics. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#define MAX_DATABASE_SIZE 500000 // The maximum allowed disk size of the primary database file at open, in bytes
#define VACUUM_THRESHOLD 0.8 // The database is vacuumed after its size exceeds this proportion of the maximum.
@interface LocalyticsDatabase : NSObject {
sqlite3 *_databaseConnection;
}
+ (LocalyticsDatabase *)sharedLocalyticsDatabase;
- (NSUInteger)databaseSize;
- (int)eventCount;
- (NSTimeInterval)createdTimestamp;
- (BOOL)beginTransaction:(NSString *)name;
- (BOOL)releaseTransaction:(NSString *)name;
- (BOOL)rollbackTransaction:(NSString *)name;
- (BOOL)incrementLastUploadNumber:(int *)uploadNumber;
- (BOOL)incrementLastSessionNumber:(int *)sessionNumber;
- (BOOL)addEventWithBlobString:(NSString *)blob;
- (BOOL)addCloseEventWithBlobString:(NSString *)blob;
- (BOOL)addFlowEventWithBlobString:(NSString *)blob;
- (BOOL)removeLastCloseAndFlowEvents;
- (BOOL)addHeaderWithSequenceNumber:(int)number blobString:(NSString *)blob rowId:(sqlite3_int64 *)insertedRowId;
- (int)unstagedEventCount;
- (BOOL)stageEventsForUpload:(sqlite3_int64)headerId;
- (BOOL)updateAppKey:(NSString *)appKey;
- (NSString *)uploadBlobString;
- (BOOL)deleteUploadedData;
- (BOOL)resetAnalyticsData;
- (BOOL)vacuumIfRequired;
- (NSTimeInterval)lastSessionStartTimestamp;
- (BOOL)setLastsessionStartTimestamp:(NSTimeInterval)timestamp;
- (BOOL)isOptedOut;
- (BOOL)setOptedOut:(BOOL)optOut;
- (NSString *)installId;
- (NSString *)appKey; // Most recent app key-- may not be that used to open the session.
- (NSString *)customDimension:(int)dimension;
- (BOOL)setCustomDimension:(int)dimension value:(NSString *)value;
@end

View File

@@ -1,743 +0,0 @@
//
// LocalyticsDatabase.m
// LocalyticsDemo
//
// Created by jkaufman on 5/26/11.
// Copyright 2011 Localytics. All rights reserved.
//
#import "LocalyticsDatabase.h"
#define LOCALYTICS_DIR @".localytics" // Name for the directory in which Localytics database is stored
#define LOCALYTICS_DB @"localytics" // File name for the database (without extension)
#define BUSY_TIMEOUT 30 // Maximum time SQlite will busy-wait for the database to unlock before returning SQLITE_BUSY
@interface LocalyticsDatabase ()
- (int)schemaVersion;
- (void)createSchema;
- (void)upgradeToSchemaV2;
- (void)upgradeToSchemaV3;
- (void)moveDbToCaches;
- (NSString *)randomUUID;
@end
@implementation LocalyticsDatabase
// The singleton database object.
static LocalyticsDatabase *_sharedLocalyticsDatabase = nil;
+ (NSString *)localyticsDirectoryPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
return [[paths objectAtIndex:0] stringByAppendingPathComponent:LOCALYTICS_DIR];
}
+ (NSString *)localyticsDatabasePath {
NSString *path = [[LocalyticsDatabase localyticsDirectoryPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.sqlite", LOCALYTICS_DB]];
return path;
}
#pragma mark Singleton Class
+ (LocalyticsDatabase *)sharedLocalyticsDatabase {
@synchronized(self) {
if (_sharedLocalyticsDatabase == nil) {
_sharedLocalyticsDatabase = [[self alloc] init];
}
}
return _sharedLocalyticsDatabase;
}
- (LocalyticsDatabase *)init {
if((self = [super init])) {
// Mover any data that a previous library may have left in the documents directory
[self moveDbToCaches];
// Create directory structure for Localytics.
NSString *directoryPath = [LocalyticsDatabase localyticsDirectoryPath];
if (![[NSFileManager defaultManager] fileExistsAtPath:directoryPath]) {
[[NSFileManager defaultManager] createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:nil];
}
// Attempt to open database. It will be created if it does not exist, already.
NSString *dbPath = [LocalyticsDatabase localyticsDatabasePath];
int code = sqlite3_open([dbPath UTF8String], &_databaseConnection);
// If we were unable to open the database, it is likely corrupted. Clobber it and move on.
if (code != SQLITE_OK) {
[[NSFileManager defaultManager] removeItemAtPath:dbPath error:nil];
code = sqlite3_open([dbPath UTF8String], &_databaseConnection);
}
// Check db connection, creating schema if necessary.
if (code == SQLITE_OK) {
sqlite3_busy_timeout(_databaseConnection, BUSY_TIMEOUT); // Defaults to 0, otherwise.
if ([self schemaVersion] == 0) {
[self createSchema];
}
}
// Perform any Migrations if necessary
if ([self schemaVersion] < 2) {
[self upgradeToSchemaV2];
}
if ([self schemaVersion] < 3) {
[self upgradeToSchemaV3];
}
}
return self;
}
#pragma mark - Database
- (BOOL)beginTransaction:(NSString *)name {
const char *sql = [[NSString stringWithFormat:@"SAVEPOINT %@", name] cStringUsingEncoding:NSUTF8StringEncoding];
int code = sqlite3_exec(_databaseConnection, sql, NULL, NULL, NULL);
return code == SQLITE_OK;
}
- (BOOL)releaseTransaction:(NSString *)name {
const char *sql = [[NSString stringWithFormat:@"RELEASE SAVEPOINT %@", name] cStringUsingEncoding:NSUTF8StringEncoding];
int code = sqlite3_exec(_databaseConnection, sql, NULL, NULL, NULL);
return code == SQLITE_OK;
}
- (BOOL)rollbackTransaction:(NSString *)name {
const char *sql = [[NSString stringWithFormat:@"ROLLBACK SAVEPOINT %@", name] cStringUsingEncoding:NSUTF8StringEncoding];
int code = sqlite3_exec(_databaseConnection, sql, NULL, NULL, NULL);
return code == SQLITE_OK;
}
- (int)schemaVersion {
int version = 0;
const char *sql = "SELECT MAX(schema_version) FROM localytics_info";
sqlite3_stmt *selectSchemaVersion;
if(sqlite3_prepare_v2(_databaseConnection, sql, -1, &selectSchemaVersion, NULL) == SQLITE_OK) {
if(sqlite3_step(selectSchemaVersion) == SQLITE_ROW) {
version = sqlite3_column_int(selectSchemaVersion, 0);
}
}
sqlite3_finalize(selectSchemaVersion);
return version;
}
- (NSString *)installId {
NSString *installId = nil;
sqlite3_stmt *selectInstallId;
sqlite3_prepare_v2(_databaseConnection, "SELECT install_id FROM localytics_info", -1, &selectInstallId, NULL);
int code = sqlite3_step(selectInstallId);
if (code == SQLITE_ROW && sqlite3_column_text(selectInstallId, 0)) {
installId = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectInstallId, 0)];
}
sqlite3_finalize(selectInstallId);
return installId;
}
- (NSString *)appKey {
NSString *appKey = nil;
sqlite3_stmt *selectAppKey;
sqlite3_prepare_v2(_databaseConnection, "SELECT app_key FROM localytics_info", -1, &selectAppKey, NULL);
int code = sqlite3_step(selectAppKey);
if (code == SQLITE_ROW && sqlite3_column_text(selectAppKey, 0)) {
appKey = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectAppKey, 0)];
}
sqlite3_finalize(selectAppKey);
return appKey;
}
// Due to the new iOS storage guidelines it is necessary to move the database out of the documents directory
// and into the /library/caches directory
- (void)moveDbToCaches {
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *localyticsDocumentsDirectory = [[documentPaths objectAtIndex:0] stringByAppendingPathComponent:LOCALYTICS_DIR];
NSArray *cachesPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *localyticsCachesDirectory = [[cachesPaths objectAtIndex:0] stringByAppendingPathComponent:LOCALYTICS_DIR];
// If the old directory doesn't exist, there is nothing else to do here
if([[NSFileManager defaultManager] fileExistsAtPath:localyticsDocumentsDirectory] == NO)
{
return;
}
// Try to move the directory
if(NO == [[NSFileManager defaultManager] moveItemAtPath:localyticsDocumentsDirectory
toPath:localyticsCachesDirectory
error:nil])
{
// If the move failed try and, delete the old directory
[ [NSFileManager defaultManager] removeItemAtPath:localyticsDocumentsDirectory error:nil];
}
}
- (void)createSchema {
int code = SQLITE_OK;
// Execute schema creation within a single transaction.
code = sqlite3_exec(_databaseConnection, "BEGIN", NULL, NULL, NULL);
if (code == SQLITE_OK) {
code = sqlite3_exec(_databaseConnection,
"CREATE TABLE upload_headers ("
"sequence_number INTEGER PRIMARY KEY, "
"blob_string TEXT)",
NULL, NULL, NULL);
}
if (code == SQLITE_OK) {
code = sqlite3_exec(_databaseConnection,
"CREATE TABLE events ("
"event_id INTEGER PRIMARY KEY AUTOINCREMENT, " // In case foreign key constraints are reintroduced.
"upload_header INTEGER, "
"blob_string TEXT NOT NULL)",
NULL, NULL, NULL);
}
if (code == SQLITE_OK) {
code = sqlite3_exec(_databaseConnection,
"CREATE TABLE localytics_info ("
"schema_version INTEGER PRIMARY KEY, "
"last_upload_number INTEGER, "
"last_session_number INTEGER, "
"opt_out BOOLEAN, "
"last_close_event INTEGER, "
"last_flow_event INTEGER, "
"last_session_start REAL, "
"app_key CHAR(64), "
"custom_d0 CHAR(64), "
"custom_d1 CHAR(64), "
"custom_d2 CHAR(64), "
"custom_d3 CHAR(64) "
")",
NULL, NULL, NULL);
}
if (code == SQLITE_OK) {
code = sqlite3_exec(_databaseConnection,
"INSERT INTO localytics_info (schema_version, last_upload_number, last_session_number, opt_out) "
"VALUES (3, 0, 0, 0)", NULL, NULL, NULL);
}
// Commit transaction.
if (code == SQLITE_OK || code == SQLITE_DONE) {
sqlite3_exec(_databaseConnection, "COMMIT", NULL, NULL, NULL);
} else {
sqlite3_exec(_databaseConnection, "ROLLBACK", NULL, NULL, NULL);
}
}
// V2 adds a unique identifier for each installation
// This identifier has been moved to user preferences so the database an live in the caches directory
// Also adds storage for custom dimensions
- (void)upgradeToSchemaV2 {
int code = SQLITE_OK;
code = sqlite3_exec(_databaseConnection, "BEGIN", NULL, NULL, NULL);
if (code == SQLITE_OK) {
code = sqlite3_exec(_databaseConnection,
"ALTER TABLE localytics_info ADD install_id CHAR(40)",
NULL, NULL, NULL);
}
if (code == SQLITE_OK) {
code = sqlite3_exec(_databaseConnection,
"ALTER TABLE localytics_info ADD custom_d0 CHAR(64)",
NULL, NULL, NULL);
}
if (code == SQLITE_OK) {
code = sqlite3_exec(_databaseConnection,
"ALTER TABLE localytics_info ADD custom_d1 CHAR(64)",
NULL, NULL, NULL);
}
if (code == SQLITE_OK) {
code = sqlite3_exec(_databaseConnection,
"ALTER TABLE localytics_info ADD custom_d2 CHAR(64)",
NULL, NULL, NULL);
}
if (code == SQLITE_OK) {
sqlite3_exec(_databaseConnection,
"ALTER TABLE localytics_info ADD custom_d3 CHAR(64)",
NULL, NULL, NULL);
}
// Attempt to set schema version and install_id regardless of the result code following the ALTER statements above.
// This is necessary because a previous version of the library performed the migration without setting these values.
// The transaction will succeed even if the individual statements fail with errors (eg. "duplicate column name").
sqlite3_stmt *updateLocalyticsInfo;
sqlite3_prepare_v2(_databaseConnection, "UPDATE localytics_info set install_id = ?, schema_version = 2 ", -1, &updateLocalyticsInfo, NULL);
sqlite3_bind_text (updateLocalyticsInfo, 1, [[self randomUUID] UTF8String], -1, SQLITE_TRANSIENT);
code = sqlite3_step(updateLocalyticsInfo);
sqlite3_finalize(updateLocalyticsInfo);
// Commit transaction.
if (code == SQLITE_OK || code == SQLITE_DONE) {
sqlite3_exec(_databaseConnection, "COMMIT", NULL, NULL, NULL);
} else {
sqlite3_exec(_databaseConnection, "ROLLBACK", NULL, NULL, NULL);
}
}
// V3 adds a field for the last app key and patches a V2 migration issue.
- (void)upgradeToSchemaV3 {
sqlite3_exec(_databaseConnection,
"ALTER TABLE localytics_info ADD app_key CHAR(64)",
NULL, NULL, NULL);
}
- (NSUInteger)databaseSize {
NSUInteger size = 0;
NSDictionary *fileAttributes = [[NSFileManager defaultManager]
attributesOfItemAtPath:[LocalyticsDatabase localyticsDatabasePath]
error:nil];
size = [fileAttributes fileSize];
return size;
}
- (int) eventCount {
int count = 0;
const char *sql = "SELECT count(*) FROM events";
sqlite3_stmt *selectEventCount;
if(sqlite3_prepare_v2(_databaseConnection, sql, -1, &selectEventCount, NULL) == SQLITE_OK)
{
if(sqlite3_step(selectEventCount) == SQLITE_ROW) {
count = sqlite3_column_int(selectEventCount, 0);
}
}
sqlite3_finalize(selectEventCount);
return count;
}
- (NSTimeInterval)createdTimestamp {
NSTimeInterval timestamp = 0;
NSDictionary *fileAttributes = [[NSFileManager defaultManager]
attributesOfItemAtPath:[LocalyticsDatabase localyticsDatabasePath]
error:nil];
timestamp = [[fileAttributes fileCreationDate] timeIntervalSince1970];
return timestamp;
}
- (NSTimeInterval)lastSessionStartTimestamp {
NSTimeInterval lastSessionStart = 0;
sqlite3_stmt *selectLastSessionStart;
sqlite3_prepare_v2(_databaseConnection, "SELECT last_session_start FROM localytics_info", -1, &selectLastSessionStart, NULL);
int code = sqlite3_step(selectLastSessionStart);
if (code == SQLITE_ROW) {
lastSessionStart = sqlite3_column_double(selectLastSessionStart, 0) == 1;
}
sqlite3_finalize(selectLastSessionStart);
return lastSessionStart;
}
- (BOOL)setLastsessionStartTimestamp:(NSTimeInterval)timestamp {
sqlite3_stmt *updateLastSessionStart;
sqlite3_prepare_v2(_databaseConnection, "UPDATE localytics_info SET last_session_start = ?", -1, &updateLastSessionStart, NULL);
sqlite3_bind_double(updateLastSessionStart, 1, timestamp);
int code = sqlite3_step(updateLastSessionStart);
sqlite3_finalize(updateLastSessionStart);
return code == SQLITE_DONE;
}
- (BOOL)isOptedOut {
BOOL optedOut = NO;
sqlite3_stmt *selectOptOut;
sqlite3_prepare_v2(_databaseConnection, "SELECT opt_out FROM localytics_info", -1, &selectOptOut, NULL);
int code = sqlite3_step(selectOptOut);
if (code == SQLITE_ROW) {
optedOut = sqlite3_column_int(selectOptOut, 0) == 1;
}
sqlite3_finalize(selectOptOut);
return optedOut;
}
- (BOOL)setOptedOut:(BOOL)optOut {
sqlite3_stmt *updateOptedOut;
sqlite3_prepare_v2(_databaseConnection, "UPDATE localytics_info SET opt_out = ?", -1, &updateOptedOut, NULL);
sqlite3_bind_int(updateOptedOut, 1, optOut);
int code = sqlite3_step(updateOptedOut);
sqlite3_finalize(updateOptedOut);
return code == SQLITE_OK;
}
- (NSString *)customDimension:(int)dimension {
if(dimension < 0 || dimension > 3) {
return nil;
}
NSString *value = nil;
NSString *query = [NSString stringWithFormat:@"select custom_d%i from localytics_info", dimension];
sqlite3_stmt *selectCustomDim;
sqlite3_prepare_v2(_databaseConnection, [query UTF8String], -1, &selectCustomDim, NULL);
int code = sqlite3_step(selectCustomDim);
if (code == SQLITE_ROW && sqlite3_column_text(selectCustomDim, 0)) {
value = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectCustomDim, 0)];
}
sqlite3_finalize(selectCustomDim);
return value;
}
- (BOOL)setCustomDimension:(int)dimension value:(NSString *)value {
if(dimension < 0 || dimension > 3) {
return false;
}
NSString *query = [NSString stringWithFormat:@"update localytics_info SET custom_d%i = %@",
dimension,
(value == nil) ? @"null" : [NSString stringWithFormat:@"\"%@\"", value]];
int code = sqlite3_exec(_databaseConnection, [query UTF8String], NULL, NULL, NULL);
return code == SQLITE_OK;
}
- (BOOL)incrementLastUploadNumber:(int *)uploadNumber {
NSString *t = @"increment_upload_number";
int code = SQLITE_OK;
code = [self beginTransaction:t] ? SQLITE_OK : SQLITE_ERROR;
if(code == SQLITE_OK) {
// Increment value
code = sqlite3_exec(_databaseConnection,
"UPDATE localytics_info "
"SET last_upload_number = (last_upload_number + 1)",
NULL, NULL, NULL);
}
if(code == SQLITE_OK) {
// Retrieve new value
sqlite3_stmt *selectUploadNumber;
sqlite3_prepare_v2(_databaseConnection,
"SELECT last_upload_number FROM localytics_info",
-1, &selectUploadNumber, NULL);
code = sqlite3_step(selectUploadNumber);
if (code == SQLITE_ROW) {
*uploadNumber = sqlite3_column_int(selectUploadNumber, 0);
}
sqlite3_finalize(selectUploadNumber);
}
if(code == SQLITE_ROW) {
[self releaseTransaction:t];
} else {
[self rollbackTransaction:t];
}
return code == SQLITE_ROW;
}
- (BOOL)incrementLastSessionNumber:(int *)sessionNumber {
NSString *t = @"increment_session_number";
int code = [self beginTransaction:t] ? SQLITE_OK : SQLITE_ERROR;
if(code == SQLITE_OK) {
// Increment value
code = sqlite3_exec(_databaseConnection,
"UPDATE localytics_info "
"SET last_session_number = (last_session_number + 1)",
NULL, NULL, NULL);
}
if(code == SQLITE_OK) {
// Retrieve new value
sqlite3_stmt *selectSessionNumber;
sqlite3_prepare_v2(_databaseConnection,
"SELECT last_session_number FROM localytics_info",
-1, &selectSessionNumber, NULL);
code = sqlite3_step(selectSessionNumber);
if (code == SQLITE_ROW && sessionNumber != NULL) {
*sessionNumber = sqlite3_column_int(selectSessionNumber, 0);
}
sqlite3_finalize(selectSessionNumber);
}
if(code == SQLITE_ROW) {
[self releaseTransaction:t];
} else {
[self rollbackTransaction:t];
}
return code == SQLITE_ROW;
}
- (BOOL)addEventWithBlobString:(NSString *)blob {
int code = SQLITE_OK;
sqlite3_stmt *insertEvent;
sqlite3_prepare_v2(_databaseConnection, "INSERT INTO events (blob_string) VALUES (?)", -1, &insertEvent, NULL);
sqlite3_bind_text(insertEvent, 1, [blob UTF8String], -1, SQLITE_TRANSIENT);
code = sqlite3_step(insertEvent);
sqlite3_finalize(insertEvent);
return code == SQLITE_DONE;
}
- (BOOL)addCloseEventWithBlobString:(NSString *)blob {
NSString *t = @"add_close_event";
BOOL success = [self beginTransaction:t];
// Add close event.
if (success) {
success = [self addEventWithBlobString:blob];
}
// Record row id to localytics_info so that it can be removed if the session resumes.
if (success) {
sqlite3_stmt *updateCloseEvent;
sqlite3_prepare_v2(_databaseConnection, "UPDATE localytics_info SET last_close_event = (SELECT event_id FROM events WHERE rowid = ?)", -1, &updateCloseEvent, NULL);
sqlite3_int64 lastRow = sqlite3_last_insert_rowid(_databaseConnection);
sqlite3_bind_int64(updateCloseEvent, 1, lastRow);
int code = sqlite3_step(updateCloseEvent);
sqlite3_finalize(updateCloseEvent);
success = code == SQLITE_DONE;
}
if (success) {
[self releaseTransaction:t];
} else {
[self rollbackTransaction:t];
}
return success;
}
- (BOOL)addFlowEventWithBlobString:(NSString *)blob {
NSString *t = @"add_flow_event";
BOOL success = [self beginTransaction:t];
// Add flow event.
if (success) {
success = [self addEventWithBlobString:blob];
}
// Record row id to localytics_info so that it can be removed if the session resumes.
if (success) {
sqlite3_stmt *updateFlowEvent;
sqlite3_prepare_v2(_databaseConnection, "UPDATE localytics_info SET last_flow_event = (SELECT event_id FROM events WHERE rowid = ?)", -1, &updateFlowEvent, NULL);
sqlite3_int64 lastRow = sqlite3_last_insert_rowid(_databaseConnection);
sqlite3_bind_int64(updateFlowEvent, 1, lastRow);
int code = sqlite3_step(updateFlowEvent);
sqlite3_finalize(updateFlowEvent);
success = code == SQLITE_DONE;
}
if (success) {
[self releaseTransaction:t];
} else {
[self rollbackTransaction:t];
}
return success;
}
- (BOOL)removeLastCloseAndFlowEvents {
// Attempt to remove the last recorded close event.
// Fail quietly if none was saved or it was previously removed.
int code = sqlite3_exec(_databaseConnection, "DELETE FROM events WHERE event_id = (SELECT last_close_event FROM localytics_info) OR event_id = (SELECT last_flow_event FROM localytics_info)", NULL, NULL, NULL);
return code == SQLITE_OK;
}
- (BOOL)addHeaderWithSequenceNumber:(int)number blobString:(NSString *)blob rowId:(sqlite3_int64 *)insertedRowId {
sqlite3_stmt *insertHeader;
sqlite3_prepare_v2(_databaseConnection, "INSERT INTO upload_headers (sequence_number, blob_string) VALUES (?, ?)", -1, &insertHeader, NULL);
sqlite3_bind_int(insertHeader, 1, number);
sqlite3_bind_text(insertHeader, 2, [blob UTF8String], -1, SQLITE_TRANSIENT);
int code = sqlite3_step(insertHeader);
sqlite3_finalize(insertHeader);
if (code == SQLITE_DONE && insertedRowId != NULL) {
*insertedRowId = sqlite3_last_insert_rowid(_databaseConnection);
}
return code == SQLITE_DONE;
}
- (int)unstagedEventCount {
int rowCount = 0;
sqlite3_stmt *selectEventCount;
sqlite3_prepare_v2(_databaseConnection, "SELECT COUNT(*) FROM events WHERE UPLOAD_HEADER IS NULL", -1, &selectEventCount, NULL);
int code = sqlite3_step(selectEventCount);
if (code == SQLITE_ROW) {
rowCount = sqlite3_column_int(selectEventCount, 0);
}
sqlite3_finalize(selectEventCount);
return rowCount;
}
- (BOOL)stageEventsForUpload:(sqlite3_int64)headerId {
// Associate all outstanding events with the given upload header ID.
NSString *stageEvents = [NSString stringWithFormat:@"UPDATE events SET upload_header = ? WHERE upload_header IS NULL"];
sqlite3_stmt *updateEvents;
sqlite3_prepare_v2(_databaseConnection, [stageEvents UTF8String], -1, &updateEvents, NULL);
sqlite3_bind_int(updateEvents, 1, headerId);
int code = sqlite3_step(updateEvents);
sqlite3_finalize(updateEvents);
BOOL success = (code == SQLITE_DONE);
return success;
}
- (BOOL)updateAppKey:(NSString *)appKey {
sqlite3_stmt *updateAppKey;
sqlite3_prepare_v2(_databaseConnection, "UPDATE localytics_info set app_key = ?", -1, &updateAppKey, NULL);
sqlite3_bind_text (updateAppKey, 1, [appKey UTF8String], -1, SQLITE_TRANSIENT);
int code = sqlite3_step(updateAppKey);
sqlite3_finalize(updateAppKey);
BOOL success = (code == SQLITE_DONE);
return success;
}
- (NSString *)uploadBlobString {
// Retrieve the blob strings of each upload header and its child events, in order.
const char *sql = "SELECT * FROM ( "
" SELECT h.blob_string AS 'blob', h.sequence_number as 'seq', 0 FROM upload_headers h"
" UNION ALL "
" SELECT e.blob_string AS 'blob', e.upload_header as 'seq', 1 FROM events e"
") "
"ORDER BY 2, 3";
sqlite3_stmt *selectBlobs;
sqlite3_prepare_v2(_databaseConnection, sql, -1, &selectBlobs, NULL);
NSMutableString *uploadBlobString = [NSMutableString string];
while (sqlite3_step(selectBlobs) == SQLITE_ROW) {
const char *blob = (const char *)sqlite3_column_text(selectBlobs, 0);
if (blob != NULL) {
NSString *blobString = [[NSString alloc] initWithCString:blob encoding:NSUTF8StringEncoding];
[uploadBlobString appendString:blobString];
[blobString release];
}
}
sqlite3_finalize(selectBlobs);
return [[uploadBlobString copy] autorelease];
}
- (BOOL)deleteUploadedData {
// Delete all headers and staged events.
NSString *t = @"delete_upload_data";
int code = [self beginTransaction:t] ? SQLITE_OK : SQLITE_ERROR;
if (code == SQLITE_OK) {
code = sqlite3_exec(_databaseConnection, "DELETE FROM events WHERE upload_header IS NOT NULL", NULL, NULL, NULL);
}
if (code == SQLITE_OK) {
code = sqlite3_exec(_databaseConnection, "DELETE FROM upload_headers", NULL, NULL, NULL);
}
if (code == SQLITE_OK) {
[self releaseTransaction:t];
} else {
[self rollbackTransaction:t];
}
return code == SQLITE_OK;
}
- (BOOL)resetAnalyticsData {
// Delete or zero all analytics data.
// Reset: headers, events, session number, upload number, last session start, last close event, and last flow event.
// Unaffected: schema version, opt out status, install ID (deprecated), and app key.
NSString *t = @"reset_analytics_data";
int code = [self beginTransaction:t] ? SQLITE_OK : SQLITE_ERROR;
if (code == SQLITE_OK) {
code = sqlite3_exec(_databaseConnection, "DELETE FROM events", NULL, NULL, NULL);
}
if (code == SQLITE_OK) {
code = sqlite3_exec(_databaseConnection, "DELETE FROM upload_headers", NULL, NULL, NULL);
}
if (code == SQLITE_OK) {
code = sqlite3_exec(_databaseConnection,"UPDATE localytics_info SET last_session_number = 0, last_upload_number = 0,"
"last_close_event = null, last_flow_event = null, last_session_start = null, "
"custom_d0 = null, custom_d1 = null, custom_d2 = null, custom_d3 = null",
NULL, NULL, NULL);
}
if (code == SQLITE_OK) {
[self releaseTransaction:t];
} else {
[self rollbackTransaction:t];
}
return code == SQLITE_OK;
}
- (BOOL)vacuumIfRequired {
int code = SQLITE_OK;
if ([self databaseSize] > MAX_DATABASE_SIZE * VACUUM_THRESHOLD) {
code = sqlite3_exec(_databaseConnection, "VACUUM", NULL, NULL, NULL);
}
return code == SQLITE_OK;
}
- (NSString *)randomUUID {
CFUUIDRef theUUID = CFUUIDCreate(NULL);
CFStringRef stringUUID = CFUUIDCreateString(NULL, theUUID);
CFRelease(theUUID);
return [(NSString *)stringUUID autorelease];
}
#pragma mark - Lifecycle
+ (id)allocWithZone:(NSZone *)zone {
@synchronized(self) {
if (_sharedLocalyticsDatabase == nil) {
_sharedLocalyticsDatabase = [super allocWithZone:zone];
return _sharedLocalyticsDatabase;
}
}
// returns nil on subsequent allocations
return nil;
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
// maximum value of an unsigned int - prevents additional retains for the class
return UINT_MAX;
}
- (oneway void)release {
// ignore release commands
}
- (id)autorelease {
return self;
}
- (void)dealloc {
sqlite3_close(_databaseConnection);
[super dealloc];
}
@end

View File

@@ -1,216 +0,0 @@
// LocalyticsSession.h
// Copyright (C) 2009 Char Software Inc., DBA Localytics
//
// This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE
// with this source code.
//
// Please visit www.localytics.com for more information.
#import <UIKit/UIKit.h>
// Set this to true to enable localytics traces (useful for debugging)
#define DO_LOCALYTICS_LOGGING false
/*!
@class LocalyticsSession
@discussion The class which manages creating, collecting, & uploading a Localytics session.
Please see the following guides for information on how to best use this
library, sample code, and other useful information:
<ul>
<li><a href="http://wiki.localytics.com/index.php?title=Developer's_Integration_Guide">Main Developer's Integration Guide</a></li>
</ul>
<strong>Best Practices</strong>
<ul>
<li>Instantiate the LocalyticsSession object in applicationDidFinishLaunching.</li>
<li>Open your session and begin your uploads in applicationDidFinishLaunching. This way the
upload has time to complete and it all happens before your users have a
chance to begin any data intensive actions of their own.</li>
<li>Close the session in applicationWillTerminate, and in applicationDidEnterBackground.</li>
<li>Resume the session in applicationWillEnterForeground.</li>
<li>Do not call any Localytics functions inside a loop. Instead, calls
such as <code>tagEvent</code> should follow user actions. This limits the
amount of data which is stored and uploaded.</li>
<li>Do not use multiple LocalticsSession objects to upload data with
multiple application keys. This can cause invalid state.</li>
</ul>
@author Localytics
*/
@interface LocalyticsSession : NSObject {
BOOL _hasInitialized; // Whether or not the session object has been initialized.
BOOL _isSessionOpen; // Whether or not this session has been opened.
float _backgroundSessionTimeout; // If an App stays in the background for more
// than this many seconds, start a new session
// when it returns to foreground.
@private
#pragma mark Member Variables
dispatch_queue_t _queue; // Queue of Localytics block objects.
dispatch_group_t _criticalGroup; // Group of blocks the must complete before backgrounding.
NSString *_sessionUUID; // Unique identifier for this session.
NSString *_applicationKey; // Unique identifier for the instrumented application
NSTimeInterval _lastSessionStartTimestamp; // The start time of the most recent session.
NSDate *_sessionResumeTime; // Time session was started or resumed.
NSDate *_sessionCloseTime; // Time session was closed.
NSMutableString *_unstagedFlowEvents; // Comma-delimited list of app screens and events tagged during this
// session that have NOT been staged for upload.
NSMutableString *_stagedFlowEvents; // App screens and events tagged during this session that HAVE been staged
// for upload.
NSMutableString *_screens; // Comma-delimited list of screens tagged during this session.
NSTimeInterval _sessionActiveDuration; // Duration that session open.
BOOL _sessionHasBeenOpen; // Whether or not this session has ever been open.
}
@property dispatch_queue_t queue;
@property dispatch_group_t criticalGroup;
@property BOOL isSessionOpen;
@property BOOL hasInitialized;
@property float backgroundSessionTimeout;
#pragma mark Public Methods
/*!
@method sharedLocalyticsSession
@abstract Accesses the Session object. This is a Singleton class which maintains
a single session throughout your application. It is possible to manage your own
session, but this is the easiest way to access the Localytics object throughout your code.
The class is accessed within the code using the following syntax:
[[LocalyticsSession sharedLocalyticsSession] functionHere]
So, to tag an event, all that is necessary, anywhere in the code is:
[[LocalyticsSession sharedLocalyticsSession] tagEvent:@"MY_EVENT"];
*/
+ (LocalyticsSession *)sharedLocalyticsSession;
/*!
@method LocalyticsSession
@abstract Initializes the Localytics Object. Not necessary if you choose to use startSession.
@param applicationKey The key unique for each application generated at www.localytics.com
*/
- (void)LocalyticsSession:(NSString *)appKey;
/*!
@method startSession
@abstract An optional convenience initialize method that also calls the LocalyticsSession, open &
upload methods. Best Practice is to call open & upload immediately after Localytics Session when loading an app,
this method fascilitates that behavior.
It is recommended that this call be placed in <code>applicationDidFinishLaunching</code>.
@param applicationKey The key unique for each application generated
at www.localytics.com
*/
- (void)startSession:(NSString *)appKey;
/*!
@method setOptIn
@abstract (OPTIONAL) Allows the application to control whether or not it will collect user data.
Even if this call is used, it is necessary to continue calling upload(). No new data will be
collected, so nothing new will be uploaded but it is necessary to upload an event telling the
server this user has opted out.
@param optedIn True if the user is opted in, false otherwise.
*/
- (void)setOptIn:(BOOL)optedIn;
/*!
@method isOptedIn
@abstract (OPTIONAL) Whether or not this user has is opted in or out. The only way they can be
opted out is if setOptIn(false) has been called before this. This function should only be
used to pre-populate a checkbox in an options menu. It is not recommended that an application
branch based on Localytics instrumentation because this creates an additional test case. If
the app is opted out, all subsequent Localytics calls will return immediately.
@result true if the user is opted in, false otherwise.
*/
- (BOOL)isOptedIn;
/*!
@method open
@abstract Opens the Localytics session. Not necessary if you choose to use startSession.
The session time as presented on the website is the time between <code>open</code> and the
final <code>close</code> so it is recommended to open the session as early as possible, and close
it at the last moment. The session must be opened before any tags can
be written. It is recommended that this call be placed in <code>applicationDidFinishLaunching</code>.
<br>
If for any reason this is called more than once every subsequent open call
will be ignored.
*/
- (void)open;
/*!
@method resume
@abstract Resumes the Localytics session. When the App enters the background, the session is
closed and the time of closing is recorded. When the app returns to the foreground, the session
is resumed. If the time since closing is greater than BACKGROUND_SESSION_TIMEOUT, (15 seconds
by default) a new session is created, and uploading is triggered. Otherwise, the previous session
is reopened.
*/
- (void)resume;
/*!
@method close
@abstract Closes the Localytics session. This should be called in
<code>applicationWillTerminate</code>.
<br>
If close is not called, the session will still be uploaded but no
events will be processed and the session time will not appear. This is
because the session is not yet closed so it should not be used in
comparison with sessions which are closed.
*/
- (void)close;
/*!
@method tagEvent
@abstract Allows a session to tag a particular event as having occurred. For
example, if a view has three buttons, it might make sense to tag
each button click with the name of the button which was clicked.
For another example, in a game with many levels it might be valuable
to create a new tag every time the user gets to a new level in order
to determine how far the average user is progressing in the game.
<br>
<strong>Tagging Best Practices</strong>
<ul>
<li>DO NOT use tags to record personally identifiable information.</li>
<li>The best way to use tags is to create all the tag strings as predefined
constants and only use those. This is more efficient and removes the risk of
collecting personal information.</li>
<li>Do not set tags inside loops or any other place which gets called
frequently. This can cause a lot of data to be stored and uploaded.</li>
</ul>
<br>
See the tagging guide at: http://wiki.localytics.com/
@param event The name of the event which occurred.
*/
- (void)tagEvent:(NSString *)event;
- (void)tagEvent:(NSString *)event attributes:(NSDictionary *)attributes;
- (void)tagEvent:(NSString *)event attributes:(NSDictionary *)attributes reportAttributes:(NSDictionary *)reportAttributes;
/*!
@method tagScreen
@abstract Allows tagging the flow of screens encountered during the session.
@param screen The name of the screen
*/
- (void)tagScreen:(NSString *)screen;
/*!
@method upload
@abstract Creates a low priority thread which uploads any Localytics data already stored
on the device. This should be done early in the process life in order to
guarantee as much time as possible for slow connections to complete. It is also reasonable
to upload again when the application is exiting because if the upload is cancelled the data
will just get uploaded the next time the app comes up.
*/
- (void)upload;
/*!
@method setCustomDimension
@abstract (ENTERPRISE ONLY) Sets the value of a custom dimension. Custom dimensions are dimensions
which contain user defined data unlike the predefined dimensions such as carrier, model, and country.
Once a value for a custom dimension is set, the device it was set on will continue to upload that value
until the value is changed. To clear a value pass nil as the value.
The proper use of custom dimensions involves defining a dimension with less than ten distinct possible
values and assigning it to one of the four available custom dimensions. Once assigned this definition should
never be changed without changing the App Key otherwise old installs of the application will pollute new data.
*/
- (void)setCustomDimension:(int)dimension value:(NSString *)value;
@end

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +0,0 @@
// LocalyticsUploader.h
// Copyright (C) 2009 Char Software Inc., DBA Localytics
//
// This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE
// with this source code.
//
// Please visit www.localytics.com for more information.
#import <UIKit/UIKit.h>
/*!
@class LocalyticsUploader
@discussion Singleton class to handle data uploads
*/
@interface LocalyticsUploader : NSObject {
}
@property (readonly) BOOL isUploading;
/*!
@method sharedLocalyticsUploader
@abstract Establishes this as a Singleton Class allowing for data persistence.
The class is accessed within the code using the following syntax:
[[LocalyticsUploader sharedLocalyticsUploader] functionHere]
*/
+ (LocalyticsUploader *)sharedLocalyticsUploader;
/*!
@method LocalyticsUploader
@abstract Creates a thread which uploads all queued header and event data.
All files starting with sessionFilePrefix are renamed,
uploaded and deleted on upload. This way the sessions can continue
writing data regardless of whether or not the upload succeeds. Files
which have been renamed still count towards the total number of Localytics
files which can be stored on the disk.
@param localyticsApplicationKey the Localytics application ID
*/
- (void)uploaderWithApplicationKey:(NSString *)localyticsApplicationKey;
@end

View File

@@ -1,236 +0,0 @@
// LocalyticsUploader.m
// Copyright (C) 2009 Char Software Inc., DBA Localytics
//
// This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE
// with this source code.
//
// Please visit www.localytics.com for more information.
#import "LocalyticsUploader.h"
#import "LocalyticsSession.h"
#import "LocalyticsDatabase.h"
#import <zlib.h>
#define LOCALYTICS_URL @"http://analytics.localytics.com/api/v2/applications/%@/uploads"
static LocalyticsUploader *_sharedUploader = nil;
@interface LocalyticsUploader ()
- (void)finishUpload;
- (NSData *)gzipDeflatedDataWithData:(NSData *)data;
- (void)logMessage:(NSString *)message;
@property (readwrite) BOOL isUploading;
@end
@implementation LocalyticsUploader
@synthesize isUploading = _isUploading;
#pragma mark - Singleton Class
+ (LocalyticsUploader *)sharedLocalyticsUploader {
@synchronized(self) {
if (_sharedUploader == nil) {
_sharedUploader = [[self alloc] init];
}
}
return _sharedUploader;
}
#pragma mark - Class Methods
- (void)uploaderWithApplicationKey:(NSString *)localyticsApplicationKey {
// Do nothing if already uploading.
if (self.isUploading == true)
{
[self logMessage:@"Upload already in progress. Aborting."];
return;
}
[self logMessage:@"Beginning upload process"];
self.isUploading = true;
// Prepare the data for upload. The upload could take a long time, so some effort has to be made to be sure that events
// which get written while the upload is taking place don't get lost or duplicated. To achieve this, the logic is:
// 1) Append every header row blob string and and those of its associated events to the upload string.
// 2) Deflate and upload the data.
// 3) On success, delete all blob headers and staged events. Events added while an upload is in process are not
// deleted because they are not associated a header (and cannot be until the upload completes).
// Step 1
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
LocalyticsDatabase *db = [LocalyticsDatabase sharedLocalyticsDatabase];
NSString *blobString = [db uploadBlobString];
if ([blobString length] == 0) {
// There is nothing outstanding to upload.
[self logMessage:@"Abandoning upload. There are no new events."];
[pool drain];
[self finishUpload];
return;
}
NSData *requestData = [blobString dataUsingEncoding:NSUTF8StringEncoding];
NSString *myString = [[[NSString alloc] initWithData:requestData encoding:NSUTF8StringEncoding] autorelease];
[self logMessage:[NSString stringWithFormat:@"Uploading data (length: %u)", [myString length]]];
// Step 2
NSData *deflatedRequestData = [[self gzipDeflatedDataWithData:requestData] retain];
[pool drain];
NSString *apiUrlString = [NSString stringWithFormat:LOCALYTICS_URL, [localyticsApplicationKey stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSMutableURLRequest *submitRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:apiUrlString]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:60.0];
[submitRequest setHTTPMethod:@"POST"];
[submitRequest setValue:@"application/x-gzip" forHTTPHeaderField:@"Content-Type"];
[submitRequest setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"];
[submitRequest setValue:[NSString stringWithFormat:@"%d", [deflatedRequestData length]] forHTTPHeaderField:@"Content-Length"];
[submitRequest setHTTPBody:deflatedRequestData];
[deflatedRequestData release];
// Perform synchronous upload in an async dispatch. This is necessary because the calling block will not persist to
// receive the response data.
dispatch_group_async([[LocalyticsSession sharedLocalyticsSession] criticalGroup], [[LocalyticsSession sharedLocalyticsSession] queue], ^{
@try {
NSURLResponse *response = nil;
NSError *responseError = nil;
[NSURLConnection sendSynchronousRequest:submitRequest returningResponse:&response error:&responseError];
NSInteger responseStatusCode = [(NSHTTPURLResponse *)response statusCode];
if (responseError) {
// On error, simply print the error and close the uploader. We have to assume the data was not transmited
// so it is not deleted. In the event that we accidently store data which was succesfully uploaded, the
// duplicate data will be ignored by the server when it is next uploaded.
[self logMessage:[NSString stringWithFormat:
@"Error Uploading. Code: %d, Description: %@",
[responseError code],
[responseError localizedDescription]]];
} else {
// Step 3
// While response status codes in the 5xx range leave upload rows intact, the default case is to delete.
if (responseStatusCode >= 500 && responseStatusCode < 600) {
[self logMessage:[NSString stringWithFormat:@"Upload failed with response status code %d", responseStatusCode]];
} else {
// Because only one instance of the uploader can be running at a time it should not be possible for
// new upload rows to appear so there is no fear of deleting data which has not yet been uploaded.
[self logMessage:[NSString stringWithFormat:@"Upload completed successfully. Response code %d", responseStatusCode]];
[[LocalyticsDatabase sharedLocalyticsDatabase] deleteUploadedData];
}
}
}
@catch (NSException * e) {}
[self finishUpload];
});
}
- (void)finishUpload
{
self.isUploading = false;
// Upload data has been deleted. Recover the disk space if necessary.
[[LocalyticsDatabase sharedLocalyticsDatabase] vacuumIfRequired];
}
/*!
@method gzipDeflatedDataWithData
@abstract Deflates the provided data using gzip at the default compression level (6). Complete NSData gzip category available on CocoaDev. http://www.cocoadev.com/index.pl?NSDataCategory.
@return the deflated data
*/
- (NSData *)gzipDeflatedDataWithData:(NSData *)data
{
if ([data length] == 0) return data;
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.total_out = 0;
strm.next_in=(Bytef *)[data bytes];
strm.avail_in = [data length];
// Compresssion Levels:
// Z_NO_COMPRESSION
// Z_BEST_SPEED
// Z_BEST_COMPRESSION
// Z_DEFAULT_COMPRESSION
if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK) return nil;
NSMutableData *compressed = [NSMutableData dataWithLength:16384]; // 16K chunks for expansion
do {
if (strm.total_out >= [compressed length])
[compressed increaseLengthBy: 16384];
strm.next_out = [compressed mutableBytes] + strm.total_out;
strm.avail_out = [compressed length] - strm.total_out;
deflate(&strm, Z_FINISH);
} while (strm.avail_out == 0);
deflateEnd(&strm);
[compressed setLength: strm.total_out];
return [NSData dataWithData:compressed];
}
/*!
@method logMessage
@abstract Logs a message with (localytics uploader) prepended to it
@param message The message to log
*/
- (void) logMessage:(NSString *)message {
if(DO_LOCALYTICS_LOGGING) {
NSLog(@"(localytics uploader) %s\n", [message UTF8String]);
}
}
#pragma mark - System Functions
+ (id)allocWithZone:(NSZone *)zone {
@synchronized(self) {
if (_sharedUploader == nil) {
_sharedUploader = [super allocWithZone:zone];
return _sharedUploader;
}
}
// returns nil on subsequent allocations
return nil;
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
// maximum value of an unsigned int - prevents additional retains for the class
return UINT_MAX;
}
- (oneway void)release {
// ignore release commands
}
- (id)autorelease {
return self;
}
- (void)dealloc {
[_sharedUploader release];
[super dealloc];
}
@end

View File

@@ -1,48 +0,0 @@
// UploaderThread.h
// Copyright (C) 2009 Char Software Inc., DBA Localytics
//
// This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE
// with this source code.
//
// Please visit www.localytics.com for more information.
#import <UIKit/UIKit.h>
/*!
@class UploaderThread
@discussion Singleton class to handle data uploads
*/
@interface UploaderThread : NSObject {
NSURLConnection *_uploadConnection; // The connection which uploads the bits
NSInteger _responseStatusCode; // The HTTP response status code for the current connection
BOOL _isUploading; // A flag to gaurantee only one uploader instance can happen at once
}
@property (nonatomic, retain) NSURLConnection *uploadConnection;
@property BOOL isUploading;
/*!
@method sharedUploaderThread
@abstract Establishes this as a Singleton Class allowing for data persistence.
The class is accessed within the code using the following syntax:
[[UploaderThread sharedUploaderThread] functionHere]
*/
+ (UploaderThread *)sharedUploaderThread;
/*!
@method UploaderThread
@abstract Creates a thread which uploads all queued header and event data.
All files starting with sessionFilePrefix are renamed,
uploaded and deleted on upload. This way the sessions can continue
writing data regardless of whether or not the upload succeeds. Files
which have been renamed still count towards the total number of Localytics
files which can be stored on the disk.
@param localyticsApplicationKey the Localytics application ID
*/
- (void)uploaderThreadwithApplicationKey:(NSString *)localyticsApplicationKey;
@end

View File

@@ -1,260 +0,0 @@
// UploaderThread.m
// Copyright (C) 2009 Char Software Inc., DBA Localytics
//
// This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE
// with this source code.
//
// Please visit www.localytics.com for more information.
#import "UploaderThread.h"
#import "LocalyticsSession.h"
#import "LocalyticsDatabase.h"
#import <zlib.h>
#define LOCALYTICS_URL @"http://analytics.localytics.com/api/v2/applications/%@/uploads" // url to send the
static UploaderThread *_sharedUploaderThread = nil;
@interface UploaderThread ()
- (void)complete;
- (NSData *)gzipDeflatedDataWithData:(NSData *)data;
- (void)logMessage:(NSString *)message;
@end
@implementation UploaderThread
@synthesize uploadConnection = _uploadConnection;
@synthesize isUploading = _isUploading;
#pragma mark Singleton Class
+ (UploaderThread *)sharedUploaderThread {
@synchronized(self) {
if (_sharedUploaderThread == nil)
{
_sharedUploaderThread = [[self alloc] init];
}
}
return _sharedUploaderThread;
}
#pragma mark Class Methods
- (void)uploaderThreadwithApplicationKey:(NSString *)localyticsApplicationKey {
// Do nothing if already uploading.
if (self.uploadConnection != nil || self.isUploading == true)
{
[self logMessage:@"Upload already in progress. Aborting."];
return;
}
[self logMessage:@"Beginning upload process"];
self.isUploading = true;
// Prepare the data for upload. The upload could take a long time, so some effort has to be made to be sure that events
// which get written while the upload is taking place don't get lost or duplicated. To achieve this, the logic is:
// 1) Append every header row blob string and and those of its associated events to the upload string.
// 2) Deflate and upload the data.
// 3) On success, delete all blob headers and staged events. Events added while an upload is in process are not
// deleted because they are not associated a header (and cannot be until the upload completes).
// Step 1
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
LocalyticsDatabase *db = [LocalyticsDatabase sharedLocalyticsDatabase];
NSString *blobString = [db uploadBlobString];
if ([blobString length] == 0) {
// There is nothing outstanding to upload.
[self logMessage:@"Abandoning upload. There are no new events."];
[pool drain];
[self complete];
return;
}
NSData *requestData = [blobString dataUsingEncoding:NSUTF8StringEncoding];
NSString *myString = [[[NSString alloc] initWithData:requestData encoding:NSUTF8StringEncoding] autorelease];
[self logMessage:@"Upload data:"];
[self logMessage:myString];
// Step 2
NSData *deflatedRequestData = [[self gzipDeflatedDataWithData:requestData] retain];
[pool drain];
NSString *apiUrlString = [NSString stringWithFormat:LOCALYTICS_URL, [localyticsApplicationKey stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSMutableURLRequest *submitRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:apiUrlString]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:60.0];
[submitRequest setHTTPMethod:@"POST"];
[submitRequest setValue:@"application/x-gzip" forHTTPHeaderField:@"Content-Type"];
[submitRequest setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"];
[submitRequest setValue:[NSString stringWithFormat:@"%d", [deflatedRequestData length]] forHTTPHeaderField:@"Content-Length"];
[submitRequest setHTTPBody:deflatedRequestData];
[deflatedRequestData release];
// The NSURLConnection Object automatically spawns its own thread as a default behavior.
@try
{
[self logMessage:@"Spawning new thread for upload"];
self.uploadConnection = [NSURLConnection connectionWithRequest:submitRequest delegate:self];
// Step 3 is handled by connectionDidFinishLoading.
}
@catch (NSException * e)
{
[self complete];
}
}
#pragma mark **** NSURLConnection FUNCTIONS ****
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// Used to gather response data from server - Not utilized in this version
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// Could receive multiple response callbacks, likely due to redirection.
// Record status and act only when connection completes load.
_responseStatusCode = [(NSHTTPURLResponse *)response statusCode];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// If the connection finished loading, the files should be deleted. While response status codes in the 5xx range
// leave upload rows intact, the default case is to delete.
if (_responseStatusCode >= 500 && _responseStatusCode < 600)
{
[self logMessage:[NSString stringWithFormat:@"Upload failed with response status code %d", _responseStatusCode]];
} else
{
// The connection finished loading and uploaded data should be deleted. Because only one instance of the
// uploader can be running at a time it should not be possible for new upload rows to appear so there is no
// fear of deleting data which has not yet been uploaded.
[self logMessage:[NSString stringWithFormat:@"Upload completed successfully. Response code %d", _responseStatusCode]];
[[LocalyticsDatabase sharedLocalyticsDatabase] deleteUploadData];
}
// Close upload session
[self complete];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// On error, simply print the error and close the uploader. We have to assume the data was not transmited
// so it is not deleted. In the event that we accidently store data which was succesfully uploaded, the
// duplicate data will be ignored by the server when it is next uploaded.
[self logMessage:[NSString stringWithFormat:
@"Error Uploading. Code: %d, Description: %s",
[error code],
[error localizedDescription]]];
[self complete];
}
/*!
@method complete
@abstract closes the upload connection and reports back to the session that the upload is complete
*/
- (void)complete {
_responseStatusCode = 0;
self.uploadConnection = nil;
self.isUploading = false;
}
/*!
@method gzipDeflatedDataWithData
@abstract Deflates the provided data using gzip at the default compression level (6). Complete NSData gzip category available on CocoaDev. http://www.cocoadev.com/index.pl?NSDataCategory.
@return the deflated data
*/
- (NSData *)gzipDeflatedDataWithData:(NSData *)data
{
if ([data length] == 0) return data;
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.total_out = 0;
strm.next_in=(Bytef *)[data bytes];
strm.avail_in = [data length];
// Compresssion Levels:
// Z_NO_COMPRESSION
// Z_BEST_SPEED
// Z_BEST_COMPRESSION
// Z_DEFAULT_COMPRESSION
if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY) != Z_OK) return nil;
NSMutableData *compressed = [NSMutableData dataWithLength:16384]; // 16K chunks for expansion
do {
if (strm.total_out >= [compressed length])
[compressed increaseLengthBy: 16384];
strm.next_out = [compressed mutableBytes] + strm.total_out;
strm.avail_out = [compressed length] - strm.total_out;
deflate(&strm, Z_FINISH);
} while (strm.avail_out == 0);
deflateEnd(&strm);
[compressed setLength: strm.total_out];
return [NSData dataWithData:compressed];
}
/*!
@method logMessage
@abstract Logs a message with (localytics uploader) prepended to it
@param message The message to log
*/
- (void) logMessage:(NSString *)message {
if(DO_LOCALYTICS_LOGGING) {
NSLog(@"(localytics uploader) %s\n", [message UTF8String]);
}
}
#pragma mark System Functions
+ (id)allocWithZone:(NSZone *)zone {
@synchronized(self) {
if (_sharedUploaderThread == nil) {
_sharedUploaderThread = [super allocWithZone:zone];
return _sharedUploaderThread;
}
}
// returns nil on subsequent allocations
return nil;
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
// maximum value of an unsigned int - prevents additional retains for the class
return UINT_MAX;
}
- (oneway void)release {
// ignore release commands
}
- (id)autorelease {
return self;
}
- (void)dealloc {
[_uploadConnection release];
[_sharedUploaderThread release];
[super dealloc];
}
@end

View File

@@ -1,111 +0,0 @@
// WebserviceConstants.h
// Copyright (C) 2009 Char Software Inc., DBA Localytics
//
// This code is provided under the Localytics Modified BSD License.
// A copy of this license has been distributed in a file called LICENSE
// with this source code.
//
// Please visit www.localytics.com for more information.
// The constants which are used to make up the JSON blob
// To save disk space and network bandwidth all the keywords have been
// abbreviated and are exploded by the server.
/*********************
* Shared Attributes *
*********************/
#define PARAM_UUID @"u" // UUID for JSON document
#define PARAM_DATA_TYPE @"dt" // Data Type
#define PARAM_CLIENT_TIME @"ct" // Client Time, seconds from Unix epoch (int)
#define PARAM_LATITUDE @"lat" // Latitude - if available
#define PARAM_LONGITUDE @"lon" // Longitude - if available
#define PARAM_SESSION_UUID @"su" // UUID for an existing session
#define PARAM_NEW_SESSION_UUID @"u" // UUID for a new session
#define PARAM_ATTRIBUTES @"attrs" // Attributes (dictionary)
/***************
* Blob Header *
***************/
// PARAM_UUID
// PARAM_DATA_TYPE => "h" for Header
// PARAM_ATTRIBUTES => dictionary containing Header Common Attributes
#define PARAM_PERSISTED_AT @"pa" // Persistent Storage Created At. A timestamp created when the app was
// first launched and the persistent storage was created. Stores as
// seconds from Unix epoch. (int)
#define PARAM_SEQUENCE_NUMBER @"seq" // Sequence number - an increasing count for each blob, stored in the
// persistent store Consistent across app starts. (int)
/****************************
* Header Common Attributes *
****************************/
// PARAM_DATA_TYPE
#define PARAM_APP_KEY @"au" // Localytics Application ID
#define PARAM_DEVICE_UUID @"du" // Device UUID
#define PARAM_DEVICE_UUID_HASHED @"udid" // Hashed version of the UUID
#define PARAM_DEVICE_MAC @"wmac" // Hashed version of the device Mac
#define PARAM_INSTALL_ID @"iu" // Install ID
#define PARAM_JAILBROKEN @"j" // Jailbroken (boolean)
#define PARAM_LIBRARY_VERSION @"lv" // Client Version
#define PARAM_APP_VERSION @"av" // Application Version
#define PARAM_DEVICE_PLATFORM @"dp" // Device Platform
#define PARAM_LOCALE_LANGUAGE @"dll" // Locale Language
#define PARAM_LOCALE_COUNTRY @"dlc" // Locale Country
#define PARAM_NETWORK_COUNTRY @"nc" // Network Country (iso code) // ???: Never used on iPhone.
#define PARAM_DEVICE_COUNTRY @"dc" // Device Country (iso code)
#define PARAM_DEVICE_MANUFACTURER @"dma" // Device Manufacturer // ???: Never used on iPhone. Used to be "Device Make".
#define PARAM_DEVICE_MODEL @"dmo" // Device Model
#define PARAM_DEVICE_OS_VERSION @"dov" // Device OS Version
#define PARAM_NETWORK_CARRIER @"nca" // Network Carrier
#define PARAM_DATA_CONNECTION @"dac" // Data Connection Type // ???: Never used on iPhone.
#define PARAM_OPT_VALUE @"optin" // Opt In (boolean)
#define PARAM_DEVICE_MEMORY @"dmem" // Device Memory
/*****************
* Session Start *
*****************/
// PARAM_UUID
// PARAM_DATA_TYPE => "s" for Start
// PARAM_CLIENT_TIME
#define PARAM_SESSION_NUMBER @"nth" // This is the nth session on the device, 1-indexed (int)
/****************
* Session Stop *
****************/
// PARAM_UUID
// PARAM_DATA_TYPE => "c" for Close
// PARAM_CLIENT_TIME
// PARAM_LATITUDE
// PARAM_LONGITUDE
// PARAM_SESSION_UUID => UUID of session being closed
#define PARAM_SESSION_ACTIVE @"cta" // Active time in seconds (time app was active)
#define PARAM_SESSION_TOTAL @"ctl" // Total session length
#define PARAM_SESSION_SCREENFLOW @"fl" // Screens encountered during this session, in order
/*********************
* Application Event *
*********************/
// PARAM_UUID
// PARAM_DATA_TYPE => "e" for Event
// PARAM_CLIENT_TIME
// PARAM_LATITUDE
// PARAM_LONGITUDE
// PARAM_SESSION_UUID => UUID of session event occured in
// PARAM_ATTRIBUTES => dictionary containing attributes for this event as key-value string pairs
#define PARAM_EVENT_NAME @"n" // Event Name, (eg. 'Button Click')
#define PARAM_REPORT_ATTRIBUTES @"rattrs" // Attributes used in custom reports
/********************
* Application flow *
********************/
// PARAM_UUID
// PARAM_DATA_TYPE => "f" for Flow
// PARAM_CLIENT_TIME
#define PARAM_SESSION_START @"ss" // Start time for the current session.
#define PARAM_NEW_FLOW_EVENTS @"nw" // Events and screens encountered during this session that have NOT been staged for upload.
#define PARAM_OLD_FLOW_EVENTS @"od" // Events and screens encountered during this session that HAVE been staged for upload.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj">
</FileRef>
<FileRef
location = "group:MasterPassword/ObjC/Mac/MasterPassword-Mac.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,125 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDESourceControlProjectFavoriteDictionaryKey</key>
<false/>
<key>IDESourceControlProjectIdentifier</key>
<string>1DC75A27-0030-4493-ACE8-E1D49AB9A549</string>
<key>IDESourceControlProjectName</key>
<string>MasterPassword</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>1AA8C0BE-EEC3-4FBC-A801-8939A1AC093A</key>
<string>git://github.com/Lyndir/love-lyndir.client.git</string>
<key>42C94803-87A2-403E-896C-D9AC3A807E1B</key>
<string>git://github.com/lhunath/UbiquityStoreManager.git</string>
<key>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</key>
<string>ssh://github.com/Lyndir/MasterPassword.git</string>
<key>ADA0D7F9-4871-4128-8FEE-FD1021EEF3AC</key>
<string>ssh://github.com/Lyndir/Pearl.git</string>
<key>AE3786C7-912B-4651-A73F-2E1DACBFB604</key>
<string>git://github.com/lhunath/uicolor-utilities.git</string>
<key>B0F634DD-AEE1-4F0D-AE35-4FAF51AD1B5A</key>
<string>git://github.com/lhunath/RHStatusItemView.git</string>
<key>CDDE92CF-0136-4DE0-8318-80EDB5C8CAF9</key>
<string>git://github.com/lhunath/InAppSettingsKit.git</string>
<key>E4C8E206-229C-4DA8-A130-0C544DEC7E07</key>
<string>git://github.com/jonmarimba/jrswizzle.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>MasterPassword.xcworkspace</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>1AA8C0BE-EEC3-4FBC-A801-8939A1AC093A</key>
<string>../External/LoveLyndir</string>
<key>42C94803-87A2-403E-896C-D9AC3A807E1B</key>
<string>../External/UbiquityStoreManager</string>
<key>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</key>
<string>..</string>
<key>ADA0D7F9-4871-4128-8FEE-FD1021EEF3AC</key>
<string>../External/Pearl</string>
<key>AE3786C7-912B-4651-A73F-2E1DACBFB604</key>
<string>../External/Pearl/External/uicolor-utilities</string>
<key>B0F634DD-AEE1-4F0D-AE35-4FAF51AD1B5A</key>
<string>../External/RHStatusItemView</string>
<key>CDDE92CF-0136-4DE0-8318-80EDB5C8CAF9</key>
<string>../External/InAppSettingsKit</string>
<key>E4C8E206-229C-4DA8-A130-0C544DEC7E07</key>
<string>../External/Pearl/External/jrswizzle</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>ssh://github.com/Lyndir/MasterPassword.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>110</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>CDDE92CF-0136-4DE0-8318-80EDB5C8CAF9</string>
<key>IDESourceControlWCCName</key>
<string>InAppSettingsKit</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>E4C8E206-229C-4DA8-A130-0C544DEC7E07</string>
<key>IDESourceControlWCCName</key>
<string>jrswizzle</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>1AA8C0BE-EEC3-4FBC-A801-8939A1AC093A</string>
<key>IDESourceControlWCCName</key>
<string>LoveLyndir</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>6A449EC2-A2A3-4635-9C5F-A811E011EAC3</string>
<key>IDESourceControlWCCName</key>
<string>MasterPassword</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>ADA0D7F9-4871-4128-8FEE-FD1021EEF3AC</string>
<key>IDESourceControlWCCName</key>
<string>Pearl</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>B0F634DD-AEE1-4F0D-AE35-4FAF51AD1B5A</string>
<key>IDESourceControlWCCName</key>
<string>RHStatusItemView</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>42C94803-87A2-403E-896C-D9AC3A807E1B</string>
<key>IDESourceControlWCCName</key>
<string>UbiquityStoreManager</string>
</dict>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>AE3786C7-912B-4651-A73F-2E1DACBFB604</string>
<key>IDESourceControlWCCName</key>
<string>uicolor-utilities</string>
</dict>
</array>
</dict>
</plist>

1920
MasterPassword/C/bashlib Executable file

File diff suppressed because it is too large Load Diff

9
MasterPassword/C/build Executable file
View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# Run with -DDEBUG to enable trace-level output.
[[ -e lib/scrypt/scryptenc.o ]] || { echo >&2 "Missing scrypt. First get and build the scrypt source in lib/scrypt from <$(<lib/scrypt/.source)>.\n"; exit 1; }
deps=( -I"lib/scrypt/lib" -I"lib/scrypt/libcperciva" -l "crypto_aesctr.o" -l "sha256.o" -l "crypto_scrypt-nosse.o" -l "memlimit.o" -l "scryptenc_cpuperf.o" -l"scryptenc.o" -l"crypto" -L"." -L"lib/scrypt" )
gcc "${deps[@]}" -Qunused-arguments -c types.c -o types.o "$@"
gcc "${deps[@]}" -Qunused-arguments -l"types.o" mpw.c -o mpw "$@"

53
MasterPassword/C/install Executable file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/env bash
#
# Install the Master Password CLI tool.
set -e
cd "${BASH_SOURCE%/*}"
source bashlib
inf "This will install the mpw tool."
# Try to guess then ask for the bin dir to install to.
IFS=: read -a paths <<< "$PATH"
if inArray ~/bin "${paths[@]}"; then
bindir=~/bin
elif inArray ~/.bin "${paths[@]}"; then
bindir=~/.bin
elif inArray /usr/local/bin "${paths[@]}"; then
bindir=/usr/local/bin
else
bindir=~/bin
fi
bindir=$(ask -d "$bindir" "What bin directory should I install to?")
[[ -d "$bindir" ]] || mkdir "$bindir" || ftl 'Cannot create missing bin directory: %s' "$bindir" || exit
[[ -w "$bindir" ]] || ftl 'Cannot write to bin directory: %s' "$bindir" || exit
# Install Master Password.
install mpw "$bindir"
[[ ! -e "$bindir/bashlib" ]] && install bashlib "$bindir" ||:
# Convenience bash function.
inf "Installation successful!"
echo
inf "To improve usability, you can install an mpw function in your bash shell."
inf "This function adds the following features:"
inf " - Automatically remember your user name in the shell if not set."
inf " - Automatically put the password in the clipboard (some platforms)."
echo
inf "To do this you need the following function in ~/.bashrc:\n%s" "$(<mpw.bashrc)"
echo
inf "We can do this for you automatically now."
if ask -c Y!n "Append the mpw function to your .bashrc?"; then
cat mpw.bashrc >> ~/.bashrc
inf "Done! Don't forget to run '%s' to apply the changes!" "source ~/.bashrc"
fi
echo
inf "You can also save your user name in ~/.bashrc. Leave blank to skip this step."
if MP_USERNAME=$(ask "Your full name:") && [[ $MP_USERNAME ]] ; then
printf 'export MP_USERNAME=%q\n' "$MP_USERNAME" >> ~/.bashrc
fi
echo
inf "To begin using Master Password, type: mpw [site name]"

View File

@@ -0,0 +1,38 @@
diff -ruN /Users/lhunath/.src/scrypt/Makefile ./Makefile
--- /Users/lhunath/.src/scrypt/Makefile 2014-05-02 11:28:58.000000000 -0400
+++ ./Makefile 2014-05-02 12:07:27.000000000 -0400
@@ -2,11 +2,11 @@
VER?= nosse
SRCS= main.c
LDADD+= -lcrypto
-WARNS?= 6
+WARNS?= 0
# We have a config file for FreeBSD
CFLAGS += -I .
-CFLAGS += -DCONFIG_H_FILE=\"config_freebsd.h\"
+CFLAGS += -DCONFIG_H_FILE=\"config_osx.h\"
# Include all possible object files containing built scrypt code.
CLEANFILES += crypto_scrypt-ref.o
diff -ruN /Users/lhunath/.src/scrypt/lib/util/memlimit.c ./lib/util/memlimit.c
--- /Users/lhunath/.src/scrypt/lib/util/memlimit.c 2014-05-02 11:28:58.000000000 -0400
+++ ./lib/util/memlimit.c 2014-05-02 11:52:42.000000000 -0400
@@ -75,7 +75,7 @@
* have returned to us.
*/
if (usermemlen == sizeof(uint64_t))
- usermem = *(uint64_t *)usermembuf;
+ usermem = *(uint64_t *)(void *)usermembuf;
else if (usermemlen == sizeof(uint32_t))
usermem = SIZE_MAX;
else
diff -ruN /Users/lhunath/.src/scrypt/lib/util/memlimit.c ./lib/util/memlimit.c
--- /Users/lhunath/.src/scrypt/config_osx.h 1969-12-31 19:00:00.000000000 -0500
+++ config_osx.h 2014-05-02 12:06:55.000000000 -0400
@@ -0,0 +1,5 @@
+/* A default configuration for FreeBSD, used if there is no config.h. */
+
+#define HAVE_POSIX_MEMALIGN 1
+#define HAVE_SYSCTL_HW_USERMEM 1
+#define HAVE_SYS_PARAM_H 1

View File

@@ -0,0 +1 @@
https://code.google.com/p/scrypt/

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,24 @@
## Added by Master Password
source bashlib
mpw() {
_copy() {
if hash pbcopy 2>/dev/null; then
pbcopy
elif hash xclip 2>/dev/null; then
xclip
else
cat; echo 2>/dev/null
return
fi
echo >&2 "Copied!"
}
# Empty the clipboard
:| _copy 2>/dev/null
# Ask for the user's name and password if not yet known.
MP_USERNAME=${MP_USERNAME:-$(ask 'Your Full Name:')}
# Start Master Password and copy the output.
printf %s "$(MP_USERNAME=$MP_USERNAME command mpw "$@")" | _copy
}

257
MasterPassword/C/mpw.c Normal file
View File

@@ -0,0 +1,257 @@
#define _WITH_GETLINE
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(__linux__)
#include <linux/fs.h>
#elif defined(__CYGWIN__)
#include <cygwin/fs.h>
#else
#include <sys/disk.h>
#endif
#include <fcntl.h>
#include <unistd.h>
#include <math.h>
#include <pwd.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <alg/sha256.h>
#include <crypto/crypto_scrypt.h>
#include "types.h"
#define MP_N 32768
#define MP_r 8
#define MP_p 2
#define MP_dkLen 64
#define MP_hash PearlHashSHA256
#define MP_env_username "MP_USERNAME"
#define MP_env_sitetype "MP_SITETYPE"
#define MP_env_sitecounter "MP_SITECOUNTER"
void usage() {
fprintf(stderr, "Usage: mpw [-u name] [-t type] [-c counter] site\n\n");
fprintf(stderr, " -u name Specify the full name of the user.\n"
" Defaults to %s in env.\n\n", MP_env_username);
fprintf(stderr, " -t type Specify the password's template.\n"
" Defaults to %s in env or 'long'.\n"
" x, max, maximum | 20 characters, contains symbols.\n"
" l, long | Copy-friendly, 14 characters, contains symbols.\n"
" m, med, medium | Copy-friendly, 8 characters, contains symbols.\n"
" b, basic | 8 characters, no symbols.\n"
" s, short | Copy-friendly, 4 characters, no symbols.\n"
" p, pin | 4 numbers.\n\n", MP_env_sitetype);
fprintf(stderr, " -c counter The value of the counter.\n"
" Defaults to %s in env or '1'.\n\n", MP_env_sitecounter);
exit(0);
}
char *homedir(const char *filename) {
char *homedir = NULL;
#if defined(__CYGWIN__)
homedir = getenv("USERPROFILE");
if (!homedir) {
const char *homeDrive = getenv("HOMEDRIVE");
const char *homePath = getenv("HOMEPATH");
homedir = char[strlen(homeDrive) + strlen(homePath) + 1];
sprintf(homedir, "%s/%s", homeDrive, homePath);
}
#else
struct passwd* passwd = getpwuid(getuid());
if (passwd)
homedir = passwd->pw_dir;
if (!homedir)
homedir = getenv("HOME");
#endif
if (!homedir)
homedir = getcwd(NULL, 0);
char *homefile = NULL;
asprintf(&homefile, "%s/%s", homedir, filename);
return homefile;
}
int main(int argc, char *const argv[]) {
if (argc < 2)
usage();
// Read the environment.
const char *userName = getenv( MP_env_username );
const char *masterPassword = NULL;
const char *siteName = NULL;
MPElementType siteType = MPElementTypeGeneratedLong;
const char *siteTypeString = getenv( MP_env_sitetype );
uint32_t siteCounter = 1;
const char *siteCounterString = getenv( MP_env_sitecounter );
// Read the options.
char opt;
while ((opt = getopt(argc, argv, "u:t:c:h")) != -1)
switch (opt) {
case 'h':
usage();
break;
case 'u':
userName = optarg;
break;
case 't':
siteTypeString = optarg;
break;
case 'c':
siteCounterString = optarg;
break;
case '?':
switch (optopt) {
case 'u':
fprintf(stderr, "Missing user name to option: -%c\n", optopt);
break;
case 't':
fprintf(stderr, "Missing type name to option: -%c\n", optopt);
break;
case 'c':
fprintf(stderr, "Missing counter value to option: -%c\n", optopt);
break;
default:
fprintf(stderr, "Unknown option: -%c\n", optopt);
}
return 1;
default:
abort();
}
if (optind < argc)
siteName = argv[optind];
// Convert and validate input.
if (!userName) {
fprintf(stderr, "Missing user name.\n");
return 1;
}
trc("userName: %s\n", userName);
if (!siteName) {
fprintf(stderr, "Missing site name.\n");
return 1;
}
trc("siteName: %s\n", siteName);
if (siteCounterString)
siteCounter = atoi( siteCounterString );
if (siteCounter < 1) {
fprintf(stderr, "Invalid site counter: %d\n", siteCounter);
return 1;
}
trc("siteCounter: %d\n", siteCounter);
if (siteTypeString)
siteType = TypeWithName( siteTypeString );
trc("siteType: %d (%s)\n", siteType, siteTypeString);
// Read the master password.
char *mpwConfigPath = homedir(".mpw");
if (!mpwConfigPath) {
fprintf(stderr, "Couldn't resolve path for configuration file: %d\n", errno);
return 1;
}
trc("mpwConfigPath: %s\n", mpwConfigPath);
FILE *mpwConfig = fopen(mpwConfigPath, "r");
if (!mpwConfig) {
fprintf(stderr, "Couldn't open configuration file: %s: %d\n", mpwConfigPath, errno);
return 1;
}
free(mpwConfigPath);
char *line = NULL;
size_t linecap = 0;
ssize_t linelen;
while ((linelen = getline(&line, &linecap, mpwConfig)) > 0)
if (strcmp(strsep(&line, ":"), userName) == 0) {
masterPassword = strsep(&line, "\n");
break;
}
if (!masterPassword) {
fprintf(stderr, "Missing master password for user: %s\n", userName);
return 1;
}
trc("masterPassword: %s\n", masterPassword);
// Calculate the master key salt.
char *mpNameSpace = "com.lyndir.masterpassword";
const uint32_t n_userNameLength = htonl(strlen(userName));
size_t masterKeySaltLength = strlen(mpNameSpace) + sizeof(n_userNameLength) + strlen(userName);
char *masterKeySalt = malloc( masterKeySaltLength );
if (!masterKeySalt) {
fprintf(stderr, "Could not allocate master key salt: %d\n", errno);
return 1;
}
char *mKS = masterKeySalt;
memcpy(mKS, mpNameSpace, strlen(mpNameSpace)); mKS += strlen(mpNameSpace);
memcpy(mKS, &n_userNameLength, sizeof(n_userNameLength)); mKS += sizeof(n_userNameLength);
memcpy(mKS, userName, strlen(userName)); mKS += strlen(userName);
if (mKS - masterKeySalt != masterKeySaltLength)
abort();
trc("masterKeySalt ID: %s\n", IDForBuf(masterKeySalt, masterKeySaltLength));
// Calculate the master key.
uint8_t *masterKey = malloc( MP_dkLen );
if (!masterKey) {
fprintf(stderr, "Could not allocate master key: %d\n", errno);
return 1;
}
if (crypto_scrypt( (const uint8_t *)masterPassword, strlen(masterPassword), (const uint8_t *)masterKeySalt, masterKeySaltLength, MP_N, MP_r, MP_p, masterKey, MP_dkLen ) < 0) {
fprintf(stderr, "Could not generate master key: %d\n", errno);
return 1;
}
memset(masterKeySalt, 0, masterKeySaltLength);
free(masterKeySalt);
trc("masterPassword Hex: %s\n", Hex(masterPassword, strlen(masterPassword)));
trc("masterPassword ID: %s\n", IDForBuf(masterPassword, strlen(masterPassword)));
trc("masterKey ID: %s\n", IDForBuf(masterKey, MP_dkLen));
// Calculate the site seed.
const uint32_t n_siteNameLength = htonl(strlen(siteName));
const uint32_t n_siteCounter = htonl(siteCounter);
size_t sitePasswordInfoLength = strlen(mpNameSpace) + sizeof(n_siteNameLength) + strlen(siteName) + sizeof(n_siteCounter);
char *sitePasswordInfo = malloc( sitePasswordInfoLength );
if (!sitePasswordInfo) {
fprintf(stderr, "Could not allocate site seed: %d\n", errno);
return 1;
}
char *sPI = sitePasswordInfo;
memcpy(sPI, mpNameSpace, strlen(mpNameSpace)); sPI += strlen(mpNameSpace);
memcpy(sPI, &n_siteNameLength, sizeof(n_siteNameLength)); sPI += sizeof(n_siteNameLength);
memcpy(sPI, siteName, strlen(siteName)); sPI += strlen(siteName);
memcpy(sPI, &n_siteCounter, sizeof(n_siteCounter)); sPI += sizeof(n_siteCounter);
if (sPI - sitePasswordInfo != sitePasswordInfoLength)
abort();
trc("seed from: hmac-sha256(masterKey, 'com.lyndir.masterpassword' | %s | %s | %s)\n", Hex(&n_siteNameLength, sizeof(n_siteNameLength)), siteName, Hex(&n_siteCounter, sizeof(n_siteCounter)));
trc("sitePasswordInfo ID: %s\n", IDForBuf(sitePasswordInfo, sitePasswordInfoLength));
uint8_t sitePasswordSeed[32];
HMAC_SHA256_Buf(masterKey, MP_dkLen, sitePasswordInfo, sitePasswordInfoLength, sitePasswordSeed);
memset(masterKey, 0, MP_dkLen);
memset(sitePasswordInfo, 0, sitePasswordInfoLength);
free(masterKey);
free(sitePasswordInfo);
trc("sitePasswordSeed ID: %s\n", IDForBuf(sitePasswordSeed, 32));
// Determine the cipher.
const char *cipher = CipherForType(siteType, sitePasswordSeed[0]);
trc("type %s, cipher: %s\n", siteTypeString, cipher);
if (strlen(cipher) > 32)
abort();
// Encode the password from the seed using the cipher.
char *sitePassword = calloc(strlen(cipher) + 1, sizeof(char));
for (int c = 0; c < strlen(cipher); ++c) {
sitePassword[c] = CharacterFromClass(cipher[c], sitePasswordSeed[c + 1]);
trc("class %c, character: %c\n", cipher[c], sitePassword[c]);
}
memset(sitePasswordSeed, 0, sizeof(sitePasswordSeed));
// Output the password.
fprintf( stdout, "%s\n", sitePassword );
return 0;
}

140
MasterPassword/C/types.c Normal file
View File

@@ -0,0 +1,140 @@
//
// MPTypes.h
// MasterPassword
//
// Created by Maarten Billemont on 02/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <alg/sha256.h>
#include "types.h"
const MPElementType TypeWithName(const char *typeName) {
char lowerTypeName[strlen(typeName)];
strcpy(lowerTypeName, typeName);
for (char *tN = lowerTypeName; *tN; ++tN)
*tN = tolower(*tN);
if (0 == strcmp(lowerTypeName, "x") || 0 == strcmp(lowerTypeName, "max") || 0 == strcmp(lowerTypeName, "maximum"))
return MPElementTypeGeneratedMaximum;
if (0 == strcmp(lowerTypeName, "l") || 0 == strcmp(lowerTypeName, "long"))
return MPElementTypeGeneratedLong;
if (0 == strcmp(lowerTypeName, "m") || 0 == strcmp(lowerTypeName, "med") || 0 == strcmp(lowerTypeName, "medium"))
return MPElementTypeGeneratedMedium;
if (0 == strcmp(lowerTypeName, "b") || 0 == strcmp(lowerTypeName, "basic"))
return MPElementTypeGeneratedBasic;
if (0 == strcmp(lowerTypeName, "s") || 0 == strcmp(lowerTypeName, "short"))
return MPElementTypeGeneratedShort;
if (0 == strcmp(lowerTypeName, "p") || 0 == strcmp(lowerTypeName, "pin"))
return MPElementTypeGeneratedPIN;
fprintf(stderr, "Not a generated type name: %s", lowerTypeName);
abort();
}
const char *CipherForType(MPElementType type, uint8_t seedByte) {
if (!(type & MPElementTypeClassGenerated)) {
fprintf(stderr, "Not a generated type: %d", type);
abort();
}
switch (type) {
case MPElementTypeGeneratedMaximum: {
char *ciphers[] = { "anoxxxxxxxxxxxxxxxxx", "axxxxxxxxxxxxxxxxxno" };
return ciphers[seedByte % 2];
}
case MPElementTypeGeneratedLong: {
char *ciphers[] = { "CvcvnoCvcvCvcv", "CvcvCvcvnoCvcv", "CvcvCvcvCvcvno", "CvccnoCvcvCvcv", "CvccCvcvnoCvcv", "CvccCvcvCvcvno", "CvcvnoCvccCvcv", "CvcvCvccnoCvcv", "CvcvCvccCvcvno", "CvcvnoCvcvCvcc", "CvcvCvcvnoCvcc", "CvcvCvcvCvccno", "CvccnoCvccCvcv", "CvccCvccnoCvcv", "CvccCvccCvcvno", "CvcvnoCvccCvcc", "CvcvCvccnoCvcc", "CvcvCvccCvccno", "CvccnoCvcvCvcc", "CvccCvcvnoCvcc", "CvccCvcvCvccno" };
return ciphers[seedByte % 21];
}
case MPElementTypeGeneratedMedium: {
char *ciphers[] = { "CvcnoCvc", "CvcCvcno" };
return ciphers[seedByte % 2];
}
case MPElementTypeGeneratedBasic: {
char *ciphers[] = { "aaanaaan", "aannaaan", "aaannaaa" };
return ciphers[seedByte % 3];
}
case MPElementTypeGeneratedShort: {
return "Cvcn";
}
case MPElementTypeGeneratedPIN: {
return "nnnn";
}
default: {
fprintf(stderr, "Unknown generated type: %d", type);
abort();
}
}
}
const char CharacterFromClass(char characterClass, uint8_t seedByte) {
const char *classCharacters;
switch (characterClass) {
case 'V': {
classCharacters = "AEIOU";
break;
}
case 'C': {
classCharacters = "BCDFGHJKLMNPQRSTVWXYZ";
break;
}
case 'v': {
classCharacters = "aeiou";
break;
}
case 'c': {
classCharacters = "bcdfghjklmnpqrstvwxyz";
break;
}
case 'A': {
classCharacters = "AEIOUBCDFGHJKLMNPQRSTVWXYZ";
break;
}
case 'a': {
classCharacters = "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz";
break;
}
case 'n': {
classCharacters = "0123456789";
break;
}
case 'o': {
classCharacters = "@&%?,=[]_:-+*$#!'^~;()/.";
break;
}
case 'x': {
classCharacters = "AEIOUaeiouBCDFGHJKLMNPQRSTVWXYZbcdfghjklmnpqrstvwxyz0123456789!@#$%^&*()";
break;
}
default: {
fprintf(stderr, "Unknown character class: %c", characterClass);
abort();
}
}
return classCharacters[seedByte % strlen(classCharacters)];
}
const char *IDForBuf(const void *buf, size_t length) {
uint8_t hash[32];
SHA256_Buf(buf, length, hash);
char *id = calloc(65, sizeof(char));
for (int kH = 0; kH < 32; kH++)
sprintf(&(id[kH * 2]), "%02X", hash[kH]);
return id;
}
const char *Hex(const void *buf, size_t length) {
char *id = calloc(length*2+1, sizeof(char));
for (int kH = 0; kH < length; kH++)
sprintf(&(id[kH * 2]), "%02X", ((const uint8_t*)buf)[kH]);
return id;
}

52
MasterPassword/C/types.h Normal file
View File

@@ -0,0 +1,52 @@
//
// MPTypes.h
// MasterPassword
//
// Created by Maarten Billemont on 02/01/12.
// Copyright (c) 2012 Lyndir. All rights reserved.
//
typedef enum {
MPElementContentTypePassword,
MPElementContentTypeNote,
MPElementContentTypePicture,
} MPElementContentType;
typedef enum {
/** Generate the password. */
MPElementTypeClassGenerated = 1 << 4,
/** Store the password. */
MPElementTypeClassStored = 1 << 5,
} MPElementTypeClass;
typedef enum {
/** Export the key-protected content data. */
MPElementFeatureExportContent = 1 << 10,
/** Never export content. */
MPElementFeatureDevicePrivate = 1 << 11,
} MPElementFeature;
typedef enum {
MPElementTypeGeneratedMaximum = 0x0 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedLong = 0x1 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedMedium = 0x2 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedBasic = 0x4 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedShort = 0x3 | MPElementTypeClassGenerated | 0x0,
MPElementTypeGeneratedPIN = 0x5 | MPElementTypeClassGenerated | 0x0,
MPElementTypeStoredPersonal = 0x0 | MPElementTypeClassStored | MPElementFeatureExportContent,
MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate,
} MPElementType;
#ifdef DEBUG
#define trc(...) fprintf(stderr, __VA_ARGS__)
#else
#define trc(...) do {} while (0)
#endif
const MPElementType TypeWithName(const char *typeName);
const char *CipherForType(MPElementType type, uint8_t seedByte);
const char CharacterFromClass(char characterClass, uint8_t seedByte);
const char *IDForBuf(const void *buf, size_t length);
const char *Hex(const void *buf, size_t length);

View File

@@ -36,7 +36,7 @@
<dependency>
<groupId>net.sf.plist</groupId>
<artifactId>property-list</artifactId>
<version>svn-SNAPSHOT</version>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.lambdaworks</groupId>

View File

@@ -15,22 +15,25 @@ public enum MPElementType {
GeneratedMaximum( "Maximum Security Password", "Maximum", "20 characters, contains symbols.", MPElementTypeClass.Generated ),
GeneratedLong( "Long Password", "Long", "Copy-friendly, 14 characters, contains symbols.", MPElementTypeClass.Generated ),
GeneratedMedium( "Medium Password", "Medium", "Copy-friendly, 8 characters, contains symbols.", MPElementTypeClass.Generated ),
GeneratedShort( "Short Password", "Short", "Copy-friendly, 4 characters, no symbols.", MPElementTypeClass.Generated ),
GeneratedBasic( "Basic Password", "Basic", "8 characters, no symbols.", MPElementTypeClass.Generated ),
GeneratedShort( "Short Password", "Short", "Copy-friendly, 4 characters, no symbols.", MPElementTypeClass.Generated ),
GeneratedPIN( "PIN", "PIN", "4 numbers.", MPElementTypeClass.Generated ),
StoredPersonal( "Personal Password", "Personal", "AES-encrypted, exportable.", MPElementTypeClass.Stored, MPElementFeature.ExportContent ),
StoredDevicePrivate( "Device Private Password", "Private", "AES-encrypted, not exported.", MPElementTypeClass.Stored, MPElementFeature.DevicePrivate );
StoredPersonal( "Personal Password", "Personal", "AES-encrypted, exportable.", MPElementTypeClass.Stored,
MPElementFeature.ExportContent ),
StoredDevicePrivate( "Device Private Password", "Private", "AES-encrypted, not exported.", MPElementTypeClass.Stored,
MPElementFeature.DevicePrivate );
static final Logger logger = Logger.get( MPElementType.class );
private final MPElementTypeClass typeClass;
private final Set<MPElementFeature> typeFeatures;
private final String name;
private final String shortName;
private final MPElementTypeClass typeClass;
private final Set<MPElementFeature> typeFeatures;
private final String name;
private final String shortName;
private final String description;
MPElementType(final String name, final String shortName, final String description, final MPElementTypeClass typeClass, final MPElementFeature... typeFeatures) {
MPElementType(final String name, final String shortName, final String description, final MPElementTypeClass typeClass,
final MPElementFeature... typeFeatures) {
this.name = name;
this.shortName = shortName;
@@ -38,8 +41,9 @@ public enum MPElementType {
this.description = description;
ImmutableSet.Builder<MPElementFeature> typeFeaturesBuilder = ImmutableSet.builder();
for (final MPElementFeature typeFeature : typeFeatures)
for (final MPElementFeature typeFeature : typeFeatures) {
typeFeaturesBuilder.add( typeFeature );
}
this.typeFeatures = typeFeaturesBuilder.build();
}
@@ -68,12 +72,37 @@ public enum MPElementType {
return description;
}
/**
* @param name The full or short name of the type we want to look up. It is matched case insensitively.
*
* @return The type with the given name.
*/
public static MPElementType forName(final String name) {
for (final MPElementType type : values())
if (type.getName().equals( name ))
for (final MPElementType type : values()) {
if (type.getName().equalsIgnoreCase( name ) || type.getShortName().equalsIgnoreCase( name )) {
return type;
}
}
throw logger.bug( "Element type not known: %s", name );
}
/**
* @param typeClass The class for which we look up types.
*
* @return All types that support the given class.
*/
public static ImmutableSet<MPElementType> forClass(final MPElementTypeClass typeClass) {
ImmutableSet.Builder<MPElementType> types = ImmutableSet.builder();
for (final MPElementType type : values()) {
if (type.getTypeClass() == typeClass) {
types.add( type );
}
}
return types.build();
}
}

View File

@@ -32,10 +32,16 @@ public class MPTemplates extends MetaObject {
this.templates = templates;
}
public static MPTemplates load() {
return loadFromPList( "ciphers.plist" );
}
public static MPTemplates loadFromPList(final String templateResource) {
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
InputStream templateStream = Thread.currentThread().getContextClassLoader().getResourceAsStream( templateResource );
Preconditions.checkNotNull( templateStream, "Not found: %s", templateResource );
try {
NSObject plistObject = PropertyListParser.parse( templateStream );
Preconditions.checkState( NSDictionary.class.isAssignableFrom( plistObject.getClass() ) );
@@ -98,6 +104,6 @@ public class MPTemplates extends MetaObject {
public static void main(final String... arguments) {
loadFromPList( "templates.plist" );
load();
}
}

View File

@@ -31,7 +31,7 @@ public abstract class MasterPassword {
private static final ByteOrder MP_byteOrder = ByteOrder.BIG_ENDIAN;
private static final MessageDigests MP_hash = MessageDigests.SHA256;
private static final MessageAuthenticationDigests MP_mac = MessageAuthenticationDigests.HmacSHA256;
private static final MPTemplates templates = MPTemplates.loadFromPList( "templates.plist" );
private static final MPTemplates templates = MPTemplates.load();
public static byte[] keyForPassword(final String password, final String username) {

View File

@@ -0,0 +1 @@
../../../../../../MasterPassword/Resources/Data/ciphers.plist

View File

@@ -1 +0,0 @@
../../../../../../Resources/ciphers.plist

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lyndir.lhunath.masterpassword" android:versionCode="1" android:versionName="GIT-SNAPSHOT">
<uses-sdk android:minSdkVersion="8"
android:targetSdkVersion="16" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".HelloAndroidActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,3 @@
# File used by Eclipse to determine the target system
# Project target.
target=android-16

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- PROJECT METADATA -->
<parent>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<artifactId>masterpassword</artifactId>
<version>GIT-SNAPSHOT</version>
</parent>
<name>Master Password Android</name>
<description>An Android application to the Master Password algorithm</description>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<artifactId>masterpassword-android</artifactId>
<packaging>apk</packaging>
<!-- BUILD CONFIGURATION -->
<build>
<plugins>
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<!--configuration>
<proguard>
<skip>false</skip>
<config>proguard.cfg</config>
</proguard>
</configuration-->
</plugin>
</plugins>
</build>
<!-- DEPENDENCY MANAGEMENT -->
<dependencies>
<!-- PROJECT REFERENCES -->
<dependency>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<artifactId>masterpassword-algorithm</artifactId>
<version>GIT-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>com.google.android</groupId>
<artifactId>android</artifactId>
<version>4.1.1.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,5 @@
-ignorewarnings
-dontoptimize
-dontobfuscate
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
</LinearLayout>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello masterpassword-android!</string>
<string name="app_name">masterpassword-android</string>
</resources>

View File

@@ -0,0 +1,25 @@
package com.lyndir.lhunath.masterpassword;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
public class HelloAndroidActivity extends Activity {
private static String TAG = "masterpassword-android";
/**
* Called when the activity is first created.
* @param savedInstanceState If the activity is being re-initialized after
* previously being shut down then this Bundle contains the data it most
* recently supplied in onSaveInstanceState(Bundle). <b>Note: Otherwise it is null.</b>
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "onCreate");
setContentView(R.layout.main);
}
}

View File

@@ -29,30 +29,49 @@
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.lyndir.lhunath.masterpassword.CLI</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>prepare-package</id>
<phase>prepare-package</phase>
<configuration>
<target>
<chmod file="${project.build.directory}/install" perm="755"/>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.4</version>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
<goal>shade</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.lyndir.lhunath.masterpassword.CLI</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>

View File

@@ -8,10 +8,6 @@
<logger name="com.lyndir" level="TRACE" />
<!--
<logger name="org.apache.wicket" level="DEBUG" />
-->
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env bash
#
# Install the Master Password CLI tool.
set -e
cd "${BASH_SOURCE%/*}"
source bashlib
inf "This will install the mpw tool."
# Try to guess then ask for the bin dir to install to.
IFS=: read -a paths <<< "$PATH"
if inArray ~/bin "${paths[@]}"; then
bindir=~/bin
elif inArray ~/.bin "${paths[@]}"; then
bindir=~/.bin
elif inArray /usr/local/bin "${paths[@]}"; then
bindir=/usr/local/bin
else
bindir=~/bin
fi
bindir=$(ask -d "$bindir" "What bin directory should I install to?")
[[ -d "$bindir" ]] || mkdir "$bindir" || ftl 'Cannot create missing bin directory: %s' "$bindir" || exit
[[ -w "$bindir" ]] || ftl 'Cannot write to bin directory: %s' "$bindir" || exit
# Try to guess then ask for the share dir to install to.
sharedir=$(cd -P "$bindir/.."; [[ $bindir = */.bin ]] && printf '%s/.share' "$PWD" || printf '%s/share' "$PWD")
sharedir=$(ask -d "$sharedir" "What share directory should I install to?")
[[ -d "$sharedir" ]] || mkdir "$sharedir" || ftl 'Cannot create missing share directory: %s' "$sharedir" || exit
[[ -w "$sharedir" ]] || ftl 'Cannot write to share directory: %s' "$sharedir" || exit
# Install Master Password.
sharepath=$sharedir/masterpassword
mkdir -p "$sharepath"
cp -a "masterpassword-cli-"*".jar" bashlib mpw "$sharepath"
ex -c "%s~%SHAREPATH%~$sharepath~g|x" "$sharepath/mpw"
ln -sf "$sharepath/mpw" "$bindir/mpw"
chmod +x "$sharepath/mpw"
[[ ! -e "$bindir/bashlib" ]] && ln -s "$sharepath/bashlib" "$bindir/bashlib" ||:
# Convenience bash function.
inf "Installation successful!"
echo
inf "To improve usability, you can install an mpw function in your bash shell."
inf "This function adds the following features:"
inf " - Ask the Master Password once, remember in the shell."
inf " - Automatically put the password in the clipboard (some platforms)."
echo
inf "To do this you need the following function in ~/.bashrc:\n%s" "$(<mpw.bashrc)"
echo
inf "We can do this for you automatically now."
if ask -c Y!n "Append the mpw function to your .bashrc?"; then
cat mpw.bashrc >> ~/.bashrc
inf "Done! Don't forget to run '%s' to apply the changes!" "source ~/.bashrc"
fi
echo
inf "To begin using Master Password, type: mpw [site name]"

View File

@@ -1,4 +1,9 @@
#!/usr/bin/env bash
cd "${BASH_SOURCE[0]%/*}"
java -jar masterpassword-cli-GIT-SNAPSHOT.jar "$@"
# Uncomment this to set your user name. Master Password will no longer ask you for a user name.
# export MP_USERNAME="Robert Lee Mitchell"
# Uncomment this to hardcode your master password. Make sure this file's permissions are tight. Master Password will not ask you for your master password anymore. This is probably not a good idea.
# export MP_PASSWORD="banana colored duckling"
cd "%SHAREPATH%"
exec java -jar masterpassword-cli-GIT-SNAPSHOT.jar "$@"

View File

@@ -0,0 +1,15 @@
source bashlib
mpw() {
_nocopy() { echo >&2 "$(cat)"; }
_copy() { "$(type -P pbcopy || type -P xclip || echo _nocopy)"; }
# Empty the clipboard
:| _copy 2>/dev/null
# Ask for the user's name and password if not yet known.
MP_USERNAME=${MP_USERNAME:-$(ask -s 'Your Full Name:')}
MP_PASSWORD=${MP_PASSWORD:-$(ask -s 'Master Password:')}
# Start Master Password and copy the output.
printf %s "$(MP_USERNAME=$MP_USERNAME MP_PASSWORD=$MP_PASSWORD command mpw "$@")" | _copy
}

View File

@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- PROJECT METADATA -->
<parent>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<artifactId>masterpassword</artifactId>
<version>GIT-SNAPSHOT</version>
</parent>
<name>Master Password GUI</name>
<description>A GUI interface to the Master Password algorithm</description>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<artifactId>masterpassword-gui</artifactId>
<packaging>jar</packaging>
<!-- BUILD CONFIGURATION -->
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.lyndir.lhunath.masterpassword.GUI</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- DEPENDENCY MANAGEMENT -->
<dependencies>
<!-- PROJECT REFERENCES -->
<dependency>
<groupId>com.lyndir.lhunath.masterpassword</groupId>
<artifactId>masterpassword-algorithm</artifactId>
<version>GIT-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,32 @@
package com.lyndir.lhunath.masterpassword;
import com.apple.eawt.*;
/**
* @author lhunath, 2014-06-10
*/
public class AppleGUI extends GUI {
public AppleGUI() {
Application application = Application.getApplication();
application.addAppEventListener( new AppForegroundListener() {
@Override
public void appMovedToBackground(AppEvent.AppForegroundEvent arg0) {
}
@Override
public void appRaisedToForeground(AppEvent.AppForegroundEvent arg0) {
open();
}
} );
application.addAppEventListener( new AppReOpenedListener() {
@Override
public void appReOpened(AppEvent.AppReOpenedEvent arg0) {
open();
}
} );
}
}

View File

@@ -0,0 +1,48 @@
package com.lyndir.lhunath.masterpassword;
import com.google.common.io.Resources;
import java.awt.*;
import javax.swing.*;
/**
* @author lhunath, 2014-06-11
*/
public abstract class AuthenticationPanel extends JPanel {
protected final UnlockFrame unlockFrame;
public AuthenticationPanel(final UnlockFrame unlockFrame) {
this.unlockFrame = unlockFrame;
setLayout( new BoxLayout( this, BoxLayout.PAGE_AXIS ) );
// Avatar
add( Box.createVerticalGlue() );
add( new JLabel( Res.avatar(0) ) {
@Override
public Dimension getMaximumSize() {
return new Dimension( Integer.MAX_VALUE, Integer.MAX_VALUE );
}
} );
add( Box.createVerticalGlue() );
}
protected void updateUser(boolean repack) {
unlockFrame.setUser( getUser() );
validate();
if (repack)
unlockFrame.repack();
}
protected abstract User getUser();
public Component getFocusComponent() {
return null;
}
public String getHelpText() {
return null;
}
}

View File

@@ -0,0 +1,164 @@
package com.lyndir.lhunath.masterpassword;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.io.CharStreams;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.Iterator;
import java.util.NoSuchElementException;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
/**
* @author lhunath, 2014-06-11
*/
public class ConfigAuthenticationPanel extends AuthenticationPanel implements ItemListener, ActionListener, DocumentListener {
private final JComboBox userField;
private final JLabel masterPasswordLabel;
private final JPasswordField masterPasswordField;
public ConfigAuthenticationPanel(final UnlockFrame unlockFrame) {
// User
super( unlockFrame );
JLabel userLabel = new JLabel( "User:" );
userLabel.setAlignmentX( LEFT_ALIGNMENT );
userLabel.setHorizontalAlignment( SwingConstants.CENTER );
userLabel.setVerticalAlignment( SwingConstants.BOTTOM );
add( userLabel );
userField = new JComboBox<User>( new DefaultComboBoxModel<>( readConfigUsers() ) ) {
@Override
public Dimension getMaximumSize() {
return new Dimension( Integer.MAX_VALUE, getPreferredSize().height );
}
};
userField.setAlignmentX( LEFT_ALIGNMENT );
userField.addItemListener( this );
userField.addActionListener( this );
add( userField );
// Master Password
masterPasswordLabel = new JLabel( "Master Password:" );
masterPasswordLabel.setAlignmentX( Component.LEFT_ALIGNMENT );
masterPasswordLabel.setHorizontalAlignment( SwingConstants.CENTER );
masterPasswordLabel.setVerticalAlignment( SwingConstants.BOTTOM );
add( masterPasswordLabel );
masterPasswordField = new JPasswordField() {
@Override
public Dimension getMaximumSize() {
return new Dimension( Integer.MAX_VALUE, getPreferredSize().height );
}
};
masterPasswordField.setAlignmentX( Component.LEFT_ALIGNMENT );
masterPasswordField.addActionListener( this );
masterPasswordField.getDocument().addDocumentListener( this );
add( masterPasswordField );
}
@Override
public Component getFocusComponent() {
return masterPasswordField.isVisible()? masterPasswordField: null;
}
@Override
protected void updateUser(boolean repack) {
boolean masterPasswordMissing = userField.getSelectedItem() == null || !((User) userField.getSelectedItem()).hasKey();
if (masterPasswordField.isVisible() != masterPasswordMissing) {
masterPasswordLabel.setVisible( masterPasswordMissing );
masterPasswordField.setVisible( masterPasswordMissing );
repack = true;
}
super.updateUser( repack );
}
@Override
protected User getUser() {
User selectedUser = (User) userField.getSelectedItem();
if (selectedUser.hasKey()) {
return selectedUser;
}
return new User( selectedUser.getName(), new String( masterPasswordField.getPassword() ) );
}
public String getHelpText() {
return "Reads users from ~/.mpw, the following syntax applies:\nUser Name:masterpassword"
+ "\n\nEnsure the file's permissions make it only readable by you!";
}
public static boolean hasConfigUsers() {
return new File( System.getProperty( "user.home" ), ".mpw" ).canRead();
}
private User[] readConfigUsers() {
ImmutableList.Builder<User> users = ImmutableList.builder();
File mpwConfig = new File( System.getProperty( "user.home" ), ".mpw" );
try (FileReader mpwReader = new FileReader( mpwConfig )) {
for (String line : CharStreams.readLines( mpwReader )) {
if (line.startsWith( "#" ) || line.startsWith( "//" ) || line.isEmpty()) {
continue;
}
Iterator<String> fields = Splitter.on( ':' ).limit( 2 ).split( line ).iterator();
String userName = fields.next(), masterPassword = fields.next();
users.add( new User( userName, masterPassword ) );
}
return Iterables.toArray( users.build(), User.class );
}
catch (FileNotFoundException e) {
JOptionPane.showMessageDialog( this, "First create the config file at:\n" + mpwConfig.getAbsolutePath() +
"\n\nIt should contain a line for each user of the following format:" +
"\nUser Name:masterpassword" +
"\n\nEnsure the file's permissions make it only readable by you!", //
"Config File Not Found", JOptionPane.WARNING_MESSAGE );
return new User[0];
}
catch (IOException | NoSuchElementException e) {
e.printStackTrace();
String error = ifNotNullElse( e.getLocalizedMessage(), ifNotNullElse( e.getMessage(), e.toString() ) );
JOptionPane.showMessageDialog( this, //
"Problem reading config file:\n" + mpwConfig.getAbsolutePath() //
+ "\n\n" + error, //
"Config File Not Readable", JOptionPane.WARNING_MESSAGE );
return new User[0];
}
}
@Override
public void itemStateChanged(final ItemEvent e) {
updateUser( false );
}
@Override
public void actionPerformed(final ActionEvent e) {
updateUser( false );
unlockFrame.trySignIn( userField );
}
@Override
public void insertUpdate(final DocumentEvent e) {
updateUser( false );
}
@Override
public void removeUpdate(final DocumentEvent e) {
updateUser( false );
}
@Override
public void changedUpdate(final DocumentEvent e) {
updateUser( false );
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2008, Maarten Billemont
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.lyndir.lhunath.masterpassword;
import com.google.common.base.Optional;
import com.lyndir.lhunath.opal.system.util.TypeUtils;
import java.io.IOException;
import javax.swing.*;
/**
* <p> <i>Jun 10, 2008</i> </p>
*
* @author mbillemo
*/
public class GUI implements UnlockFrame.SignInCallback {
private UnlockFrame unlockFrame = new UnlockFrame( this );
private PasswordFrame passwordFrame;
public static void main(final String[] args)
throws IOException {
// Apple
Optional<? extends GUI> appleGUI = TypeUtils.newInstance( AppleGUI.class );
if (appleGUI.isPresent()) {
appleGUI.get().open();
return;
}
// All others
new GUI().open();
}
void open() {
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
if (passwordFrame == null) {
unlockFrame.setVisible( true );
} else {
passwordFrame.setVisible( true );
}
}
} );
}
@Override
public boolean signedIn(final User user) {
if (!user.hasKey()) {
return false;
}
user.getKey();
passwordFrame = new PasswordFrame( user );
open();
return true;
}
}

View File

@@ -0,0 +1,175 @@
package com.lyndir.lhunath.masterpassword;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.collect.Iterables;
import com.lyndir.lhunath.masterpassword.util.Components;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
/**
* @author lhunath, 2014-06-08
*/
public class PasswordFrame extends JFrame implements DocumentListener {
private final User user;
private final JTextField siteNameField;
private final JComboBox<MPElementType> siteTypeField;
private final JSpinner siteCounterField;
private final JLabel passwordLabel;
public PasswordFrame(User user)
throws HeadlessException {
super( "Master Password" );
this.user = user;
JLabel label;
setDefaultCloseOperation( DISPOSE_ON_CLOSE );
setContentPane( new JPanel( new BorderLayout( 20, 20 ) ) {
{
setBorder( new EmptyBorder( 20, 20, 20, 20 ) );
}
} );
// User
add( label = new JLabel( strf( "Generating passwords for: %s", user.getName() ) ), BorderLayout.NORTH );
label.setAlignmentX( LEFT_ALIGNMENT );
// Site
JPanel sitePanel = new JPanel();
sitePanel.setLayout( new BoxLayout( sitePanel, BoxLayout.PAGE_AXIS ) );
sitePanel.setBorder( new CompoundBorder( new EtchedBorder( EtchedBorder.RAISED ), new EmptyBorder( 8, 8, 8, 8 ) ) );
add( sitePanel, BorderLayout.CENTER );
// Site Name
sitePanel.add( label = new JLabel( "Site Name:", JLabel.LEADING ) );
label.setAlignmentX( LEFT_ALIGNMENT );
sitePanel.add( siteNameField = new JTextField() {
@Override
public Dimension getMaximumSize() {
return new Dimension( Integer.MAX_VALUE, getPreferredSize().height );
}
} );
siteNameField.setAlignmentX( LEFT_ALIGNMENT );
siteNameField.getDocument().addDocumentListener( this );
siteNameField.addActionListener( new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
updatePassword( new PasswordCallback() {
@Override
public void passwordGenerated(final String siteName, final String sitePassword) {
StringSelection clipboardContents = new StringSelection( sitePassword );
Toolkit.getDefaultToolkit().getSystemClipboard().setContents( clipboardContents, null );
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
dispose();
}
} );
}
} );
}
} );
// Site Type & Counter
MPElementType[] types = Iterables.toArray( MPElementType.forClass( MPElementTypeClass.Generated ), MPElementType.class );
JComponent siteSettings = Components.boxLayout( BoxLayout.LINE_AXIS, //
siteTypeField = new JComboBox<>( types ), //
siteCounterField = new JSpinner(
new SpinnerNumberModel( 1, 1, Integer.MAX_VALUE, 1 ) ) {
@Override
public Dimension getMaximumSize() {
return new Dimension( 20, getPreferredSize().height );
}
} );
siteSettings.setAlignmentX( LEFT_ALIGNMENT );
sitePanel.add( siteSettings );
siteTypeField.setAlignmentX( LEFT_ALIGNMENT );
siteTypeField.setAlignmentY( CENTER_ALIGNMENT );
siteTypeField.setSelectedItem( MPElementType.GeneratedLong );
siteTypeField.addItemListener( new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent e) {
updatePassword( null );
}
} );
siteCounterField.setAlignmentX( RIGHT_ALIGNMENT );
siteCounterField.setAlignmentY( CENTER_ALIGNMENT );
siteCounterField.addChangeListener( new ChangeListener() {
@Override
public void stateChanged(final ChangeEvent e) {
updatePassword( null );
}
} );
// Password
add( passwordLabel = new JLabel( " ", JLabel.CENTER ), BorderLayout.SOUTH );
passwordLabel.setAlignmentX( LEFT_ALIGNMENT );
passwordLabel.setFont( Res.sourceCodeProBlack().deriveFont( 40f ) );
pack();
setMinimumSize( getSize() );
setPreferredSize( new Dimension( 600, getSize().height ) );
pack();
setLocationByPlatform( true );
setLocationRelativeTo( null );
}
private void updatePassword(final PasswordCallback callback) {
final MPElementType siteType = (MPElementType) siteTypeField.getSelectedItem();
final String siteName = siteNameField.getText();
final int siteCounter = (Integer) siteCounterField.getValue();
if (siteType.getTypeClass() != MPElementTypeClass.Generated || siteName == null || siteName.isEmpty() || !user.hasKey()) {
passwordLabel.setText( null );
return;
}
Res.execute( new Runnable() {
@Override
public void run() {
final String sitePassword = MasterPassword.generateContent( siteType, siteName, user.getKey(), siteCounter );
if (callback != null) {
callback.passwordGenerated( siteName, sitePassword );
}
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
passwordLabel.setText( sitePassword );
}
} );
}
} );
}
@Override
public void insertUpdate(final DocumentEvent e) {
updatePassword( null );
}
@Override
public void removeUpdate(final DocumentEvent e) {
updatePassword( null );
}
@Override
public void changedUpdate(final DocumentEvent e) {
updatePassword( null );
}
interface PasswordCallback {
void passwordGenerated(String siteName, String sitePassword);
}
}

View File

@@ -0,0 +1,120 @@
package com.lyndir.lhunath.masterpassword;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.ifNotNullElse;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
import com.google.common.base.Throwables;
import com.google.common.io.Resources;
import com.lyndir.lhunath.opal.system.logging.Logger;
import java.awt.*;
import java.awt.image.ImageObserver;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.*;
/**
* @author lhunath, 2014-06-11
*/
public abstract class Res {
private static final ExecutorService executor = Executors.newSingleThreadExecutor();
private static final Logger logger = Logger.get( Res.class );
private static Font sourceCodeProBlack;
public static void execute(final Runnable job) {
executor.submit( new Runnable() {
@Override
public void run() {
try {
job.run();
}
catch (Throwable t) {
logger.err( t, "Unexpected: %s", t.getLocalizedMessage() );
}
}
} );
}
public static Icon iconQuestion() {
return new RetinaIcon( Resources.getResource( "media/icon_question@2x.png" ) );
}
public static Icon avatar(final int index) {
return new RetinaIcon( Resources.getResource( strf( "media/avatar-%d@2x.png", index ) ) );
}
public static Font sourceCodeProBlack() {
try {
URL resource = Resources.getResource( "fonts/SourceCodePro-Bold.otf" );
Font font = Font.createFont( Font.TRUETYPE_FONT, resource.openStream() );
return sourceCodeProBlack != null? sourceCodeProBlack: //
(sourceCodeProBlack = font);
}
catch (FontFormatException | IOException e) {
throw Throwables.propagate( e );
}
}
private static final class RetinaIcon extends ImageIcon {
private static final Pattern scalePattern = Pattern.compile(".*@(\\d+)x.[^.]+$");
private final float scale;
public RetinaIcon(final URL url) {
super( url );
Matcher scaleMatcher = scalePattern.matcher( url.getPath() );
if (scaleMatcher.matches())
scale = Float.parseFloat( scaleMatcher.group( 1 ) );
else
scale = 1;
}
//private static URL retinaURL(final URL url) {
// try {
// final boolean[] isRetina = new boolean[1];
// new apple.awt.CImage.HiDPIScaledImage(1,1, BufferedImage.TYPE_INT_ARGB) {
// @Override
// public void drawIntoImage(BufferedImage image, float v) {
// isRetina[0] = v > 1;
// }
// };
// return isRetina[0];
// } catch (Throwable e) {
// e.printStackTrace();
// return url;
// }
//}
@Override
public int getIconWidth() {
return (int) (super.getIconWidth() / scale);
}
@Override
public int getIconHeight() {
return (int) (super.getIconHeight() / scale);
}
public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
ImageObserver observer = ifNotNullElse( getImageObserver(), c );
Image image = getImage();
int width = image.getWidth( observer );
int height = image.getHeight( observer );
final Graphics2D g2d = (Graphics2D) g.create( x, y, width, height );
g2d.scale( 1 / scale, 1 / scale );
g2d.drawImage( image, 0, 0, observer );
g2d.scale( 1, 1 );
g2d.dispose();
}
}
}

View File

@@ -0,0 +1,89 @@
package com.lyndir.lhunath.masterpassword;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
/**
* @author lhunath, 2014-06-11
*/
public class TextAuthenticationPanel extends AuthenticationPanel implements DocumentListener, ActionListener {
private final JTextField userNameField;
private final JPasswordField masterPasswordField;
public TextAuthenticationPanel(final UnlockFrame unlockFrame) {
// User Name
super( unlockFrame );
JLabel userNameLabel = new JLabel( "User Name:" );
userNameLabel.setAlignmentX( Component.LEFT_ALIGNMENT );
userNameLabel.setHorizontalAlignment( SwingConstants.CENTER );
userNameLabel.setVerticalAlignment( SwingConstants.BOTTOM );
add( userNameLabel );
userNameField = new JTextField() {
@Override
public Dimension getMaximumSize() {
return new Dimension( Integer.MAX_VALUE, getPreferredSize().height );
}
};
userNameField.setAlignmentX( Component.LEFT_ALIGNMENT );
userNameField.getDocument().addDocumentListener( this );
userNameField.addActionListener( this );
add( userNameField );
// Master Password
JLabel masterPasswordLabel = new JLabel( "Master Password:" );
masterPasswordLabel.setAlignmentX( Component.LEFT_ALIGNMENT );
masterPasswordLabel.setHorizontalAlignment( SwingConstants.CENTER );
masterPasswordLabel.setVerticalAlignment( SwingConstants.BOTTOM );
add( masterPasswordLabel );
masterPasswordField = new JPasswordField() {
@Override
public Dimension getMaximumSize() {
return new Dimension( Integer.MAX_VALUE, getPreferredSize().height );
}
};
masterPasswordField.setAlignmentX( Component.LEFT_ALIGNMENT );
masterPasswordField.addActionListener( this );
masterPasswordField.getDocument().addDocumentListener( this );
add( masterPasswordField );
}
@Override
public Component getFocusComponent() {
return userNameField;
}
@Override
protected User getUser() {
return new User( userNameField.getText(), new String( masterPasswordField.getPassword() ) );
}
@Override
public void insertUpdate(final DocumentEvent e) {
updateUser( false );
}
@Override
public void removeUpdate(final DocumentEvent e) {
updateUser( false );
}
@Override
public void changedUpdate(final DocumentEvent e) {
updateUser( false );
}
@Override
public void actionPerformed(final ActionEvent e) {
updateUser( false );
unlockFrame.trySignIn( userNameField, masterPasswordField );
}
}

View File

@@ -0,0 +1,175 @@
package com.lyndir.lhunath.masterpassword;
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
import com.lyndir.lhunath.masterpassword.util.Components;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
/**
* @author lhunath, 2014-06-08
*/
public class UnlockFrame extends JFrame {
private final SignInCallback signInCallback;
private final JPanel root;
private final JButton signInButton;
private final JPanel authenticationContainer;
private boolean useConfig;
public User user;
public UnlockFrame(final SignInCallback signInCallback)
throws HeadlessException {
super( "Unlock Master Password" );
this.signInCallback = signInCallback;
setDefaultCloseOperation( DISPOSE_ON_CLOSE );
setContentPane( root = new JPanel( new BorderLayout( 20, 20 ) ) );
root.setBorder( new EmptyBorder( 20, 20, 20, 20 ) );
authenticationContainer = new JPanel();
authenticationContainer.setLayout( new BoxLayout( authenticationContainer, BoxLayout.PAGE_AXIS ) );
authenticationContainer.setBorder( new CompoundBorder( new EtchedBorder( EtchedBorder.RAISED ), new EmptyBorder( 8, 8, 8, 8 ) ) );
add( authenticationContainer );
// Sign In
root.add( Components.boxLayout( BoxLayout.LINE_AXIS, Box.createGlue(), signInButton = new JButton( "Sign In" ), Box.createGlue() ),
BorderLayout.SOUTH );
signInButton.setAlignmentX( LEFT_ALIGNMENT );
signInButton.addActionListener( new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
trySignIn();
}
} );
useConfig = ConfigAuthenticationPanel.hasConfigUsers();
createAuthenticationPanel();
setLocationByPlatform( true );
setLocationRelativeTo( null );
}
protected void repack() {
setPreferredSize( null );
pack();
setMinimumSize( getSize() );
setPreferredSize( new Dimension( 300, 300 ) );
pack();
}
private void createAuthenticationPanel() {
authenticationContainer.removeAll();
final AuthenticationPanel authenticationPanel;
if (useConfig) {
authenticationPanel = new ConfigAuthenticationPanel( this );
} else {
authenticationPanel = new TextAuthenticationPanel( this );
}
authenticationPanel.updateUser( false );
authenticationContainer.add( authenticationPanel, BorderLayout.CENTER );
final JCheckBox typeCheckBox = new JCheckBox( "Use Config File" );
typeCheckBox.setAlignmentX( LEFT_ALIGNMENT );
typeCheckBox.setSelected( useConfig );
typeCheckBox.addItemListener( new ItemListener() {
@Override
public void itemStateChanged(final ItemEvent e) {
useConfig = typeCheckBox.isSelected();
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
createAuthenticationPanel();
}
} );
}
} );
JButton typeHelp = new JButton( Res.iconQuestion() );
typeHelp.setMargin( new Insets( 0, 0, 0, 0 ) );
typeHelp.setBackground( Color.red );
typeHelp.setAlignmentX( RIGHT_ALIGNMENT );
typeHelp.setBorder( null );
typeHelp.addActionListener( new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
JOptionPane.showMessageDialog( UnlockFrame.this, authenticationPanel.getHelpText(), "Help",
JOptionPane.INFORMATION_MESSAGE );
}
} );
if (authenticationPanel.getHelpText() == null) {
typeHelp.setVisible( false );
}
JComponent typePanel = Components.boxLayout( BoxLayout.LINE_AXIS, typeCheckBox, Box.createGlue(), typeHelp );
typePanel.setAlignmentX( Component.LEFT_ALIGNMENT );
authenticationContainer.add( typePanel );
checkSignIn();
validate();
repack();
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
ifNotNullElse( authenticationPanel.getFocusComponent(), signInButton ).requestFocusInWindow();
}
} );
}
void setUser(User user) {
this.user = user;
checkSignIn();
}
boolean checkSignIn() {
boolean enabled = user != null && !user.getName().isEmpty() && user.hasKey();
signInButton.setEnabled( enabled );
return enabled;
}
void trySignIn(final JComponent... signInComponents) {
if (!checkSignIn()) {
return;
}
for (JComponent signInComponent : signInComponents) {
signInComponent.setEnabled( false );
}
signInButton.setEnabled( false );
signInButton.setText( "Signing In..." );
Res.execute( new Runnable() {
@Override
public void run() {
final boolean success = signInCallback.signedIn( user );
SwingUtilities.invokeLater( new Runnable() {
@Override
public void run() {
if (success) {
dispose();
return;
}
signInButton.setText( "Sign In" );
for (JComponent signInComponent : signInComponents) {
signInComponent.setEnabled( true );
}
checkSignIn();
}
} );
}
} );
}
interface SignInCallback {
boolean signedIn(User user);
}
}

View File

@@ -0,0 +1,49 @@
package com.lyndir.lhunath.masterpassword;
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
/**
* @author lhunath, 2014-06-08
*/
public class User {
private final String name;
private final String masterPassword;
private byte[] key;
public User(final String name, final String masterPassword) {
this.name = name;
this.masterPassword = masterPassword;
}
public String getName() {
return name;
}
public boolean hasKey() {
return key != null || (masterPassword != null && !masterPassword.isEmpty());
}
public byte[] getKey() {
if (key == null) {
if (!hasKey()) {
throw new IllegalStateException( strf( "Master password unknown for user: %s", name ) );
} else {
key = MasterPassword.keyForPassword( masterPassword, name );
}
}
return key;
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public String toString() {
return name;
}
}

Some files were not shown because too many files have changed in this diff Show More