355 Commits
V1.4 ... master

Author SHA1 Message Date
Geoffroy BONNEVILLE
2ebd952982 Minor refactoring 2021-06-15 15:33:15 +02:00
Geoffroy BONNEVILLE
5387f1c5a1 Fix navigation issue
Applied some syntax style
2021-06-15 10:16:58 +02:00
Geoffroy BONNEVILLE
77b5927d46 Refactor NavigationHelper 2021-06-14 19:38:48 +02:00
Geoffroy BONNEVILLE
e917bd249f Unregister the messenger everywhere on unload/navigate from 2021-05-10 20:28:13 +02:00
Geoffroy BONNEVILLE
dec59b2378 Update certificates 2021-04-30 17:18:50 +02:00
Geoffroy BONNEVILLE
4153dc7344 Update store association
Update CommonServiceLocator
2021-04-30 16:37:54 +02:00
Geoffroy BONNEVILLE
a589e1c5b7 Fix multiple messenger instance registrations in entry view models 2021-04-27 15:48:45 +02:00
Geoffroy BONNEVILLE
fc8dde32cd Remove sonarqube files from source control 2020-06-26 15:37:10 +02:00
Geoffroy BONNEVILLE
80a255aa6f Restored stackpanel in breadcrumb 2020-06-26 15:21:06 +02:00
Geoffroy BONNEVILLE
1f06bf3ba7 Root group up button disabled
Going back to home when opening a file from explorer no longer displays open file
Inverted Breadcrumb order to avoid reordering items
Update release notes
Code cleanup
2020-06-26 01:16:44 +02:00
Geoffroy BONNEVILLE
7dcd5a4a57 Removed Breadcrumb service
Breadcrumb control handles breadcrumb status
Layout improvements
Added the ability to delete an entry from the group menu
2020-06-10 13:38:04 +02:00
Geoffroy BONNEVILLE
c62ed584dc New Breadcrumb user control
New Breadcrumb service
WIP icons and back button behavior
2020-06-09 20:18:17 +02:00
d6b17fe696 WIP Return of the Breadcrumb
Entry Title field added as part of the entry page
Code cleanup
2020-06-08 19:17:11 +02:00
f477828628 Changed some observable collections types for HamburgerMenu binding (issue with WinRT 8.1)
Restored CollectionViewSource for recent (issue with WinRT 8.1)
Forbid horizontal scrolling in Main Menu
Fixed an incorrect SetupFocusAction target object binding
2020-06-08 14:16:54 +02:00
Geoffroy BONNEVILLE
4a0bc1cb86 Add ARM debug target 2020-06-08 11:52:12 +02:00
Geoffroy BONNEVILLE
4e7aca5517 CSV Import command created 2020-06-05 19:08:29 +02:00
Geoffroy BONNEVILLE
1f04f941c2 Corrected issue in color picker user control when changing history
Use of commands instead of events in code-behind
Some refactoring
2020-06-04 16:29:26 +02:00
Geoffroy BONNEVILLE
5c1dfa1b0e Update version to 1.20
Clicking new group button while collapsed will expand the menu
Use of space freed by hidden hamburger menu
2020-06-04 15:31:38 +02:00
Geoffroy BONNEVILLE
1c6fb0f2bb Removed useless collectionviewsource
Updated some packages
2020-06-02 15:57:14 +02:00
Geoffroy BONNEVILLE
e5b35dc6ab SemanticView zoomed out layout and design improvements 2020-06-02 13:16:36 +02:00
Geoffroy BONNEVILLE
ce48850566 Fix Sonar issues 2020-06-01 23:03:57 +02:00
Geoffroy BONNEVILLE
5d8d996f44 Working ColorPickerUserControl 2020-06-01 10:32:06 +02:00
Geoffroy BONNEVILLE
4000d51f70 Update PasswordLength property on password generation 2020-05-26 19:06:59 +02:00
Geoffroy BONNEVILLE
0c70b5146f Create entry history only if DB is open
Fix issues in entry field names
Entry field names cleanup and refactoring
2020-05-26 13:38:07 +02:00
Geoffroy BONNEVILLE
3ecee4a821 Fix ClipboardAction so that it only clears Clipboard when Window is active 2020-05-26 12:30:52 +02:00
Geoffroy BONNEVILLE
3d436c56fa Password generation button with display toggle and indicator is now a user control
SetCredentials user controls now uses PasswordGenerationBox user control
Some layout improvements in EntryDetailsPage
WIP Clipboard suspend issues
2020-05-25 19:23:32 +02:00
Geoffroy BONNEVILLE
0e05e3fbca Fix Sonar issues 2020-05-20 19:03:31 +02:00
Geoffroy BONNEVILLE
45b5ae5630 ColorPickerControl finally doesn't set database to dirty when there is an initial value 2020-05-20 17:40:06 +02:00
Geoffroy BONNEVILLE
643fb9a3f2 Working protected fields (warning: check performance) 2020-05-20 11:59:40 +02:00
Geoffroy BONNEVILLE
b7f8853ef2 WIP Protect/Unprotect Additional Field on selection 2020-05-18 22:20:31 +02:00
Geoffroy BONNEVILLE
9126307b4c Cryptography service now handles random byte generation
Protected strings are now protected in memory
2020-05-18 14:14:28 +02:00
Geoffroy BONNEVILLE
ceaf7dabd3 Fix Sonar issues 2020-05-14 17:06:39 +02:00
Geoffroy BONNEVILLE
7a2ce30512 Design improvements 2020-05-14 16:09:06 +02:00
Geoffroy BONNEVILLE
d497f69a5e Updated deleted text information
Improved dirty status detection (restored removed variable...)
This corrected history creation on navigation when entry deleted
2020-05-14 13:32:44 +02:00
Geoffroy BONNEVILLE
72e5bf4ee1 Added a cryptography service to encrypt protected information (unused atm)
Corrected a bug when deleting recycle bin
2020-05-14 12:05:05 +02:00
Geoffroy BONNEVILLE
2e01fa2212 Changed tooltip styles
Removed useless isdirty field in entry
When an app can't be saved on suspend, don't reopen it to avoid possible de-sync
2020-05-13 18:59:26 +02:00
Geoffroy BONNEVILLE
0adb44bc81 Some design changes
Again fixed open url bug
2020-05-13 15:14:58 +02:00
Geoffroy BONNEVILLE
d38d6461bd Updated Settings page
Added new settings (history and clipboard)
Renamed and moved Settings Vms
2020-05-13 13:50:33 +02:00
Geoffroy BONNEVILLE
7ac1595aaa Clipboard action now sets an expiration timer
WIP Max History count (back-end done, front-end todo)
2020-05-12 18:43:37 +02:00
Geoffroy BONNEVILLE
f8f7c19f65 Display a big database size warning
Auto rename additional field when it matches standard
Treated all fields as new Field class
Added the Is Protected property
2020-05-12 17:14:30 +02:00
Geoffroy BONNEVILLE
d6dc6a74a3 Groups can now also be manually reordered
Design improvements
2020-05-11 19:22:41 +02:00
Geoffroy BONNEVILLE
bb2b99ed66 Additional fields Add, Update and Delete work (too well)
SelectableListView works when programmatically setting selection
2020-05-11 10:53:14 +02:00
Geoffroy BONNEVILLE
71b6009a29 Remove some useless code (again)
Improve some visuals
2020-05-07 19:10:25 +02:00
Geoffroy BONNEVILLE
fbcc354809 Additional fields rendering done
Removed lots of unused classes
2020-05-07 16:01:59 +02:00
Geoffroy BONNEVILLE
e901afaf29 Attachment Add and Delete commands implemented 2020-05-07 12:11:12 +02:00
Geoffroy BONNEVILLE
ca04a6c8ee Entry page is now a Hub
EntryDetailVM and GroupDetailVM are now singleton
Read-only Additional fields and Attachments
2020-05-06 18:54:39 +02:00
Geoffroy BONNEVILLE
1488c3244f Better exception handling 2020-05-05 19:26:38 +02:00
Geoffroy BONNEVILLE
2e22a2bd92 Added some translations in file pickers
Corrected key file creation picker issue (any not allowed)
Fixed some Sonar issues
2020-05-05 17:32:07 +02:00
Geoffroy BONNEVILLE
8fb468358e Hamburger button state is now correct (no more double clicks) but it's a bit hacky
Changed Help tooltip location in New Database Settings page
Suggest Save As when opening DB when another is opened and there is a save error
2020-05-05 16:59:49 +02:00
Geoffroy BONNEVILLE
5ce0262318 TextBoxWithButton control correctly updates field value
Create Group now allows inline input of the group name
2020-05-05 15:27:34 +02:00
Geoffroy BONNEVILLE
2f30389f6c Big redesign (closer to Win10 UWP)
Replaced breadcrumb with Up button
Search button now integrated in top menu
Hamburger menu make better use of visual states
Better visual states changes when size changes
2020-05-04 20:56:19 +02:00
Geoffroy BONNEVILLE
b3c7683c12 Send a message on save to update commands can execute 2020-05-04 14:29:52 +02:00
Geoffroy BONNEVILLE
1e7662def7 Save error is now handled via Messenger instead of unhandled exception handler (which didn't work)
Save as actually works now
WIP Styles
Code cleanup
2020-05-04 12:48:27 +02:00
Geoffroy BONNEVILLE
97b10baedc Resuming correctly re-opens the previsouly opened database 2020-05-02 14:39:42 +02:00
Geoffroy BONNEVILLE
654bd6b4e5 Corrected some Sonar issues
Changed a little bit the Open and Set credentials User controls
2020-05-02 14:21:59 +02:00
Geoffroy BONNEVILLE
7b88461333 *BoxWithButton data binding actually work 2020-04-30 22:04:08 +02:00
Geoffroy BONNEVILLE
8de493f987 Username is now correctly persisted
Set credentials validation works as intended
Getting settings has default values
Add parent group in Move searchbox
Moving entries work as intended
Removed unreferenced code files
2020-04-30 19:40:48 +02:00
Geoffroy BONNEVILLE
e5353478f4 Corrected issue where entry information was not showing anymore 2020-04-30 16:39:39 +02:00
Geoffroy BONNEVILLE
1b981b00d5 Update credentials better looking 2020-04-30 15:32:42 +02:00
Geoffroy BONNEVILLE
d2814c6c67 OpenDatabase control now handles status changes with VisualStateManager instead of Vm
Opening DB shows a progress ring instead
2020-04-30 11:10:10 +02:00
Geoffroy BONNEVILLE
9fdc727787 Minor code cleanup 2020-04-29 19:20:10 +02:00
Geoffroy BONNEVILLE
14cd3ab57a WIP Windows 10
Dependencies finally installed
Removal of useless code
Big cleanup in XAML styles (override colors the correct way)
2020-04-29 16:39:20 +02:00
Geoffroy BONNEVILLE
d6529646a8 Split ViewModelLocator 2020-04-29 09:44:32 +02:00
Geoffroy BONNEVILLE
7917a8b388 Updated release notes
Moved ViewModelLocator
WIP ModernKeePass10
2020-04-28 20:14:18 +02:00
Geoffroy BONNEVILLE
b8e1bbd9d7 Move finally works
Sort entries and groups refresh page info
Stopped using breadcrumb user control - for now
Some refactoring
2020-04-28 18:54:37 +02:00
Geoffroy BONNEVILLE
f158e5aced Finally a nicer looking and working TextBoxWithButton (inspired from the SearchButton)
SearchBox field style improved
2020-04-28 15:20:47 +02:00
Geoffroy BONNEVILLE
8e06bf4bb0 Removed half-baked import feature for now
No views depend on services anymore
Dirty status fully handled by behavior
2020-04-27 11:14:29 +02:00
Geoffroy BONNEVILLE
59ab43ca9c Remove entry from mru when it does not exist anymore 2020-04-25 22:34:50 +02:00
Geoffroy BONNEVILLE
7778e45deb All VMs use viewmodellocator 2020-04-25 22:03:47 +02:00
Geoffroy BONNEVILLE
df973c5f62 StorageFile client more intelligent
Save is working again
2020-04-24 16:16:48 +02:00
Geoffroy BONNEVILLE
3967db41b3 Open from Explorer works again
Updated ModernKeePassLib
2020-04-24 15:52:46 +02:00
Geoffroy BONNEVILLE
eacb3b182e Database files are added to the mru instead of the fal
Simplify opening database workflow
Corrected opening from recent bug
2020-04-24 13:58:30 +02:00
Geoffroy BONNEVILLE
d211453553 WIP ViewModelLocator - Messenger and Recent issues
Refactoring
Code cleanup
2020-04-23 19:00:38 +02:00
Geoffroy BONNEVILLE
2b8f9bd5f0 WIP ViewModelLocator - Messenger and Recent issues
Refactoring
Code cleanup
2020-04-23 18:59:56 +02:00
Geoffroy BONNEVILLE
722790e5e4 Removed useless package 2020-04-22 19:22:36 +02:00
Geoffroy BONNEVILLE
a9ed588c9a Creation of a notification service 2020-04-22 18:12:28 +02:00
Geoffroy BONNEVILLE
61f5e9df0b Update master key works
Key file creation works
Code cleanup
2020-04-22 17:06:16 +02:00
Geoffroy BONNEVILLE
a7da427ded Create database works with new Vm
Refactoring
2020-04-22 16:21:47 +02:00
Geoffroy BONNEVILLE
a88051bc0c Restore Main and Settings Page
Entry and Group delete events converted to commands
Code cleanup
2020-04-22 11:58:06 +02:00
Geoffroy BONNEVILLE
1df9cbce1c WIP DeleteCommand
WIP DataContexts binding (Main and Settings are broken)
2020-04-21 19:12:26 +02:00
Geoffroy BONNEVILLE
0b19d8d50a Opening Databases now use a Messenger service 2020-04-21 17:13:39 +02:00
Geoffroy BONNEVILLE
004f1a35a8 Detect if current group is the recycle bin for entry and group creation 2020-04-21 13:39:53 +02:00
Geoffroy BONNEVILLE
ac66faa9e2 GroupDetailPage uses navigation service 2020-04-21 13:33:15 +02:00
Geoffroy BONNEVILLE
c81f8bc835 SavePage uses nav service 2020-04-21 13:14:56 +02:00
Geoffroy BONNEVILLE
a1085b6010 Add MVVM Light library
Updated nuget packages
2020-04-21 13:07:17 +02:00
Geoffroy BONNEVILLE
75f6e2f840 OpenDatabaseUserControl works 2020-04-21 11:26:02 +02:00
Geoffroy BONNEVILLE
310bd777b2 WIP Split composite key user control
Some refactoring
2020-04-20 20:02:43 +02:00
Geoffroy BONNEVILLE
73670e8689 Create a shared project with all Win App common files (8.1 and 10)
Finally use the dependency injected Resource Service
2020-04-17 16:56:07 +02:00
Geoffroy BONNEVILLE
2fb5b14085 Updating group raise SaveCommand can execute
No need to click twice on history menu
Skipped first history entry as it is the same as the current entry
Stored SaveException innerexception as it is read more than once
2020-04-16 19:43:17 +02:00
Geoffroy BONNEVILLE
f950564000 Update groups finally implemented
Code cleanup
2020-04-16 17:16:03 +02:00
Geoffroy BONNEVILLE
9befdc321a Entry history delete and restore work 2020-04-16 14:08:50 +02:00
Geoffroy BONNEVILLE
98ac418f62 WIP History
Restore from history works
2020-04-15 19:06:13 +02:00
Geoffroy BONNEVILLE
0063ef1977 Create entries and groups put them in Edit mode (as before)
Search now uses KeePassLib search
Code cleanup
2020-04-15 12:02:30 +02:00
Geoffroy BONNEVILLE
b66e79f97c History *works*
WIP on save on entry page doesn't show last change
2020-04-14 19:59:19 +02:00
Geoffroy BONNEVILLE
9603c1ff01 Icons work again
Colors work again
2020-04-14 17:49:29 +02:00
Geoffroy BONNEVILLE
3def21bc7d Restored title group and entries icons
Editing adds a visible border
2020-04-14 14:09:31 +02:00
Geoffroy BONNEVILLE
a2eba91a3b Added dirty behavior
Removed restore action (-> Move action wip)
Added additional check on DB size before auto saving
Code cleanup
2020-04-14 13:44:07 +02:00
Geoffroy BONNEVILLE
d972b6cb5a Added the option to close DB without saving
Changed the way recent files are retrieved
Stopped showing the DB Closed exception on suspend
Reordering entries works
Moved code from infra to application
Cleanup
2020-04-09 19:43:06 +02:00
Geoffroy BONNEVILLE
14fd4634db Entry icons now correctly show up
Auto create new recycle bin works correctly
2020-04-08 20:02:13 +02:00
Geoffroy BONNEVILLE
752e96884d Code cleanup (ter) 2020-04-08 16:38:38 +02:00
Geoffroy BONNEVILLE
1046110dd2 Code cleanup (bis) 2020-04-08 16:23:15 +02:00
Geoffroy BONNEVILLE
d1047a92ba Update build configurations 2020-04-08 15:52:25 +02:00
Geoffroy BONNEVILLE
009382ea03 Cleanup code 2020-04-08 15:27:40 +02:00
Geoffroy BONNEVILLE
4863eb9fae Create DB works correctly
Sample data moved to application
Tests updated (still not working - splat)
WIP
2020-04-07 17:29:03 +02:00
Geoffroy BONNEVILLE
1fa799bdf8 FileInfo overhaul
Opening DB works again
2020-04-07 12:48:18 +02:00
Geoffroy BONNEVILLE
56d93a5187 Moved application code to the Application layer
Imported Win10 project
Code cleanup
WIP - Use common UWP services for Win8.1 and Win10
2020-04-06 20:20:45 +02:00
Geoffroy BONNEVILLE
e795a8c3c4 Database settings now work properly 2020-04-03 18:14:44 +02:00
Geoffroy BONNEVILLE
b875f3c89d Adding entries and groups works again
Entry history almost fully functional
Some refactoring
2020-04-03 17:33:53 +02:00
Geoffroy BONNEVILLE
36aa8914fa Handle entities with id
No hierarchy is built anymore
WIP save issues after delete
2020-04-02 19:12:16 +02:00
Geoffroy BONNEVILLE
b61a9652d1 WIP change to ids 2020-04-01 19:37:30 +02:00
Geoffroy BONNEVILLE
57be6bb917 Build hierarchy instead of using Automapper
Add entities before removing them
2020-04-01 12:48:36 +02:00
Geoffroy BONNEVILLE
90c592d7ee Lots of bug corrections
WIP - still lots left
2020-03-31 19:19:02 +02:00
Geoffroy BONNEVILLE
e4bd788ed3 1st working version in clean arch
WIP Parent group mapping issues
2020-03-30 19:43:04 +02:00
Geoffroy BONNEVILLE
d1ba73ee9d Don't use mediator for App services (recent, resource, settings)
WIP in View models
2020-03-28 16:13:17 +01:00
Geoffroy BONNEVILLE
45fcf7e8ab Removed ModernKeePassLib dependency
Code cleanup
WIP on service replacement and VM use
2020-03-27 18:45:13 +01:00
Geoffroy BONNEVILLE
e3638c2f5c More commands/queries
WIP on XAML EntryVm and GroupVm
2020-03-27 13:27:29 +01:00
Geoffroy BONNEVILLE
22072bb2fe Most services are implemented as command/queries
Code cleanup
2020-03-26 19:04:51 +01:00
Geoffroy BONNEVILLE
903e7649e4 More queries/commands 2020-03-26 15:38:29 +01:00
Geoffroy BONNEVILLE
a17d6b05ae Added lots of commands
Simplified KeePass client
2020-03-26 12:25:22 +01:00
Geoffroy BONNEVILLE
4b1210f414 WIP 2020-03-24 19:14:34 +01:00
Geoffroy BONNEVILLE
f208e2d0b6 Correct package version installed
Dependency injection works
Project renaming
WIP replacement of services with CQRS
2020-03-24 17:31:34 +01:00
Geoffroy BONNEVILLE
ba8bbe045b Cleanup 2020-03-24 13:09:00 +01:00
Geoffroy BONNEVILLE
7e44d47065 WIP Clean Architecture
Windows 8.1 App Uses keepasslib v2.44 (temporarily)
2020-03-24 13:01:14 +01:00
Geoffroy BONNEVILLE
34cd4ca3d8 Allow any file type for key selection 2020-03-20 17:05:46 +01:00
638bfacadd Bug corrections 2018-09-12 16:49:01 +02:00
d341535d60 Corrected some tests
Minor code refactor
Main page now correctly shows save page even when opening a DB from Explorer
2018-09-12 12:58:32 +02:00
BONNEVILLE Geoffroy
38e2d1ac51 Updated store screenshots 2018-09-11 10:08:33 +02:00
BONNEVILLE Geoffroy
5b1039b81f Hid useless open from URL
Removed commented out code
2018-09-10 18:26:55 +02:00
BONNEVILLE Geoffroy
37deac2ab9 Basic CSV Import working 2018-09-10 17:29:52 +02:00
BONNEVILLE Geoffroy
34f6d4e793 Correct navigation to root group when creating new database 2018-09-10 11:25:57 +02:00
BONNEVILLE Geoffroy
bbae2c356a Changed implementation of sample data
Creating a new entry does not create an useless history value
WIP import data
2018-09-10 11:13:44 +02:00
deec19a60c Merge branch 'master' of https://geogeob.visualstudio.com/_git/ModernKeePass 2018-09-09 20:02:02 +02:00
b1167594db Finally corrected weird Windows 8 and RT bug
Refactor TopMenu User Control visibility with Visual State Manager
2018-09-09 20:01:56 +02:00
BONNEVILLE Geoffroy
0da6a5fc60 WIP Import mechanism 2018-09-07 18:16:40 +02:00
BONNEVILLE Geoffroy
549006036b Changed default icon from IntToSymbolConverter to a parameter
Filtered symbol list from drop down list to only show actually settable symbols
2018-09-06 18:30:30 +02:00
BONNEVILLE Geoffroy
6ed29e788c Sort menu default visibility set to Collapsed 2018-09-04 15:07:31 +02:00
BONNEVILLE Geoffroy
e437f65f83 Restored useless changes
Code cleanup
2018-08-03 17:41:52 +02:00
BONNEVILLE Geoffroy
6f96e698ec Created Import/Export page (stub)
Changed some dependency properties from Interfaces to implementations
Used CanExecute on Commands
2018-08-02 17:40:30 +02:00
BONNEVILLE Geoffroy
b2dd028fc7 Textbox button now works again correctly (but has caret instead of pointer...) 2018-07-30 16:29:28 +02:00
BONNEVILLE Geoffroy
62f2be8823 Finally corrected strange behaviour in TextBoxWithButton where text would sometimes not appear unless pointed over 2018-07-27 10:52:23 +02:00
BONNEVILLE Geoffroy
89d43e21eb Created a sub style for textbox with buttons in EntryDetailPage
Set long forgotten resources for buttons tooltips
2018-07-26 17:58:34 +02:00
BONNEVILLE Geoffroy
5d9831efb5 Clearer clipboard action toast messages
Created a top menu button style
2018-07-26 16:28:28 +02:00
BONNEVILLE Geoffroy
b65cb87e58 Minor code cleanup 2018-07-26 12:01:49 +02:00
BONNEVILLE Geoffroy
7e687f7001 Donation page now displays a loading ring while page is loaded 2018-07-26 11:49:48 +02:00
BONNEVILLE Geoffroy
1d5a4d6fab Removal of unused string resources
Minor Toast code refactor
2018-07-26 10:18:00 +02:00
BONNEVILLE Geoffroy
2a2a934006 Entry delete button now shows up correctly
Minor code refactoring
2018-07-25 18:39:03 +02:00
BONNEVILLE Geoffroy
4ae65fdbac Created an app theme instead of using the System accent colors (which doesn't work in Win 8.1)
Merged two dictionaries into one
Re-added focus on title when editing an entity
2018-07-25 18:08:59 +02:00
BONNEVILLE Geoffroy
dd347b56a2 Updated some MS packages 2018-07-24 18:06:44 +02:00
BONNEVILLE Geoffroy
ff1cdc265a Removed useless CodeAnalysis packages 2018-07-24 18:05:07 +02:00
BONNEVILLE Geoffroy
9863195684 Added CodeAnalysis package
Better entry history handling
Changing icon now adds an history entry
2018-07-24 17:52:44 +02:00
BONNEVILLE Geoffroy
d6765904a1 Slider control now uses Accent Color
ComboBox enter key now uses Accent Color
Some code cleanup
Updated release notes
2018-07-24 16:26:58 +02:00
BONNEVILLE Geoffroy
7e4d6a2836 Update release notes 2018-07-24 11:00:41 +02:00
BONNEVILLE Geoffroy
8a0b3a0870 HockeyApp correct app id 2018-07-24 10:55:31 +02:00
BONNEVILLE Geoffroy
6f53fc79bb Updated README.md 2018-07-20 17:49:22 +02:00
BONNEVILLE Geoffroy
6f161e8699 Changed search button and search box visibility behavior for a more modern and user friendly mechanism 2018-07-20 17:24:02 +02:00
BONNEVILLE Geoffroy
8f1f80ae38 New version number
New homepage URL
2018-07-20 16:33:13 +02:00
BONNEVILLE Geoffroy
aec09a6890 Updated screenshots
Widened semantic view group header to accomodate larger letters
2018-07-18 18:30:56 +02:00
BONNEVILLE Geoffroy
8e557c608e Hamburger menu expanded size set to static value
LeftIndicator list view pointed over opacity reduced
2018-07-18 16:20:02 +02:00
BONNEVILLE Geoffroy
991a678788 Hamburger button now has a hover opacity change
Search box text bottom margin removed
2018-07-13 11:30:10 +02:00
BONNEVILLE Geoffroy
b88d6131c5 Set a global XAML variable for menu and button sizes
Set global to 60 instead of 50
Changed expired entry icon
2018-07-12 18:19:26 +02:00
BONNEVILLE Geoffroy
c25ae2ad0f Group and entry icon is now shown (and editable) on the left of the title
Added new entry placeholder text in resources
Group detail page small view triggered on larger width
2018-07-12 15:32:54 +02:00
BONNEVILLE Geoffroy
2abab27d5c Updating master key now works again
Security settings page now also uses Toast Action
2018-07-12 12:30:58 +02:00
BONNEVILLE Geoffroy
a91f8b6c5c Entry page now has vertical scrollbar if needed
Removed command bar
Restore button is now correctly enabled or not depending on context
2018-07-11 18:23:52 +02:00
BONNEVILLE Geoffroy
83d37d943f Sorting now works with code behind 2018-07-11 13:48:15 +02:00
BONNEVILLE Geoffroy
81ca11a955 WIP Top Menu - sort buttons present but not working
Removed flyout from textbox with button
Generating a new password creates a new history entry
Top Menu edit mode now works as intended
2018-07-11 12:15:56 +02:00
BONNEVILLE Geoffroy
931f79ac16 WIP Top Menu - added code behind to handle visibility and enabled status in flyouts because XAML doesn't work 2018-07-10 18:26:27 +02:00
BONNEVILLE Geoffroy
2ab84ef4af WIP Top Menu - Overflow mechanism works, commands implemented 2018-07-05 18:32:42 +02:00
BONNEVILLE Geoffroy
056d1af9d0 WIP Top Menu - Button visibility ok when not in menu 2018-07-04 18:26:16 +02:00
BONNEVILLE Geoffroy
34f5f2f6c8 WIP Top Menu 2018-07-02 18:23:43 +02:00
BONNEVILLE Geoffroy
6d32161312 Small layout changes 2018-07-02 14:33:53 +02:00
BONNEVILLE Geoffroy
df6914d1e0 Added possibility to change groups and entries icons
Add new entry link now hides text depending on width
TimePicker uses main color
2018-06-26 18:14:01 +02:00
BONNEVILLE Geoffroy
6f277e7b33 Added ability to change Entries background and foreground colors 2018-06-26 15:01:02 +02:00
BONNEVILLE Geoffroy
7ffcf1c82b Navigate to URL correctly shows the error, should it happen
Entry title linked to history version
Title text boxes selection now uses the main color
2018-06-25 17:31:17 +02:00
BONNEVILLE Geoffroy
c6e27c35c8 Finally a workaround the stupid CommandBar DataContext issues
Delete and Restore actions now work as intended
Renamed styles folder
2018-06-22 18:31:55 +02:00
BONNEVILLE Geoffroy
a6f82b4541 WIP Delete and restore entities as Actions 2018-06-21 18:40:44 +02:00
BONNEVILLE Geoffroy
d533abada5 Better suspend/resume handling 2018-06-21 16:40:04 +02:00
BONNEVILLE Geoffroy
4393aada3e Textbox selection now uses Accent color 2018-06-21 12:16:35 +02:00
BONNEVILLE Geoffroy
559fbe65c3 New toast action to show toast messages from XAML
Code cleanup for Sonar
Tests corrections
2018-06-21 11:13:40 +02:00
BONNEVILLE Geoffroy
803dab0fb5 Replaced almost all CallMethodActions with RelayCommands (allows using async)
SonarQube bug correction
2018-06-20 18:41:56 +02:00
BONNEVILLE Geoffroy
ca377a6684 SonarQube async method return type set to Task 2018-06-20 17:20:15 +02:00
BONNEVILLE Geoffroy
188233cc81 Database file is now handled by each page, instead of a central place
Opening a database while another one is open triggers a warning message
2018-06-20 11:52:17 +02:00
BONNEVILLE Geoffroy
408b4eed90 WIP removing global databaseFile property 2018-06-19 18:47:37 +02:00
BONNEVILLE Geoffroy
b456e56789 Making modifications in an Entry creates a new History entry 2018-06-18 18:40:00 +02:00
BONNEVILLE Geoffroy
9225732c1a Removal of unused License Service 2018-06-18 16:19:56 +02:00
BONNEVILLE Geoffroy
e9601e8d13 Removed unused anti corruption code 2018-06-18 15:39:01 +02:00
BONNEVILLE Geoffroy
b1ded11fa5 Sonar code smells corrections 2018-06-18 14:58:01 +02:00
BONNEVILLE Geoffroy
978929ba48 Correct Sonar vulnerability 2018-06-18 11:25:21 +02:00
BONNEVILLE Geoffroy
7e337c4a40 History list fully functional in Entry page
Viewing a historic entry disables controls on the page
Enhancements in the hamburger menu
2018-06-15 18:07:44 +02:00
BONNEVILLE Geoffroy
62c9719a77 Hamburger menu button visibility is now a property
Hamburger menu now has a display member path property
2018-06-15 10:10:48 +02:00
BONNEVILLE Geoffroy
2b48b64f2f Hamburger button menu is now a User Control
WIP History in Entry page
2018-06-14 18:38:05 +02:00
BONNEVILLE Geoffroy
799b896bfe Breadcrumb finished and working 2018-06-14 10:50:16 +02:00
BONNEVILLE Geoffroy
8a5db88225 Entries and groups icons are now handled with int
Static mapping is changed to a converter
2018-06-14 10:20:00 +02:00
BONNEVILLE Geoffroy
cc65c56042 WIP Breadcrumb
Breadcrumb is now a working User Control (removal of the Templated Control)
AssemblyInfo updated
Some code cleanup
2018-06-13 18:58:28 +02:00
BONNEVILLE Geoffroy
0a4df01354 WIP Breadcrumb 2018-06-12 18:40:54 +02:00
BONNEVILLE Geoffroy
25945b8b3b Add update script version
GroupVM new breadcrumb code
2018-06-12 09:42:08 +02:00
BONNEVILLE Geoffroy
9921a4db52 Correct AppID in HockeyApp 2018-06-11 18:55:55 +02:00
BONNEVILLE Geoffroy
2c6530f3b0 Removed AppCenter and included HockeyApp 2018-06-11 18:42:50 +02:00
BONNEVILLE Geoffroy
f158191e52 Increase version number
WIP new breadcrumb (with hyperlinks)
2018-06-08 18:46:07 +02:00
BONNEVILLE Geoffroy
a7f2ae91a7 Reference ModernKeePassLib as a Nuget package (v2.39.1)
Correct bug when selecting search result
2018-06-08 15:39:28 +02:00
BONNEVILLE Geoffroy
49e1b709f7 ComboBox (including those in DatePicker) now use Accent Color 2018-06-08 14:27:35 +02:00
BONNEVILLE Geoffroy
59c903b635 Search box now recursively search sub groups 2018-06-08 12:08:06 +02:00
BONNEVILLE Geoffroy
c9d599216d List view now set Accent Color on selected item text 2018-06-08 11:22:00 +02:00
BONNEVILLE Geoffroy
8fa3a75a63 ToggleSwitch now also uses Accent Color 2018-06-08 11:12:54 +02:00
BONNEVILLE Geoffroy
e31d1edb99 Use of System Accent Color instead of purple (ToggleButtons still need to be styled) 2018-06-07 18:27:50 +02:00
BONNEVILLE Geoffroy
915cad8c85 Display a title on groups header menu 2018-06-06 18:26:05 +02:00
BONNEVILLE Geoffroy
7bd6c0dd09 XAML code cleanup 2018-06-06 12:21:11 +02:00
BONNEVILLE Geoffroy
0aa8e886ce Entry icon size reduced to 50%, with no side effects 2018-06-06 12:17:28 +02:00
BONNEVILLE Geoffroy
1334b266b9 Updated release notes
Finally a working zoomed out view for the Semantic Zoom
2018-06-06 12:13:25 +02:00
BONNEVILLE Geoffroy
9566c9a719 Open databases errors are cleaner
WIP SemanticView ListView Width issue
2018-06-05 18:40:23 +02:00
BONNEVILLE Geoffroy
0643701c4a Typing a password auto checks the check box
Correct hit test area on entries in group detail page
Correct zoomed out entries (filter and group)
2018-06-05 16:23:09 +02:00
BONNEVILLE Geoffroy
4d86c25411 ModernKeePass lib version 2.39.1 seemeegly functional
WIP in some pages
2018-06-04 18:38:48 +02:00
BONNEVILLE Geoffroy
ad02740d8a WIP Lib version 2.39.1 2018-05-22 18:27:44 +02:00
BONNEVILLE Geoffroy
0b95669db0 Projects renamed 2018-05-22 14:52:31 +02:00
BONNEVILLE Geoffroy
4aefbcb8b9 RecycleBin now uses resources
RecycleBin bugs correction
2018-03-12 17:30:03 +01:00
BONNEVILLE Geoffroy
56129253d9 Use ModernKeePass Lib 2.38.2
Changed suspension save errors handling
2018-03-12 12:45:12 +01:00
BONNEVILLE Geoffroy
7613629d87 Deactivation of buggy Splat custom icon implementation 2018-03-12 12:40:07 +01:00
BONNEVILLE Geoffroy
fb0eab00c2 Create group and delete current group hidden in Recycle Bin 2018-03-12 11:27:15 +01:00
BONNEVILLE Geoffroy
5b8c3b9b11 Typo in restore button 2018-03-12 11:18:42 +01:00
BONNEVILLE Geoffroy
700f76679a Corrected RecycleBin group bug
Database Settings page now has radio button for recycle bin
2018-03-12 10:21:36 +01:00
BONNEVILLE Geoffroy
e7d731bb04 KeepassLib version 2.38
Added a new settings page to allow auto-save or not
App now resumes correctly from suspend
Settings service now allows getting default values
Removed french special characters from metadata
Code cleanup
2018-03-09 18:06:06 +01:00
BONNEVILLE Geoffroy
49637fcc3b KeepassLib version update to 2.38 2018-03-09 17:49:47 +01:00
BONNEVILLE Geoffroy
fc25d7ea93 Update some packages 2018-03-07 18:39:56 +01:00
BONNEVILLE Geoffroy
cca6579274 Removed useless code in Donate page 2018-02-23 18:13:44 +01:00
BONNEVILLE Geoffroy
7dbf93fe7b Changed most services to singletons
Refactor the Database Service (no more enum, ...)
Restored the Donate page with Paypal web page
Added (but not working) MS App Center integration
Corrected tests accordingly
WIP AOP to detect database changes
2018-02-23 18:09:21 +01:00
BONNEVILLE Geoffroy
b46ab8db51 Code cleanup
Popup discard action now works
2018-01-09 18:40:11 +01:00
BONNEVILLE Geoffroy
a19519fa73 Removed database status in favor of much cleaner code
Implemented (but deactivated) anti corruption mechanism
WIP detect changes and save them if opening another database
2018-01-08 18:52:03 +01:00
BONNEVILLE Geoffroy
4a3f36d38b Version bump to 1.13
New group button is now at the bottom of the listview
2018-01-08 11:02:53 +01:00
BONNEVILLE Geoffroy
4ae02fc07b Corrected test case to reflect page removal 2018-01-03 11:37:09 +01:00
BONNEVILLE Geoffroy
047fca32bf Hid donations pages (need to implement 3rd party API) 2018-01-03 11:29:51 +01:00
BONNEVILLE Geoffroy
abbff449c0 Removed User Account from composite key (probably never going to work as intended)
Changed copy URL to navigate to URL in entry quick menu
2017-12-26 17:54:13 +01:00
BONNEVILLE Geoffroy
fba668860b WIP user accounts - not working at all 2017-12-21 18:24:01 +01:00
BONNEVILLE Geoffroy
acb196d9c2 WIP Windows User Accounts Composite Key integration 2017-12-20 18:49:11 +01:00
BONNEVILLE Geoffroy
dfa3a21e6b Removed an useless converter
Groups in menu now use instead a Template selector (depending on IIsSelected)
2017-12-19 18:44:35 +01:00
BONNEVILLE Geoffroy
7ff6bccbc4 Added some tests
Removed false first group, replaced it a button in the header
Code refactor
2017-12-18 18:53:42 +01:00
BONNEVILLE Geoffroy
88e5b80778 Version bump to 1.12
Added small menu on entries list to copy login, password and URL
2017-12-18 14:09:04 +01:00
BONNEVILLE Geoffroy
d127431396 Third try on store special character escaping 2017-12-18 11:52:49 +01:00
BONNEVILLE Geoffroy
588703ecd6 Added a small text explaining how to reorder entries
Code cleanup
2017-12-14 17:54:14 +01:00
BONNEVILLE Geoffroy
223c9b641a Updated release notes
HTML encoded french text
2017-12-14 17:28:22 +01:00
BONNEVILLE Geoffroy
7db34d6517 Corrected critical error when opening file from explorer
Reverted filter mechanisme to search box because of numerous regressions (on ordering, refresh etc.)
2017-12-14 17:15:28 +01:00
BONNEVILLE Geoffroy
13901d17ab Added FR store metadata 2017-12-12 14:59:56 +01:00
BONNEVILLE Geoffroy
19bc9005e9 Removed add-ons ordering to avoid Culture bugs - for now 2017-12-12 13:25:42 +01:00
BONNEVILLE Geoffroy
7c86a325d9 Solution metadata files correction 2017-12-12 11:56:25 +01:00
BONNEVILLE Geoffroy
d203b521c1 Small design changes
Create new database button now properly translated
Store metadata and screenshots updated
2017-12-12 11:54:15 +01:00
BONNEVILLE Geoffroy
0afa59fb66 Minor XAML changes 2017-12-11 19:13:28 +01:00
BONNEVILLE Geoffroy
470a08f4bc Entry page now wraps expiration date controls depending on page size
Group page now toggle filter box visibility depending on size, with a button and flyout on small size
Search text renamed to filter
2017-12-11 19:00:14 +01:00
BONNEVILLE Geoffroy
50c5940a0a Donations are sorted ascending 2017-12-11 11:08:33 +01:00
BONNEVILLE Geoffroy
35f64eec1b Implemented Donate page with wirking (?) in app purchases
Moved Pages to Views
2017-12-08 19:38:33 +01:00
BONNEVILLE Geoffroy
e25f9f4aae Create a LicenseService to handle in-app purchases 2017-12-07 18:49:03 +01:00
BONNEVILLE Geoffroy
a86dbf9dac New database settings version flyout now wraps text instead of showing scrollbar 2017-12-06 18:42:02 +01:00
BONNEVILLE Geoffroy
026bfcba78 New group text is now visible again in Group and Settings pages 2017-12-06 18:29:19 +01:00
BONNEVILLE Geoffroy
3b66824c58 Code cleanup 2017-12-04 18:08:42 +01:00
BONNEVILLE Geoffroy
898a9a0935 Search box now directly filters entries, no need for another drop down
TextBoxWithButton now scales button with text size and text can now be properly aligned
Corrected some French translations
2017-12-04 18:07:03 +01:00
BONNEVILLE Geoffroy
7aa342cf9c French translation added 2017-12-04 12:20:05 +01:00
BONNEVILLE Geoffroy
f173283a66 New clear all button in recent pages
First-time open of app correctly shows Welcome page
New Home button in group and entry pages
2017-12-04 10:46:01 +01:00
bg45
4f69b5cdcc Minor code refactor 2017-12-02 08:42:10 -05:00
BONNEVILLE Geoffroy
744858df81 Created a Settings Service
Created a Recent Service
Created a Resources Service
Code refactor
Updated tests
2017-12-01 17:59:38 +01:00
BONNEVILLE Geoffroy
f172e31250 Settings are now disabled instead of not present when database is closed 2017-12-01 09:31:59 +01:00
BONNEVILLE Geoffroy
7530cf8006 Groups sorting now works with new Lib
New database settings improved
2017-11-30 18:56:56 +01:00
BONNEVILLE Geoffroy
33223934e3 Sorting now works for entries (not yet for groups) 2017-11-30 11:05:47 +01:00
BONNEVILLE Geoffroy
f2731c49dd Drag drop finally works
WIP item background
New Donate page stub
Renamed some classes as services
2017-11-29 19:13:38 +01:00
bg45
227bc30dde New database setting page
(Database) Settings available from Main menu
2017-11-28 16:57:16 -05:00
BONNEVILLE Geoffroy
7b39fe79c8 WIP strings in ressource file (XAML is done, code-behind is not)
Invalid URI now shows a message
Create entry is now a link above entries
Entries gridview allows reordering (WIP enable it conditionnally)
Code cleanup in adding/removing PwEntries from VM
2017-11-28 18:53:10 +01:00
BONNEVILLE Geoffroy
fcbda1e33d Adds some VM tests
New tooltip in Textbox with button control
New welcome page in Settings (shown when noting is selected)
Settings are now grouped
2017-11-27 15:26:36 +01:00
BONNEVILLE Geoffroy
42ac04b02c Layout change in CompositeKey user control
Button text is now settable
Opening database is placed in async task dispatcher to return control to the UI
2017-11-24 18:21:06 +01:00
BONNEVILLE Geoffroy
7cd05cb1d8 Better global exception handling
Save error now shows a Save as button
Recent list now not changed at every access (only on actual file open)
Some code refactoring
2017-11-24 12:17:41 +01:00
BONNEVILLE Geoffroy
1b2d25e171 Error messages are now caught at the app level (see if it's a good solution in the long term)
Redesign of the create key file button
2017-11-23 19:02:49 +01:00
BONNEVILLE Geoffroy
675a718107 Update test project certificate 2017-11-23 15:32:44 +01:00
BONNEVILLE Geoffroy
a8f5897364 Changed VMs references to database singleton
Added some unit tests (WIP)
2017-11-23 15:26:57 +01:00
BONNEVILLE Geoffroy
5120c8177b Adding tests for App
WIP make VMs app agnostic
2017-11-22 18:54:03 +01:00
BONNEVILLE Geoffroy
f2d97b4e7e Bump to 1.10
Bug when pressing enter with invalid composite key
2017-11-21 18:45:42 +01:00
BONNEVILLE Geoffroy
197e061bc5 Update release notes 2017-11-20 18:09:20 +01:00
BONNEVILLE Geoffroy
d1a6b418d5 Added store metadata information 2017-11-20 18:08:19 +01:00
BONNEVILLE Geoffroy
e9c79b192b Finally satisfiable assets
Attempt to handle null reference exception in Key File (not sure to have found source)
2017-11-20 17:21:22 +01:00
BONNEVILLE Geoffroy
52c56757ca Correctly reference logo assets 2017-11-17 17:48:24 +01:00
BONNEVILLE Geoffroy
559af0ddd8 Clean up 2017-11-17 17:43:56 +01:00
BONNEVILLE Geoffroy
cd1b3ce1ed Changed app assets (not fully satisfied though) 2017-11-17 17:43:01 +01:00
BONNEVILLE Geoffroy
5273a25385 Adds the ability to create key files (no entropy generator for now) 2017-11-17 10:20:54 +01:00
BONNEVILLE Geoffroy
3089609c19 Code cleanup 2017-11-16 18:55:20 +01:00
BONNEVILLE Geoffroy
e1f62342d9 Update app and tests to use new ModernKeePassLib 2017-11-15 18:17:41 +01:00
BONNEVILLE Geoffroy
9313ac1abf Repaired key file creation in lib 2017-11-15 17:56:31 +01:00
7a632c8f80 Updated README.md 2017-11-15 09:35:57 +00:00
7f9a0e5b1e Updated README.md 2017-11-14 17:30:37 +00:00
BONNEVILLE Geoffroy
b0a3f796cb Merge branch 'master' of https://geogeob.visualstudio.com/_git/ModernKeePass 2017-11-14 18:00:47 +01:00
BONNEVILLE Geoffroy
97521f174a Test project uses same certificate as main App 2017-11-14 18:00:44 +01:00
432d5e49d5 Updated ImportCertificate.ps1 2017-11-14 16:26:44 +00:00
b2c8f2e0f4 Updated ImportCertificate.ps1 2017-11-14 16:22:37 +00:00
23011568b7 Updated ImportCertificate.ps1 2017-11-14 16:15:31 +00:00
078f9535cf Updated ImportCertificate.ps1 2017-11-14 16:10:28 +00:00
BONNEVILLE Geoffroy
ea481187d5 Add build scripts 2017-11-14 17:03:24 +01:00
BONNEVILLE Geoffroy
810caaf8e2 Test project uses Nuget for lib 2017-11-13 18:31:47 +01:00
BONNEVILLE Geoffroy
d290d9b4e3 Exclude certificate from project 2017-11-13 17:19:08 +01:00
BONNEVILLE Geoffroy
abb12accc7 Correct two bugs related to key file opening
Bettter error messages with composite key
Show an error message if save has failed and don't close the database
2017-11-13 11:28:14 +01:00
2779e5b7c7 Updated README.md 2017-11-09 16:54:43 +00:00
3970d485f6 Updated README.md 2017-11-09 16:53:47 +00:00
BONNEVILLE Geoffroy
7b888cc4a2 Merge branch 'master' of https://geogeob.visualstudio.com/_git/ModernKeePass 2017-11-09 13:46:15 +01:00
BONNEVILLE Geoffroy
117513d6bf Correct credits in About 2017-11-09 13:46:10 +01:00
97511ab290 Updated README.md 2017-11-09 12:43:41 +00:00
3131eca8a1 Updated README.md 2017-11-09 12:39:55 +00:00
91a5507217 Added file README.md 2017-11-09 11:16:13 +00:00
7d904b7120 Updated README.md 2017-11-09 11:08:46 +00:00
BONNEVILLE Geoffroy
be72fc4f7e Minor change for Designer 2017-11-08 18:52:48 +01:00
BONNEVILLE Geoffroy
ecba11a9a9 Version 1.7 - only difference with 1.6 is Argon2Kdf fully working 2017-11-08 18:01:50 +01:00
BONNEVILLE Geoffroy
65f2e529f4 Argon2KDF write mode works! (thanks to an option in XMLWriterSettings) 2017-11-08 17:52:00 +01:00
BONNEVILLE Geoffroy
29e7b22953 Ignored useless files 2017-11-08 17:17:11 +01:00
BONNEVILLE Geoffroy
a61d4573a6 Version 1.6 2017-11-08 17:04:09 +01:00
BONNEVILLE Geoffroy
ce127f55c8 Merge branch 'master' of https://geogeob.visualstudio.com/_git/ModernKeePass 2017-11-08 16:49:49 +01:00
BONNEVILLE Geoffroy
c982a177f7 Version 1.6 2017-11-08 16:49:39 +01:00
BONNEVILLE Geoffroy
401630da1e Correct error when opening database with an empty password 2017-11-08 16:46:03 +01:00
a8f8715648 Update README.md 2017-11-08 15:23:17 +01:00
BONNEVILLE Geoffroy
a8a3cd5437 Disable write for Argon2Kdf for store release 2017-11-08 15:08:40 +01:00
75e18c859c Clean up project files 2017-11-08 14:48:01 +01:00
c33120ec18 Exclude certain files 2017-11-08 14:48:01 +01:00
ec0372accd Deleted ModernKeePassLib.Test.old 2017-11-08 14:44:24 +01:00
aa0b21dd31 Some more cleanup 2017-11-08 14:42:48 +01:00
ed766848be Clean up project files 2017-11-08 14:42:48 +01:00
c73ce18368 Exclude certain files 2017-11-08 14:42:48 +01:00
d996209888 App uses latest lib nuget package 2017-11-08 14:42:48 +01:00
00278b8710 Renamed OpenDatabase to CompositeKey UserControl 2017-11-08 14:42:47 +01:00
10a4941b26 Major OpenDatabaseUserControl refactor, now has proper ViewModel
Status text and password box border colors are updated according to database status
Update composite key in Settings work
Some code cleanup
2017-11-08 14:42:47 +01:00
c3b8c97eea Password complexity indicator works again in new databases (but solution is dirty...)
Copy button in text boxes fully works
2017-11-08 14:42:47 +01:00
8e690747e2 Changed test project type to WIndows 8.1
Changed test project framework from Nunit to MSTest
Changed HashAlgorithm from BouncyCastle to WinRT crypto
WIP progress bar in opendatabaseusercontrol
TextBox with button made generic
WIP implement copy on button click in Entry Page
2017-11-08 14:42:47 +01:00
bg45
53a54252e3 Added more tests
Code cleanup in Lib
WIP new VM for OpendatabaseControl
WIP KDBX4 file save - still not working
2017-11-08 14:42:47 +01:00
278b2759d5 Open database control button is now purple to be more visible
WIP Argon2KDF - still no luck in saving => disabled for now
2017-11-08 14:42:46 +01:00
e495a1c2e7 Key file implemented!
Key Derivation setting added
More unit tests created
Some cleanup in lib
WIP Argon2 save
2017-11-08 14:42:46 +01:00
536bddf442 Minor code cleanup 2017-11-08 14:42:46 +01:00
a0d1c82afa Added lots of tests from Lib SelfTest.cs to Test project
Code cleanup in KeePassLib
Code cleanup in ModernKeePass.Tests
Argon2Kdf files can now be opened
WIP - Argon2kdf files are corrupted on write
2017-11-08 14:42:46 +01:00
473a3700a7 Implements encryption algorithm change
Implements compression algorithm change
2017-11-08 14:42:46 +01:00
bg45
82ef424365 Recycle bin is now created when deleting first element instead of selecting new group in Settings 2017-11-08 14:42:46 +01:00
7e642e3b73 Recycle bin restore function (actually implemented a move functionality, for later) 2017-11-08 14:42:45 +01:00
d32f312d60 Auto create new recycle bin if needed
Entries now also make use of the recycle bin
New path indication below groups and entries title
Password generator now has custom characters back (working thanks to lib 2.37)
2017-11-08 14:42:45 +01:00
699452667c New Database settings page
Implements Recycle Bin (new group creation still needs to be implemented)
Code refactoring
2017-11-08 14:42:45 +01:00
bg45
fa3d38db18 Hidden Settings button for now
Improved Welcome and About pages layout
Redone GroupDetail page with group list view outside of entries grid view
2017-11-08 14:42:45 +01:00
dd1e128e17 Improved design in Main Page sub pages titles 2017-11-08 14:42:45 +01:00
d247aa8334 WIP Layout improvements - bis
Group and Entry pages now have better navigation bar
Hamburger menu redesigned
2017-11-08 14:42:45 +01:00
5f995a10c1 WIP layout enhancments
MainPage list view now has left indicator (more modern)
2017-11-08 14:42:45 +01:00
bg45
b89998c053 Small refactor in MainPage 2017-11-08 14:42:45 +01:00
d10f617910 Major changes in MainPage: now is layout dependant (with a base, to prepare for Settings)
Main sub pages also changed to better work with Main (but needs improvement)
Added a Settings Page stub
2017-11-08 14:42:44 +01:00
1b439a4960 ModernKeePassLib implements HMAC correctly
Blake2b also implemented, but not tested
ModernKeePass app better implements focus on database password box (but still not working correctly)
2017-11-08 14:42:44 +01:00
bg45
5cf4ff3012 Set same width for groups in Zoomed Out view 2017-11-08 14:42:44 +01:00
46c8429cde Lots of code refactoring to use XAML behaviors instead of code-behind
New Save button in the AppBar
EntryPage now uses the same AppBar as GroupPage (but not shared...)
Some new Symbol mappings
2017-11-08 14:42:44 +01:00
8cd3801897 Bigger database password textbox
Wrong password sets the password box border to red
Typing text removes the error
Implemented real command bar at the bottom in Groups
Search box is always present
2017-11-08 14:42:44 +01:00
b47d7fb69b Use latest Nuget package 2017-11-08 14:42:44 +01:00
52e08d8c98 Code cleanup in KeePassLib 2017-11-08 14:42:44 +01:00
ad0d8d6c97 KeePassLib 2.37 tentatively working!!
Replaced WinRt hash providers with BouncyCastle in CryptoUtil
2017-11-08 14:42:43 +01:00
5b31d3ff72 WIP Lib 2.37 - databases created by ModernKeepass work fine, but no interoperability... 2017-11-08 14:42:43 +01:00
2bbd931b1a Hashblockstream test now works 2017-11-08 14:42:43 +01:00
8c09d266e8 KeePassLib selftest class corrected in release 2017-11-08 14:42:43 +01:00
a11d209280 Correct implementation of SHA512 with WinRT in KeepassLib 2017-11-08 14:42:43 +01:00
bg45
e95e62f184 WIP 2.37 - ter 2017-11-08 14:42:43 +01:00
bg45
84e7afc819 WIP - Implementing HMAC with BouncyCastle 2017-11-08 14:42:43 +01:00
bg45
c82d6d001d KeePassLib bumped to 2.37, compilation ok.
WIP tests
2017-11-08 14:42:42 +01:00
d5b7845242 WIP Update lib to 2.37 2017-11-08 14:42:42 +01:00
9de9ae54da WIP About page auto version 2017-11-08 14:42:42 +01:00
6548d1d9c1 Added DataTrigger on generate password button to close flyout 2017-11-08 14:42:42 +01:00
54ad395d13 Added password complexity indicator to Entry page 2017-11-08 14:42:42 +01:00
697 changed files with 26592 additions and 29837 deletions

7
.gitignore vendored
View File

@@ -36,4 +36,9 @@ Translation/TrlUtil.vshost.exe.manifest
/UpgradeLog*.htm /UpgradeLog*.htm
packages/ packages/
project.lock.json project.lock.json
AppPackages/ AppPackages/
BundleArtifacts/
*.DotSettings
/ModernKeePass/Win81App_TemporaryKey.pfx
/ModernKeePass/Win81App_StoreKey.pfx
.sonarqube/

674
LICENSE Normal file
View File

@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
{project} Copyright (C) {year} {fullname}
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@@ -0,0 +1,176 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{42353562-5E43-459C-8E3E-2F21E575261D}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ModernKeePass.Application</RootNamespace>
<AssemblyName>ModernKeePass.Application</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|ARM' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\ARM\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>ARM</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|ARM' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\ARM\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="Common\Behaviors\DirtyStatusBehavior.cs" />
<Compile Include="Common\Interfaces\ICryptographyClient.cs" />
<Compile Include="Common\Interfaces\IDatabaseSettingsProxy.cs" />
<Compile Include="Common\Interfaces\IDatabaseProxy.cs" />
<Compile Include="Common\Interfaces\IEntityVm.cs" />
<Compile Include="Common\Interfaces\IFileProxy.cs" />
<Compile Include="Common\Interfaces\ICredentialsProxy.cs" />
<Compile Include="Common\Interfaces\ILogger.cs" />
<Compile Include="Common\Interfaces\INotificationService.cs" />
<Compile Include="Common\Interfaces\IRecentProxy.cs" />
<Compile Include="Common\Interfaces\IResourceProxy.cs" />
<Compile Include="Common\Interfaces\ISettingsProxy.cs" />
<Compile Include="Common\Mappings\IMapFrom.cs" />
<Compile Include="Common\Mappings\MappingProfile.cs" />
<Compile Include="Common\Models\BreadcrumbItem.cs" />
<Compile Include="Entry\Commands\AddAttachment\AddAttachmentCommand.cs" />
<Compile Include="Entry\Commands\AddHistory\AddHistoryCommand.cs" />
<Compile Include="Entry\Commands\DeleteAttachment\DeleteAttachmentCommand.cs" />
<Compile Include="Entry\Commands\DeleteField\DeleteFieldCommand.cs" />
<Compile Include="Entry\Commands\DeleteHistory\DeleteHistoryCommand.cs" />
<Compile Include="Entry\Commands\RestoreHistory\RestoreHistoryCommand.cs" />
<Compile Include="Entry\Models\FieldVm.cs" />
<Compile Include="Entry\Queries\GetEntry\GetEntryQuery.cs" />
<Compile Include="Group\Commands\DeleteEntry\DeleteEntryCommand.cs" />
<Compile Include="Group\Commands\DeleteGroup\DeleteGroupCommand.cs" />
<Compile Include="Group\Commands\MoveGroup\MoveGroupCommand.cs" />
<Compile Include="Group\Commands\UpdateGroup\UpdateGroupCommand.cs" />
<Compile Include="Group\Queries\GetAllGroups\GetAllGroupsQuery.cs" />
<Compile Include="Group\Queries\GetGroup\GetGroupQuery.cs" />
<Compile Include="Group\Queries\SearchEntries\SearchEntriesQuery.cs" />
<Compile Include="Import\Commands\ImportFromCsv\ImportFromCsvCommand.cs" />
<Compile Include="Import\Commands\ImportFromCsv\ImportFromCsvCommandValidator.cs" />
<Compile Include="Parameters\Commands\SetCipher\SetCipherCommand.cs" />
<Compile Include="Parameters\Commands\SetCompression\SetCompressionCommand.cs" />
<Compile Include="Parameters\Commands\SetHasRecycleBin\SetHasRecycleBinCommand.cs" />
<Compile Include="Parameters\Commands\SetMaxHistoryCount\SetHistoryCountCommand.cs" />
<Compile Include="Parameters\Commands\SetKeyDerivation\SetKeyDerivationCommand.cs" />
<Compile Include="Parameters\Commands\SetMaxHistorySize\SetMaxHistorySizeCommand.cs" />
<Compile Include="Parameters\Commands\SetRecycleBin\SetRecycleBinCommand.cs" />
<Compile Include="Parameters\Models\CipherVm.cs" />
<Compile Include="Parameters\Models\KeyDerivationVm.cs" />
<Compile Include="Parameters\Queries\GetCiphers\GetCiphersQuery.cs" />
<Compile Include="Parameters\Queries\GetCompressions\GetCompressionsQuery.cs" />
<Compile Include="Parameters\Queries\GetKeyDerivations\GetKeyDerivationsQuery.cs" />
<Compile Include="Database\Commands\CloseDatabase\CloseDatabaseCommand.cs" />
<Compile Include="Database\Commands\CreateDatabase\CreateDatabaseCommand.cs" />
<Compile Include="Database\Commands\CreateDatabase\CreateDatabaseCommandValidator.cs" />
<Compile Include="Database\Commands\SaveDatabase\SaveDatabaseCommand.cs" />
<Compile Include="Database\Commands\UpdateCredentials\UpdateCredentialsCommand.cs" />
<Compile Include="Database\Models\DatabaseVm.cs" />
<Compile Include="Database\Queries\GetDatabase\GetDatabaseQuery.cs" />
<Compile Include="Database\Queries\OpenDatabase\OpenDatabaseQuery.cs" />
<Compile Include="Database\Queries\OpenDatabase\OpenDatabaseQueryValidator.cs" />
<Compile Include="Database\Queries\ReOpenDatabase\ReOpenDatabaseQuery.cs" />
<Compile Include="DependencyInjection.cs" />
<Compile Include="Entry\Commands\UpsertField\UpsertFieldCommand.cs" />
<Compile Include="Entry\Commands\UpsertField\UpsertFieldCommandValidator.cs" />
<Compile Include="Entry\Models\EntryVm.cs" />
<Compile Include="Group\Commands\AddEntry\AddEntryCommand.cs" />
<Compile Include="Group\Commands\AddGroup\AddGroupCommand.cs" />
<Compile Include="Group\Commands\CreateEntry\CreateEntryCommand.cs" />
<Compile Include="Group\Commands\CreateGroup\CreateGroupCommand.cs" />
<Compile Include="Group\Commands\MoveEntry\MoveEntryCommand.cs" />
<Compile Include="Group\Commands\RemoveEntry\RemoveEntryCommand.cs" />
<Compile Include="Group\Commands\RemoveGroup\RemoveGroupCommand.cs" />
<Compile Include="Group\Commands\SortEntries\SortEntriesCommand.cs" />
<Compile Include="Group\Commands\SortGroups\SortGroupsCommand.cs" />
<Compile Include="Group\Models\GroupVm.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Security\Commands\GenerateKeyFile\GenerateKeyFileCommand.cs" />
<Compile Include="Security\Commands\GeneratePassword\GeneratePasswordCommand.cs" />
<Compile Include="Security\Queries\EstimatePasswordComplexity\EstimatePasswordComplexityQuery.cs" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<ProjectReference Include="..\ModernKeePass.Domain\Domain.csproj">
<Project>{9a0759f1-9069-4841-99e3-3bec44e17356}</Project>
<Name>Domain</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Database.Commands.CloseDatabase;
using ModernKeePass.Application.Database.Commands.SaveDatabase;
namespace ModernKeePass.Application.Common.Behaviors
{
public class DirtyStatusBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly List<string> _excludedCommands = new List<string>
{nameof(SaveDatabaseCommand), nameof(CloseDatabaseCommand)};
private readonly IDatabaseProxy _database;
public DirtyStatusBehavior(IDatabaseProxy database)
{
_database = database;
}
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next)
{
var response = await next();
var queryName = typeof(TRequest).Name;
if (queryName.Contains("Command"))
{
_database.IsDirty = !_excludedCommands.Contains(queryName);
}
return response;
}
}
}

View File

@@ -0,0 +1,11 @@
using ModernKeePass.Domain.Dtos;
namespace ModernKeePass.Application.Common.Interfaces
{
public interface ICredentialsProxy
{
string GeneratePassword(PasswordGenerationOptions options);
int EstimatePasswordComplexity(string password);
byte[] GenerateKeyFile(byte[] additionalEntropy);
}
}

View File

@@ -0,0 +1,11 @@
using System.Threading.Tasks;
namespace ModernKeePass.Application.Common.Interfaces
{
public interface ICryptographyClient
{
Task<string> Protect(string value);
Task<string> UnProtect(string value);
byte[] Random(uint length);
}
}

View File

@@ -0,0 +1,63 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using ModernKeePass.Domain.Dtos;
using ModernKeePass.Domain.Entities;
using ModernKeePass.Domain.Enums;
namespace ModernKeePass.Application.Common.Interfaces
{
public interface IDatabaseProxy
{
// PW Database properties
bool IsOpen { get; }
string Name { get; }
string RootGroupId { get; }
string RecycleBinId { get; set; }
string CipherId { get; set; }
string KeyDerivationId { get; set; }
string Compression { get; set; }
bool IsRecycleBinEnabled { get; set; }
// Custom properties
string FileAccessToken { get; set; }
int Size { get; set; }
bool IsDirty { get; set; }
int MaxHistoryCount { get; set; }
long MaxHistorySize { get; set; }
Task Open(byte[] file, Credentials credentials);
Task ReOpen(byte[] file);
Task Create(Credentials credentials, string name, DatabaseVersion version = DatabaseVersion.V4);
Task<byte[]> SaveDatabase();
void UpdateCredentials(Credentials credentials);
void CloseDatabase();
EntryEntity GetEntry(string id);
Task AddEntry(string parentGroupId, string entryId);
Task MoveEntry(string parentGroupId, string entryId, int index);
Task UpdateEntry(string entryId, string fieldName, object fieldValue, bool isProtected);
void DeleteField(string entryId, string fieldName);
Task RemoveEntry(string parentGroupId, string entryId);
EntryEntity CreateEntry(string parentGroupId);
void SortEntries(string groupId);
GroupEntity GetGroup(string id);
Task AddGroup(string parentGroupId, string groupId);
Task MoveGroup(string parentGroupId, string groupId, int index);
void UpdateGroup(GroupEntity group);
Task RemoveGroup(string parentGroupId, string groupId);
void DeleteEntity(string entityId);
GroupEntity CreateGroup(string parentGroupId, string name, bool isRecycleBin = false);
void SortSubGroups(string groupId);
void AddAttachment(string entryId, string attachmentName, byte[] attachmentContent);
void DeleteAttachment(string entryId, string attachmentName);
EntryEntity AddHistory(string entryId);
EntryEntity RestoreFromHistory(string entryId, int historyIndex);
void DeleteHistory(string entryId, int historyIndex);
IEnumerable<EntryEntity> Search(string groupId, string text);
IEnumerable<BaseEntity> GetAllGroups(string groupId);
}
}

View File

@@ -0,0 +1,12 @@
using System.Collections.Generic;
using ModernKeePass.Domain.Entities;
namespace ModernKeePass.Application.Common.Interfaces
{
public interface IDatabaseSettingsProxy
{
IEnumerable<BaseEntity> Ciphers { get; }
IEnumerable<BaseEntity> KeyDerivations { get; }
IEnumerable<string> CompressionAlgorithms { get; }
}
}

View File

@@ -0,0 +1,12 @@
using ModernKeePass.Domain.Enums;
namespace ModernKeePass.Application.Common.Interfaces
{
public interface IEntityVm
{
string Id { get; set; }
Icon Icon { get; set; }
string ParentGroupId { get; set; }
string ParentGroupName { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using ModernKeePass.Domain.Dtos;
namespace ModernKeePass.Application.Common.Interfaces
{
public interface IFileProxy
{
Task<FileInfo> OpenFile(string name, string extension, bool addToRecent);
Task<FileInfo> CreateFile(string name, string extension, string description, bool addToRecent);
Task<byte[]> ReadBinaryFile(string path);
Task<IList<string>> ReadTextFile(string path);
Task WriteToLogFile(IEnumerable<string> data);
Task WriteBinaryContentsToFile(string path, byte[] contents);
void ReleaseFile(string path);
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ModernKeePass.Application.Common.Interfaces
{
public interface ILogger
{
Task LogError(Exception exception);
void LogTrace(string message, Dictionary<string, string> values);
}
}

View File

@@ -0,0 +1,7 @@
namespace ModernKeePass.Application.Common.Interfaces
{
public interface INotificationService
{
void Show(string title, string text);
}
}

View File

@@ -0,0 +1,12 @@
using System.Collections.Generic;
using ModernKeePass.Domain.Dtos;
namespace ModernKeePass.Application.Common.Interfaces
{
public interface IRecentProxy
{
int EntryCount { get; }
IEnumerable<FileInfo> GetAll();
void ClearAll();
}
}

View File

@@ -0,0 +1,7 @@
namespace ModernKeePass.Application.Common.Interfaces
{
public interface IResourceProxy
{
string GetResourceValue(string key);
}
}

View File

@@ -0,0 +1,8 @@
namespace ModernKeePass.Application.Common.Interfaces
{
public interface ISettingsProxy
{
T GetSetting<T>(string property, T defaultValue = default(T));
void PutSetting<T>(string property, T value);
}
}

View File

@@ -0,0 +1,10 @@
using AutoMapper;
namespace ModernKeePass.Application.Common.Mappings
{
public interface IMapFrom<T>
{
void Mapping(Profile profile);
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Linq;
using System.Reflection;
using AutoMapper;
namespace ModernKeePass.Application.Common.Mappings
{
public class MappingProfile : Profile
{
public MappingProfile()
{
ApplyMappingsFromAssembly(typeof(MappingProfile).GetTypeInfo().Assembly);
}
private void ApplyMappingsFromAssembly(Assembly assembly)
{
var types = assembly.ExportedTypes
.Where(t => t.GetTypeInfo().ImplementedInterfaces.Any(i =>
i.GetTypeInfo().IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapFrom<>)))
.ToList();
foreach (var type in types)
{
var instance = Activator.CreateInstance(type);
var methodInfo = type.GetTypeInfo().GetDeclaredMethod("Mapping");
methodInfo?.Invoke(instance, new object[] { this });
}
}
}
}

View File

@@ -0,0 +1,12 @@
using ModernKeePass.Domain.Enums;
namespace ModernKeePass.Application.Common.Models
{
public class BreadcrumbItem
{
public string Path { get; set; }
public string Name { get; set; }
public Icon Icon { get; set; }
}
}

View File

@@ -0,0 +1,26 @@
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Database.Commands.CloseDatabase
{
public class CloseDatabaseCommand: IRequest
{
public class CloseDatabaseCommandHandler : IRequestHandler<CloseDatabaseCommand>
{
private readonly IDatabaseProxy _database;
public CloseDatabaseCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public void Handle(CloseDatabaseCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
// Prevent reopening the database due to possible de-synchronization between app and data
if (_database.IsDirty) _database.FileAccessToken = null;
_database.CloseDatabase();
}
}
}
}

View File

@@ -0,0 +1,82 @@
using MediatR;
using System.Threading.Tasks;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Dtos;
using ModernKeePass.Domain.Exceptions;
using ModernKeePass.Domain.Enums;
namespace ModernKeePass.Application.Database.Commands.CreateDatabase
{
public class CreateDatabaseCommand : IRequest
{
public string FilePath { get; set; }
public string Password { get; set; }
public string KeyFilePath { get; set; }
public string Name { get; set; }
public string Version { get; set; }
public bool CreateSampleData { get; set; }
public class CreateDatabaseCommandHandler : IAsyncRequestHandler<CreateDatabaseCommand>
{
private readonly IDatabaseProxy _database;
private readonly IFileProxy _file;
public CreateDatabaseCommandHandler(IDatabaseProxy database, IFileProxy file)
{
_database = database;
_file = file;
}
public async Task Handle(CreateDatabaseCommand message)
{
if (_database.IsDirty) throw new DatabaseOpenException();
var version = DatabaseVersion.V2;
switch (message.Version)
{
case "4":
version = DatabaseVersion.V4;
break;
case "3":
version = DatabaseVersion.V3;
break;
}
await _database.Create(new Credentials
{
KeyFileContents = !string.IsNullOrEmpty(message.KeyFilePath) ? await _file.ReadBinaryFile(message.KeyFilePath) : null,
Password = message.Password
}, message.Name, version);
_database.FileAccessToken = message.FilePath;
if (message.CreateSampleData)
{
var bankingGroup = _database.CreateGroup(_database.RootGroupId, "Banking");
bankingGroup.Icon = Icon.Shop;
_database.UpdateGroup(bankingGroup);
var emailGroup = _database.CreateGroup(_database.RootGroupId, "Email");
emailGroup.Icon = Icon.Mail;
_database.UpdateGroup(emailGroup);
var internetGroup = _database.CreateGroup(_database.RootGroupId, "Internet");
internetGroup.Icon = Icon.World;
_database.UpdateGroup(internetGroup);
var sample1 = _database.CreateEntry(_database.RootGroupId);
await _database.UpdateEntry(sample1.Id, EntryFieldName.Title, "Sample Entry", false);
await _database.UpdateEntry(sample1.Id, EntryFieldName.UserName, "Username", false);
await _database.UpdateEntry(sample1.Id, EntryFieldName.Password, "Password", true);
await _database.UpdateEntry(sample1.Id, EntryFieldName.Url, "https://keepass.info/", false);
await _database.UpdateEntry(sample1.Id, EntryFieldName.Notes, "You may safely delete this sample", false);
var sample2 = _database.CreateEntry(_database.RootGroupId);
await _database.UpdateEntry(sample2.Id, EntryFieldName.Title, "Sample Entry #2", false);
await _database.UpdateEntry(sample2.Id, EntryFieldName.UserName, "Michael321", false);
await _database.UpdateEntry(sample2.Id, EntryFieldName.Password, "12345", true);
await _database.UpdateEntry(sample2.Id, EntryFieldName.Url, "https://keepass.info/help/kb/testform.html", false);
}
}
}
}
}

View File

@@ -0,0 +1,22 @@
using FluentValidation;
namespace ModernKeePass.Application.Database.Commands.CreateDatabase
{
public class CreateDatabaseCommandValidator : AbstractValidator<CreateDatabaseCommand>
{
public CreateDatabaseCommandValidator()
{
RuleFor(v => v.FilePath)
.NotNull()
.NotEmpty();
RuleFor(v => v.Password)
.NotNull()
.NotEmpty()
.When(v => string.IsNullOrEmpty(v.KeyFilePath));
RuleFor(v => v.KeyFilePath)
.NotNull()
.NotEmpty()
.When(v => string.IsNullOrEmpty(v.Password));
}
}
}

View File

@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using MediatR;
using System.Threading.Tasks;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Database.Commands.SaveDatabase
{
public class SaveDatabaseCommand : IRequest
{
public string FilePath { get; set; }
public class SaveDatabaseCommandHandler : IAsyncRequestHandler<SaveDatabaseCommand>
{
private readonly IDatabaseProxy _database;
private readonly IFileProxy _file;
private readonly ILogger _logger;
public SaveDatabaseCommandHandler(IDatabaseProxy database, IFileProxy file, ILogger logger)
{
_database = database;
_file = file;
_logger = logger;
}
public async Task Handle(SaveDatabaseCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
try
{
var timeToSave = Stopwatch.StartNew();
if (!string.IsNullOrEmpty(message.FilePath))
{
_database.FileAccessToken = message.FilePath;
}
var contents = await _database.SaveDatabase();
// Test DB integrity
_database.CloseDatabase();
await _database.ReOpen(contents);
// Transactional write to file
await _file.WriteBinaryContentsToFile(_database.FileAccessToken, contents);
timeToSave.Stop();
_logger.LogTrace("SaveCommand", new Dictionary<string, string>
{
{ "duration", timeToSave.ElapsedMilliseconds.ToString()},
{ "size", _database.Size.ToString()}
});
}
catch (Exception exception)
{
throw new SaveException(exception);
}
}
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Dtos;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Database.Commands.UpdateCredentials
{
public class UpdateCredentialsCommand: IRequest
{
public string Password { get; set; }
public string KeyFilePath { get; set; }
public class UpdateCredentialsCommandHandler : IAsyncRequestHandler<UpdateCredentialsCommand>
{
private readonly IDatabaseProxy _database;
private readonly IFileProxy _file;
public UpdateCredentialsCommandHandler(IDatabaseProxy database, IFileProxy file)
{
_database = database;
_file = file;
}
public async Task Handle(UpdateCredentialsCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
_database.UpdateCredentials(new Credentials
{
KeyFileContents = !string.IsNullOrEmpty(message.KeyFilePath) ? await _file.ReadBinaryFile(message.KeyFilePath) : null,
Password = message.Password
});
}
}
}
}

View File

@@ -0,0 +1,18 @@
namespace ModernKeePass.Application.Database.Models
{
public class DatabaseVm
{
public bool IsOpen { get; set; }
public string Name { get; set; }
public string RootGroupId { get; set; }
public string RecycleBinId { get; set; }
public bool IsRecycleBinEnabled { get; set; }
public string Compression { get; set; }
public string CipherId { get; set; }
public string KeyDerivationId { get; set; }
public int Size { get; internal set; }
public bool IsDirty { get; internal set; }
public int MaxHistoryCount { get; set; }
public long MaxHistorySize { get; set; }
}
}

View File

@@ -0,0 +1,43 @@
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Database.Models;
using ModernKeePass.Domain.Common;
namespace ModernKeePass.Application.Database.Queries.GetDatabase
{
public class GetDatabaseQuery: IRequest<DatabaseVm>
{
public class GetDatabaseQueryHandler : IRequestHandler<GetDatabaseQuery, DatabaseVm>
{
private readonly IDatabaseProxy _databaseProxy;
public GetDatabaseQueryHandler(IDatabaseProxy databaseProxy)
{
_databaseProxy = databaseProxy;
}
public DatabaseVm Handle(GetDatabaseQuery message)
{
var database = new DatabaseVm
{
IsOpen = _databaseProxy.IsOpen
};
if (database.IsOpen)
{
database.Name = _databaseProxy.Name;
database.RootGroupId = _databaseProxy.RootGroupId;
database.IsRecycleBinEnabled = _databaseProxy.IsRecycleBinEnabled;
database.RecycleBinId = _databaseProxy.RecycleBinId == Constants.EmptyId ? null : _databaseProxy.RecycleBinId;
database.Compression = _databaseProxy.Compression;
database.CipherId = _databaseProxy.CipherId;
database.KeyDerivationId = _databaseProxy.KeyDerivationId;
database.Size = _databaseProxy.Size;
database.IsDirty = _databaseProxy.IsDirty;
database.MaxHistoryCount = _databaseProxy.MaxHistoryCount;
database.MaxHistorySize = _databaseProxy.MaxHistorySize;
}
return database;
}
}
}
}

View File

@@ -0,0 +1,43 @@
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Dtos;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Database.Queries.OpenDatabase
{
public class OpenDatabaseQuery: IRequest
{
public string FilePath { get; set; }
public string Password { get; set; }
public string KeyFilePath { get; set; }
public class OpenDatabaseQueryHandler : IAsyncRequestHandler<OpenDatabaseQuery>
{
private readonly IDatabaseProxy _database;
private readonly IFileProxy _file;
public OpenDatabaseQueryHandler(IDatabaseProxy database, IFileProxy file)
{
_database = database;
_file = file;
}
public async Task Handle(OpenDatabaseQuery message)
{
if (_database.IsDirty) throw new DatabaseOpenException();
var file = await _file.ReadBinaryFile(message.FilePath);
var hasKeyFile = !string.IsNullOrEmpty(message.KeyFilePath);
await _database.Open(file, new Credentials
{
KeyFileContents = hasKeyFile ? await _file.ReadBinaryFile(message.KeyFilePath): null,
Password = message.Password
});
if (hasKeyFile) _file.ReleaseFile(message.KeyFilePath);
_database.Size = file.Length;
_database.FileAccessToken = message.FilePath;
}
}
}
}

View File

@@ -0,0 +1,22 @@
using FluentValidation;
namespace ModernKeePass.Application.Database.Queries.OpenDatabase
{
public class OpenDatabaseQueryValidator : AbstractValidator<OpenDatabaseQuery>
{
public OpenDatabaseQueryValidator()
{
RuleFor(v => v.FilePath)
.NotNull()
.NotEmpty();
RuleFor(v => v.Password)
.NotNull()
.NotEmpty()
.When(v => string.IsNullOrEmpty(v.KeyFilePath));
RuleFor(v => v.KeyFilePath)
.NotNull()
.NotEmpty()
.When(v => string.IsNullOrEmpty(v.Password));
}
}
}

View File

@@ -0,0 +1,31 @@
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Database.Queries.ReOpenDatabase
{
public class ReOpenDatabaseQuery: IRequest
{
public class ReOpenDatabaseQueryHandler : IAsyncRequestHandler<ReOpenDatabaseQuery>
{
private readonly IDatabaseProxy _database;
private readonly IFileProxy _file;
public ReOpenDatabaseQueryHandler(IDatabaseProxy database, IFileProxy file)
{
_database = database;
_file = file;
}
public async Task Handle(ReOpenDatabaseQuery message)
{
if (_database.IsOpen) throw new DatabaseOpenException();
if (string.IsNullOrEmpty(_database.FileAccessToken)) throw new DatabaseClosedException();
var file = await _file.ReadBinaryFile(_database.FileAccessToken);
await _database.ReOpen(file);
}
}
}
}

View File

@@ -0,0 +1,19 @@
using System.Reflection;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using ModernKeePass.Application.Common.Behaviors;
namespace ModernKeePass.Application
{
public static class DependencyInjection
{
public static IServiceCollection AddApplication(this IServiceCollection services)
{
var assembly = typeof(DependencyInjection).GetTypeInfo().Assembly;
services.AddMediatR(assembly);
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(DirtyStatusBehavior<,>));
return services;
}
}
}

View File

@@ -0,0 +1,34 @@
using System;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Entry.Models;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Entry.Commands.AddAttachment
{
public class AddAttachmentCommand : IRequest
{
public EntryVm Entry { get; set; }
public string AttachmentName { get; set; }
public byte[] AttachmentContent { get; set; }
public class AddAttachmentCommandHandler : IRequestHandler<AddAttachmentCommand>
{
private readonly IDatabaseProxy _database;
public AddAttachmentCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public void Handle(AddAttachmentCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
if (message.Entry.Attachments.ContainsKey(message.AttachmentName)) throw new ArgumentException("AttachmentAlreadyExists", nameof(message.AttachmentName));
_database.AddAttachment(message.Entry.Id, message.AttachmentName, message.AttachmentContent);
message.Entry.Attachments.Add(message.AttachmentName, message.AttachmentContent);
}
}
}
}

View File

@@ -0,0 +1,33 @@
using AutoMapper;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Entry.Models;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Entry.Commands.AddHistory
{
public class AddHistoryCommand : IRequest
{
public EntryVm Entry { get; set; }
public class AddHistoryCommandHandler : IRequestHandler<AddHistoryCommand>
{
private readonly IDatabaseProxy _database;
private readonly IMapper _mapper;
public AddHistoryCommandHandler(IDatabaseProxy database, IMapper mapper)
{
_database = database;
_mapper = mapper;
}
public void Handle(AddHistoryCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
var history = _database.AddHistory(message.Entry.Id);
message.Entry.History.Add(_mapper.Map<EntryVm>(history));
}
}
}
}

View File

@@ -0,0 +1,33 @@
using System.Collections.Generic;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Entry.Models;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Entry.Commands.DeleteAttachment
{
public class DeleteAttachmentCommand : IRequest
{
public EntryVm Entry { get; set; }
public string AttachmentName { get; set; }
public class DeleteAttachmentCommandHandler : IRequestHandler<DeleteAttachmentCommand>
{
private readonly IDatabaseProxy _database;
public DeleteAttachmentCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public void Handle(DeleteAttachmentCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
if (!message.Entry.Attachments.ContainsKey(message.AttachmentName)) throw new KeyNotFoundException("AttachmentDoesntExist");
_database.DeleteAttachment(message.Entry.Id, message.AttachmentName);
message.Entry.Attachments.Remove(message.AttachmentName);
}
}
}
}

View File

@@ -0,0 +1,29 @@
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Entry.Commands.DeleteField
{
public class DeleteFieldCommand: IRequest
{
public string EntryId { get; set; }
public string FieldName { get; set; }
public class DeleteFieldCommandHandler : IRequestHandler<DeleteFieldCommand>
{
private readonly IDatabaseProxy _database;
public DeleteFieldCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public void Handle(DeleteFieldCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
_database.DeleteField(message.EntryId, message.FieldName);
}
}
}
}

View File

@@ -0,0 +1,31 @@
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Entry.Models;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Entry.Commands.DeleteHistory
{
public class DeleteHistoryCommand : IRequest
{
public EntryVm Entry { get; set; }
public int HistoryIndex { get; set; }
public class DeleteHistoryCommandHandler : IRequestHandler<DeleteHistoryCommand>
{
private readonly IDatabaseProxy _database;
public DeleteHistoryCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public void Handle(DeleteHistoryCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
_database.DeleteHistory(message.Entry.Id, message.HistoryIndex);
message.Entry.History.RemoveAt(message.HistoryIndex);
}
}
}
}

View File

@@ -0,0 +1,34 @@
using AutoMapper;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Entry.Models;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Entry.Commands.RestoreHistory
{
public class RestoreHistoryCommand : IRequest
{
public EntryVm Entry { get; set; }
public int HistoryIndex { get; set; }
public class RestoreHistoryCommandHandler : IRequestHandler<RestoreHistoryCommand>
{
private readonly IDatabaseProxy _database;
private readonly IMapper _mapper;
public RestoreHistoryCommandHandler(IDatabaseProxy database, IMapper mapper)
{
_database = database;
_mapper = mapper;
}
public void Handle(RestoreHistoryCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
var entry = _database.RestoreFromHistory(message.Entry.Id, message.HistoryIndex);
message.Entry = _mapper.Map<EntryVm>(entry);
}
}
}
}

View File

@@ -0,0 +1,32 @@
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Entry.Commands.UpsertField
{
public class UpsertFieldCommand : IRequest
{
public string EntryId { get; set; }
public string FieldName { get; set; }
public object FieldValue { get; set; }
public bool IsProtected { get; set; } = true;
public class UpsertFieldCommandHandler : IAsyncRequestHandler<UpsertFieldCommand>
{
private readonly IDatabaseProxy _database;
public UpsertFieldCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public async Task Handle(UpsertFieldCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
await _database.UpdateEntry(message.EntryId, message.FieldName, message.FieldValue, message.IsProtected);
}
}
}
}

View File

@@ -0,0 +1,17 @@
using FluentValidation;
namespace ModernKeePass.Application.Entry.Commands.UpsertField
{
public class UpsertFieldCommandValidator: AbstractValidator<UpsertFieldCommand>
{
public UpsertFieldCommandValidator()
{
RuleFor(v => v.EntryId)
.NotNull()
.NotEmpty();
RuleFor(v => v.FieldName)
.NotNull()
.NotEmpty();
}
}
}

View File

@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using AutoMapper;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Common.Mappings;
using ModernKeePass.Domain.Entities;
using ModernKeePass.Domain.Enums;
namespace ModernKeePass.Application.Entry.Models
{
public class EntryVm: IEntityVm, IMapFrom<EntryEntity>
{
public string ParentGroupId { get; set; }
public string ParentGroupName { get; set; }
public string Id { get; set; }
public FieldVm Title { get; set; }
public FieldVm Username { get; set; }
public FieldVm Password { get; set; }
public FieldVm Notes { get; set; }
public FieldVm Url { get; set; }
public bool IsValidUrl => Uri.IsWellFormedUriString(Url.Value, UriKind.Absolute);
public List<FieldVm> AdditionalFields { get; set; }
public List<EntryVm> History { get; set; }
public Icon Icon { get; set; }
public Color ForegroundColor { get; set; }
public Color BackgroundColor { get; set; }
public bool HasExpirationDate { get; set; }
public DateTimeOffset ExpirationDate { get; set; }
public DateTimeOffset ModificationDate { get; set; }
public Dictionary<string, byte[]> Attachments { get; set; }
public override string ToString()
{
return ModificationDate.ToString("g");
}
public void Mapping(Profile profile)
{
profile.CreateMap<EntryEntity, EntryVm>()
.ForMember(d => d.Title, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f =>
f.Name.Equals(EntryFieldName.Title, StringComparison.Ordinal)) ?? new FieldEntity { Name = EntryFieldName.Title, IsProtected = false } ))
.ForMember(d => d.Username, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f =>
f.Name.Equals(EntryFieldName.UserName, StringComparison.Ordinal)) ?? new FieldEntity { Name = EntryFieldName.UserName, IsProtected = false } ))
.ForMember(d => d.Password, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f =>
f.Name.Equals(EntryFieldName.Password, StringComparison.Ordinal)) ?? new FieldEntity { Name = EntryFieldName.Password, IsProtected = true } ))
.ForMember(d => d.Url, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f =>
f.Name.Equals(EntryFieldName.Url, StringComparison.Ordinal)) ?? new FieldEntity { Name = EntryFieldName.Url, IsProtected = false } ))
.ForMember(d => d.Notes, opts => opts.MapFrom(s => s.Fields.FirstOrDefault(f =>
f.Name.Equals(EntryFieldName.Notes, StringComparison.Ordinal)) ?? new FieldEntity { Name = EntryFieldName.Notes, IsProtected = false } ))
.ForMember(d => d.AdditionalFields, opts => opts.MapFrom(s =>
s.Fields.Where(f => !EntryFieldName.StandardFieldNames.Contains(f.Name, StringComparer.Ordinal))))
.ForMember(d => d.History, opts => opts.MapFrom(s => s.History.Reverse()))
.ForMember(d => d.Icon, opts => opts.MapFrom(s => s.HasExpirationDate && s.ExpirationDate < DateTimeOffset.Now ? Icon.ReportHacked : s.Icon));
}
}
}

View File

@@ -0,0 +1,20 @@
using AutoMapper;
using ModernKeePass.Application.Common.Mappings;
using ModernKeePass.Domain.Entities;
namespace ModernKeePass.Application.Entry.Models
{
public class FieldVm: IMapFrom<FieldEntity>
{
public string Name { get; set; }
public string Value { get; set; }
public bool IsProtected { get; set; }
public override string ToString() => Value;
public void Mapping(Profile profile)
{
profile.CreateMap<FieldEntity, FieldVm>();
}
}
}

View File

@@ -0,0 +1,31 @@
using AutoMapper;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Entry.Models;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Entry.Queries.GetEntry
{
public class GetEntryQuery: IRequest<EntryVm>
{
public string Id { get; set; }
public class GetEntryQueryHandler: IRequestHandler<GetEntryQuery, EntryVm>
{
private readonly IDatabaseProxy _database;
private readonly IMapper _mapper;
public GetEntryQueryHandler(IDatabaseProxy database, IMapper mapper)
{
_database = database;
_mapper = mapper;
}
public EntryVm Handle(GetEntryQuery message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
return _mapper.Map<EntryVm>(_database.GetEntry(message.Id));
}
}
}
}

View File

@@ -0,0 +1,30 @@
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Commands.AddEntry
{
public class AddEntryCommand : IRequest
{
public string ParentGroupId { get; set; }
public string EntryId { get; set; }
public class AddEntryCommandHandler : IAsyncRequestHandler<AddEntryCommand>
{
private readonly IDatabaseProxy _database;
public AddEntryCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public async Task Handle(AddEntryCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
await _database.AddEntry(message.ParentGroupId, message.EntryId);
}
}
}
}

View File

@@ -0,0 +1,30 @@
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Commands.AddGroup
{
public class AddGroupCommand : IRequest
{
public string ParentGroupId { get; set; }
public string GroupId { get; set; }
public class AddGroupCommandHandler : IAsyncRequestHandler<AddGroupCommand>
{
private readonly IDatabaseProxy _database;
public AddGroupCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public async Task Handle(AddGroupCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
await _database.AddGroup(message.ParentGroupId, message.GroupId);
}
}
}
}

View File

@@ -0,0 +1,36 @@
using AutoMapper;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Entry.Models;
using ModernKeePass.Application.Group.Models;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Commands.CreateEntry
{
public class CreateEntryCommand : IRequest<EntryVm>
{
public GroupVm ParentGroup { get; set; }
public class CreateEntryCommandHandler : IRequestHandler<CreateEntryCommand, EntryVm>
{
private readonly IDatabaseProxy _database;
private readonly IMapper _mapper;
public CreateEntryCommandHandler(IDatabaseProxy database, IMapper mapper)
{
_database = database;
_mapper = mapper;
}
public EntryVm Handle(CreateEntryCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
var entry = _database.CreateEntry(message.ParentGroup.Id);
var entryVm = _mapper.Map<EntryVm>(entry);
message.ParentGroup.Entries.Add(entryVm);
return entryVm;
}
}
}
}

View File

@@ -0,0 +1,37 @@
using AutoMapper;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Group.Models;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Commands.CreateGroup
{
public class CreateGroupCommand : IRequest<GroupVm>
{
public GroupVm ParentGroup { get; set; }
public string Name { get; set; }
public bool IsRecycleBin { get; set; }
public class CreateGroupCommandHandler : IRequestHandler<CreateGroupCommand, GroupVm>
{
private readonly IDatabaseProxy _database;
private readonly IMapper _mapper;
public CreateGroupCommandHandler(IDatabaseProxy database, IMapper mapper)
{
_database = database;
_mapper = mapper;
}
public GroupVm Handle(CreateGroupCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
var group = _database.CreateGroup(message.ParentGroup.Id, message.Name, message.IsRecycleBin);
var groupVm = _mapper.Map<GroupVm>(group);
message.ParentGroup.Groups.Add(groupVm);
return groupVm;
}
}
}
}

View File

@@ -0,0 +1,46 @@
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Common;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Commands.DeleteEntry
{
public class DeleteEntryCommand : IRequest
{
public string ParentGroupId { get; set; }
public string EntryId { get; set; }
public string RecycleBinName { get; set; }
public class DeleteEntryCommandHandler : IAsyncRequestHandler<DeleteEntryCommand>
{
private readonly IDatabaseProxy _database;
public DeleteEntryCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public async Task Handle(DeleteEntryCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
if (_database.IsRecycleBinEnabled && (string.IsNullOrEmpty(_database.RecycleBinId) || _database.RecycleBinId.Equals(Constants.EmptyId)))
{
_database.CreateGroup(_database.RootGroupId, message.RecycleBinName, true);
}
if (!_database.IsRecycleBinEnabled || message.ParentGroupId.Equals(_database.RecycleBinId))
{
_database.DeleteEntity(message.EntryId);
}
else
{
await _database.AddEntry(_database.RecycleBinId, message.EntryId);
}
await _database.RemoveEntry(message.ParentGroupId, message.EntryId);
}
}
}
}

View File

@@ -0,0 +1,48 @@
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Common;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Commands.DeleteGroup
{
public class DeleteGroupCommand : IRequest
{
public string ParentGroupId { get; set; }
public string GroupId { get; set; }
public string RecycleBinName { get; set; }
public class DeleteGroupCommandHandler : IAsyncRequestHandler<DeleteGroupCommand>
{
private readonly IDatabaseProxy _database;
public DeleteGroupCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public async Task Handle(DeleteGroupCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
var isRecycleBin = message.GroupId.Equals(_database.RecycleBinId);
if (_database.IsRecycleBinEnabled && (string.IsNullOrEmpty(_database.RecycleBinId) || _database.RecycleBinId.Equals(Constants.EmptyId)))
{
_database.CreateGroup(_database.RootGroupId, message.RecycleBinName, true);
}
if (!_database.IsRecycleBinEnabled || message.ParentGroupId.Equals(_database.RecycleBinId) || isRecycleBin)
{
_database.DeleteEntity(message.GroupId);
}
else
{
await _database.AddGroup(_database.RecycleBinId, message.GroupId);
}
await _database.RemoveGroup(message.ParentGroupId, message.GroupId);
if (isRecycleBin) _database.RecycleBinId = Constants.EmptyId;
}
}
}
}

View File

@@ -0,0 +1,34 @@
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Entry.Models;
using ModernKeePass.Application.Group.Models;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Commands.MoveEntry
{
public class MoveEntryCommand : IRequest
{
public GroupVm ParentGroup { get; set; }
public EntryVm Entry { get; set; }
public int Index { get; set; }
public class MoveEntryCommandHandler : IAsyncRequestHandler<MoveEntryCommand>
{
private readonly IDatabaseProxy _database;
public MoveEntryCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public async Task Handle(MoveEntryCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
await _database.MoveEntry(message.ParentGroup.Id, message.Entry.Id, message.Index);
message.ParentGroup.Entries.Insert(message.Index, message.Entry);
}
}
}
}

View File

@@ -0,0 +1,33 @@
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Group.Models;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Commands.MoveGroup
{
public class MoveGroupCommand : IRequest
{
public GroupVm ParentGroup { get; set; }
public GroupVm Group { get; set; }
public int Index { get; set; }
public class MoveGroupCommandHandler : IAsyncRequestHandler<MoveGroupCommand>
{
private readonly IDatabaseProxy _database;
public MoveGroupCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public async Task Handle(MoveGroupCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
await _database.MoveGroup(message.ParentGroup.Id, message.Group.Id, message.Index);
message.ParentGroup.Groups.Insert(message.Index, message.Group);
}
}
}
}

View File

@@ -0,0 +1,30 @@
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Commands.RemoveEntry
{
public class RemoveEntryCommand : IRequest
{
public string ParentGroupId { get; set; }
public string EntryId { get; set; }
public class RemoveEntryCommandHandler : IAsyncRequestHandler<RemoveEntryCommand>
{
private readonly IDatabaseProxy _database;
public RemoveEntryCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public async Task Handle(RemoveEntryCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
await _database.RemoveEntry(message.ParentGroupId, message.EntryId);
}
}
}
}

View File

@@ -0,0 +1,30 @@
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Commands.RemoveGroup
{
public class RemoveGroupCommand : IRequest
{
public string ParentGroupId { get; set; }
public string GroupId { get; set; }
public class RemoveGroupCommandHandler : IAsyncRequestHandler<RemoveGroupCommand>
{
private readonly IDatabaseProxy _database;
public RemoveGroupCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public async Task Handle(RemoveGroupCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
await _database.RemoveGroup(message.ParentGroupId, message.GroupId);
}
}
}
}

View File

@@ -0,0 +1,31 @@
using System.Linq;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Group.Models;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Commands.SortEntries
{
public class SortEntriesCommand : IRequest
{
public GroupVm Group { get; set; }
public class SortEntriesCommandHandler : IRequestHandler<SortEntriesCommand>
{
private readonly IDatabaseProxy _database;
public SortEntriesCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public void Handle(SortEntriesCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
_database.SortEntries(message.Group.Id);
message.Group.Entries = message.Group.Entries.OrderBy(e => e.Title.Value).ToList();
}
}
}
}

View File

@@ -0,0 +1,31 @@
using System.Linq;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Group.Models;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Commands.SortGroups
{
public class SortGroupsCommand : IRequest
{
public GroupVm Group { get; set; }
public class SortGroupsCommandHandler : IRequestHandler<SortGroupsCommand>
{
private readonly IDatabaseProxy _database;
public SortGroupsCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public void Handle(SortGroupsCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
_database.SortSubGroups(message.Group.Id);
message.Group.Groups = message.Group.Groups.OrderBy(g => g.Title).ToList();
}
}
}
}

View File

@@ -0,0 +1,41 @@
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Group.Models;
using ModernKeePass.Domain.Entities;
using ModernKeePass.Domain.Enums;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Commands.UpdateGroup
{
public class UpdateGroupCommand : IRequest
{
public GroupVm Group { get; set; }
public string Title { get; set; }
public Icon Icon { get; set; }
public class UpdateGroupCommandHandler : IRequestHandler<UpdateGroupCommand>
{
private readonly IDatabaseProxy _database;
public UpdateGroupCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public void Handle(UpdateGroupCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
var group = new GroupEntity
{
Id = message.Group.Id,
Name = message.Title,
Icon = message.Icon
};
_database.UpdateGroup(group);
message.Group.Title = message.Title;
message.Group.Icon = message.Icon;
}
}
}
}

View File

@@ -0,0 +1,33 @@
using System.Collections.Generic;
using AutoMapper;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Common.Mappings;
using ModernKeePass.Application.Entry.Models;
using ModernKeePass.Domain.Entities;
using ModernKeePass.Domain.Enums;
namespace ModernKeePass.Application.Group.Models
{
public class GroupVm: IEntityVm, IMapFrom<GroupEntity>
{
public string ParentGroupId { get; set; }
public string ParentGroupName { get; set; }
public string Id { get; set; }
public string Title { get; set; }
public Icon Icon { get; set; }
public List<GroupVm> Groups { get; set; }
public List<EntryVm> Entries { get; set; }
public override string ToString()
{
return Title;
}
public void Mapping(Profile profile)
{
profile.CreateMap<GroupEntity, GroupVm>()
.ForMember(d => d.Title, opts => opts.MapFrom(s => s.Name))
.MaxDepth(2);
}
}
}

View File

@@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Group.Models;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Queries.GetAllGroups
{
public class GetAllGroupsQuery : IRequest<IEnumerable<GroupVm>>
{
public string GroupId { get; set; }
public class GetAllGroupsQueryHandler : IRequestHandler<GetAllGroupsQuery, IEnumerable<GroupVm>>
{
private readonly IDatabaseProxy _database;
private readonly IMapper _mapper;
public GetAllGroupsQueryHandler(IDatabaseProxy database, IMapper mapper)
{
_database = database;
_mapper = mapper;
}
public IEnumerable<GroupVm> Handle(GetAllGroupsQuery message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
var groups = new List<GroupVm> {_mapper.Map<GroupVm>(_database.GetGroup(message.GroupId))};
groups.AddRange(_database.GetAllGroups(message.GroupId).Select(g => _mapper.Map<GroupVm>(g)));
return groups;
}
}
}
}

View File

@@ -0,0 +1,31 @@
using AutoMapper;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Group.Models;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Queries.GetGroup
{
public class GetGroupQuery : IRequest<GroupVm>
{
public string Id { get; set; }
public class GetGroupQueryHandler : IRequestHandler<GetGroupQuery, GroupVm>
{
private readonly IDatabaseProxy _database;
private readonly IMapper _mapper;
public GetGroupQueryHandler(IDatabaseProxy database, IMapper mapper)
{
_database = database;
_mapper = mapper;
}
public GroupVm Handle(GetGroupQuery message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
return _mapper.Map<GroupVm>(_database.GetGroup(message.Id));
}
}
}
}

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Linq;
using AutoMapper;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Entry.Models;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Group.Queries.SearchEntries
{
public class SearchEntriesQuery : IRequest<IEnumerable<EntryVm>>
{
public string GroupId { get; set; }
public string SearchText { get; set; }
public class SearchEntriesQueryHandler : IRequestHandler<SearchEntriesQuery, IEnumerable<EntryVm>>
{
private readonly IDatabaseProxy _database;
private readonly IMapper _mapper;
public SearchEntriesQueryHandler(IDatabaseProxy database, IMapper mapper)
{
_database = database;
_mapper = mapper;
}
public IEnumerable<EntryVm> Handle(SearchEntriesQuery message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
return _database.Search(message.GroupId, message.SearchText).Select(e => _mapper.Map<EntryVm>(e));
}
}
}
}

View File

@@ -0,0 +1,50 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Enums;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Import.Commands.ImportFromCsv
{
public class ImportFromCsvCommand : IRequest
{
public string FilePath { get; set; }
public string DestinationGroupId { get; set; }
public bool HasHeaderRow { get; set; }
public char Delimiter { get; set; } = ';';
public Dictionary<int, string> FieldMappings { get; set; }
public class CreateDatabaseCommandHandler : IAsyncRequestHandler<ImportFromCsvCommand>
{
private readonly IDatabaseProxy _database;
private readonly IFileProxy _file;
public CreateDatabaseCommandHandler(IDatabaseProxy database, IFileProxy file)
{
_database = database;
_file = file;
}
public async Task Handle(ImportFromCsvCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
var fileContents = await _file.ReadTextFile(message.FilePath);
for (var index = message.HasHeaderRow ? 1 : 0; index < fileContents.Count; index++)
{
var line = fileContents[index];
var fields = line.Split(message.Delimiter);
var entry = _database.CreateEntry(message.DestinationGroupId);
for (var i = 0; i < fields.Length; i++)
{
var fieldMapping = message.FieldMappings[i];
await _database.UpdateEntry(entry.Id, fieldMapping, fields[i], fieldMapping == EntryFieldName.Password);
}
}
}
}
}
}

View File

@@ -0,0 +1,17 @@
using FluentValidation;
namespace ModernKeePass.Application.Import.Commands.ImportFromCsv
{
public class ImportFromCsvCommandValidator : AbstractValidator<ImportFromCsvCommand>
{
public ImportFromCsvCommandValidator()
{
RuleFor(v => v.FilePath)
.NotNull()
.NotEmpty();
RuleFor(v => v.DestinationGroupId)
.NotNull()
.NotEmpty();
}
}
}

View File

@@ -0,0 +1,27 @@
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Parameters.Commands.SetCipher
{
public class SetCipherCommand : IRequest
{
public string CipherId { get; set; }
public class SetCipherCommandHandler : IRequestHandler<SetCipherCommand>
{
private readonly IDatabaseProxy _database;
public SetCipherCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public void Handle(SetCipherCommand message)
{
if (_database.IsOpen) _database.CipherId = message.CipherId;
else throw new DatabaseClosedException();
}
}
}
}

View File

@@ -0,0 +1,27 @@
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Parameters.Commands.SetCompression
{
public class SetCompressionCommand : IRequest
{
public string Compression { get; set; }
public class SetCompressionCommandHandler : IRequestHandler<SetCompressionCommand>
{
private readonly IDatabaseProxy _database;
public SetCompressionCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public void Handle(SetCompressionCommand message)
{
if (_database.IsOpen) _database.Compression = message.Compression;
else throw new DatabaseClosedException();
}
}
}
}

View File

@@ -0,0 +1,27 @@
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Parameters.Commands.SetHasRecycleBin
{
public class SetHasRecycleBinCommand : IRequest
{
public bool HasRecycleBin { get; set; }
public class SetHasRecycleBinCommandHandler : IRequestHandler<SetHasRecycleBinCommand>
{
private readonly IDatabaseProxy _database;
public SetHasRecycleBinCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public void Handle(SetHasRecycleBinCommand message)
{
if (_database.IsOpen) _database.IsRecycleBinEnabled = message.HasRecycleBin;
else throw new DatabaseClosedException();
}
}
}
}

View File

@@ -0,0 +1,27 @@
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Parameters.Commands.SetKeyDerivation
{
public class SetKeyDerivationCommand : IRequest
{
public string KeyDerivationId { get; set; }
public class SetKeyDerivationCommandHandler : IRequestHandler<SetKeyDerivationCommand>
{
private readonly IDatabaseProxy _database;
public SetKeyDerivationCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public void Handle(SetKeyDerivationCommand message)
{
if (_database.IsOpen) _database.KeyDerivationId = message.KeyDerivationId;
else throw new DatabaseClosedException();
}
}
}
}

View File

@@ -0,0 +1,27 @@
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Parameters.Commands.SetMaxHistoryCount
{
public class SetMaxHistoryCountCommand : IRequest
{
public int MaxHistoryCount { get; set; }
public class SetMaxHistoryCountCommandHandler : IRequestHandler<SetMaxHistoryCountCommand>
{
private readonly IDatabaseProxy _database;
public SetMaxHistoryCountCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public void Handle(SetMaxHistoryCountCommand message)
{
if (_database.IsOpen) _database.MaxHistoryCount = message.MaxHistoryCount;
else throw new DatabaseClosedException();
}
}
}
}

View File

@@ -0,0 +1,28 @@
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Parameters.Commands.SetMaxHistorySize
{
public class SetMaxHistorySizeCommand : IRequest
{
public long MaxHistorySize { get; set; }
public class SetMaxHistorySizeCommandHandler : IRequestHandler<SetMaxHistorySizeCommand>
{
private readonly IDatabaseProxy _database;
public SetMaxHistorySizeCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public void Handle(SetMaxHistorySizeCommand message)
{
if (_database.IsOpen) _database.MaxHistorySize = message.MaxHistorySize;
else throw new DatabaseClosedException();
}
}
}
}

View File

@@ -0,0 +1,28 @@
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Common;
using ModernKeePass.Domain.Exceptions;
namespace ModernKeePass.Application.Parameters.Commands.SetRecycleBin
{
public class SetRecycleBinCommand : IRequest
{
public string RecycleBinId { get; set; }
public class SetRecycleBinCommandHandler : IRequestHandler<SetRecycleBinCommand>
{
private readonly IDatabaseProxy _database;
public SetRecycleBinCommandHandler(IDatabaseProxy database)
{
_database = database;
}
public void Handle(SetRecycleBinCommand message)
{
if (!_database.IsOpen) throw new DatabaseClosedException();
_database.RecycleBinId = message.RecycleBinId ?? Constants.EmptyId;
}
}
}
}

View File

@@ -0,0 +1,8 @@
namespace ModernKeePass.Application.Parameters.Models
{
public class CipherVm
{
public string Id { get; set; }
public string Name { get; set; }
}
}

View File

@@ -0,0 +1,8 @@
namespace ModernKeePass.Application.Parameters.Models
{
public class KeyDerivationVm
{
public string Id { get; set; }
public string Name { get; set; }
}
}

View File

@@ -0,0 +1,30 @@
using System.Collections.Generic;
using System.Linq;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Parameters.Models;
namespace ModernKeePass.Application.Parameters.Queries.GetCiphers
{
public class GetCiphersQuery: IRequest<IEnumerable<CipherVm>>
{
public class GetCiphersQueryHandler: IRequestHandler<GetCiphersQuery, IEnumerable<CipherVm>>
{
private readonly IDatabaseSettingsProxy _databaseSettings;
public GetCiphersQueryHandler(IDatabaseSettingsProxy databaseSettings)
{
_databaseSettings = databaseSettings;
}
public IEnumerable<CipherVm> Handle(GetCiphersQuery message)
{
return _databaseSettings.Ciphers.Select(c => new CipherVm
{
Id = c.Id,
Name = c.Name
});
}
}
}
}

View File

@@ -0,0 +1,25 @@
using System.Collections.Generic;
using System.Linq;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
namespace ModernKeePass.Application.Parameters.Queries.GetCompressions
{
public class GetCompressionsQuery : IRequest<IEnumerable<string>>
{
public class GetCompressionsQueryHandler : IRequestHandler<GetCompressionsQuery, IEnumerable<string>>
{
private readonly IDatabaseSettingsProxy _databaseSettings;
public GetCompressionsQueryHandler(IDatabaseSettingsProxy databaseSettings)
{
_databaseSettings = databaseSettings;
}
public IEnumerable<string> Handle(GetCompressionsQuery message)
{
return _databaseSettings.CompressionAlgorithms.OrderBy(c => c);
}
}
}
}

View File

@@ -0,0 +1,30 @@
using System.Collections.Generic;
using System.Linq;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Application.Parameters.Models;
namespace ModernKeePass.Application.Parameters.Queries.GetKeyDerivations
{
public class GetKeyDerivationsQuery : IRequest<IEnumerable<KeyDerivationVm>>
{
public class GetKeyDerivationsQueryHandler : IRequestHandler<GetKeyDerivationsQuery, IEnumerable<KeyDerivationVm>>
{
private readonly IDatabaseSettingsProxy _databaseSettings;
public GetKeyDerivationsQueryHandler(IDatabaseSettingsProxy databaseSettings)
{
_databaseSettings = databaseSettings;
}
public IEnumerable<KeyDerivationVm> Handle(GetKeyDerivationsQuery message)
{
return _databaseSettings.KeyDerivations.Select(c => new KeyDerivationVm
{
Id = c.Id,
Name = c.Name
});
}
}
}
}

View File

@@ -0,0 +1,28 @@
using System.Resources;
using System.Reflection;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ModernKeePass.Application")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ModernKeePass.Application")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,37 @@
using System.Threading.Tasks;
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
namespace ModernKeePass.Application.Security.Commands.GenerateKeyFile
{
public class GenerateKeyFileCommand : IRequest
{
public string KeyFilePath { get; set; }
public bool AddAdditionalEntropy { get; set; }
public class GenerateKeyFileCommandHandler : IAsyncRequestHandler<GenerateKeyFileCommand>
{
private readonly ICredentialsProxy _security;
private readonly IFileProxy _file;
private readonly ICryptographyClient _cryptography;
public GenerateKeyFileCommandHandler(ICredentialsProxy security, IFileProxy file, ICryptographyClient cryptography)
{
_security = security;
_file = file;
_cryptography = cryptography;
}
public async Task Handle(GenerateKeyFileCommand message)
{
byte[] entropy = null;
if (message.AddAdditionalEntropy)
{
entropy = _cryptography.Random(10);
}
var keyFile = _security.GenerateKeyFile(entropy);
await _file.WriteBinaryContentsToFile(message.KeyFilePath, keyFile);
}
}
}
}

View File

@@ -0,0 +1,48 @@
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
using ModernKeePass.Domain.Dtos;
namespace ModernKeePass.Application.Security.Commands.GeneratePassword
{
public class GeneratePasswordCommand: IRequest<string>
{
public int PasswordLength { get; set; }
public bool UpperCasePatternSelected { get; set; }
public bool LowerCasePatternSelected { get; set; }
public bool DigitsPatternSelected { get; set; }
public bool SpecialPatternSelected { get; set; }
public bool MinusPatternSelected { get; set; }
public bool UnderscorePatternSelected { get; set; }
public bool SpacePatternSelected { get; set; }
public bool BracketsPatternSelected { get; set; }
public string CustomChars { get; set; }
public class GeneratePasswordCommandHandler: IRequestHandler<GeneratePasswordCommand, string>
{
private readonly ICredentialsProxy _security;
public GeneratePasswordCommandHandler(ICredentialsProxy security)
{
_security = security;
}
public string Handle(GeneratePasswordCommand message)
{
var options = new PasswordGenerationOptions
{
PasswordLength = message.PasswordLength,
BracketsPatternSelected = message.BracketsPatternSelected,
CustomChars = message.CustomChars,
DigitsPatternSelected = message.DigitsPatternSelected,
LowerCasePatternSelected = message.LowerCasePatternSelected,
MinusPatternSelected = message.MinusPatternSelected,
SpacePatternSelected = message.SpacePatternSelected,
SpecialPatternSelected = message.SpecialPatternSelected,
UnderscorePatternSelected = message.UnderscorePatternSelected,
UpperCasePatternSelected = message.UpperCasePatternSelected
};
return _security.GeneratePassword(options);
}
}
}
}

View File

@@ -0,0 +1,25 @@
using MediatR;
using ModernKeePass.Application.Common.Interfaces;
namespace ModernKeePass.Application.Security.Queries.EstimatePasswordComplexity
{
public class EstimatePasswordComplexityQuery : IRequest<int>
{
public string Password { get; set; }
public class EstimatePasswordComplexityQueryHandler : IRequestHandler<EstimatePasswordComplexityQuery, int>
{
private readonly ICredentialsProxy _security;
public EstimatePasswordComplexityQueryHandler(ICredentialsProxy security)
{
_security = security;
}
public int Handle(EstimatePasswordComplexityQuery message)
{
return _security.EstimatePasswordComplexity(message.Password);
}
}
}
}

View File

@@ -0,0 +1,16 @@
{
"supports": {},
"dependencies": {
"AutoMapper": "5.2.0",
"FluentValidation": "8.6.2",
"MediatR": "3.0.1",
"MediatR.Extensions.Microsoft.DependencyInjection": "2.0.0",
"Microsoft.Extensions.DependencyInjection": "1.1.1",
"Microsoft.NETCore.Portable.Compatibility": "1.0.2",
"NETStandard.Library": "2.0.3",
"Splat": "3.0.0"
},
"frameworks": {
"netstandard1.2": {}
}
}

View File

@@ -0,0 +1,14 @@
namespace ModernKeePass.Domain.Common
{
public static class Constants
{
public static string EmptyId => "00000000000000000000000000000000";
public static class Extensions
{
public static string Any => "*";
public static string Kdbx => ".kdbx";
public static string Key => ".key";
}
}
}

View File

@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{9A0759F1-9069-4841-99E3-3BEC44E17356}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>ModernKeePass.Domain</RootNamespace>
<AssemblyName>ModernKeePass.Domain</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|ARM' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\ARM\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>ARM</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|ARM' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\ARM\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="Common\Constants.cs" />
<Compile Include="Dtos\Attachment.cs" />
<Compile Include="Dtos\Credentials.cs" />
<Compile Include="Dtos\FileInfo.cs" />
<Compile Include="Dtos\PasswordGenerationOptions.cs" />
<Compile Include="Entities\BaseEntity.cs" />
<Compile Include="Entities\EntryEntity.cs" />
<Compile Include="Entities\FieldEntity.cs" />
<Compile Include="Entities\GroupEntity.cs" />
<Compile Include="Enums\CredentialStatusTypes.cs" />
<Compile Include="Enums\DatabaseVersion.cs" />
<Compile Include="Enums\EntryFieldName.cs" />
<Compile Include="Enums\Icon.cs" />
<Compile Include="Enums\ImportFormat.cs" />
<Compile Include="Exceptions\DatabaseClosedException.cs" />
<Compile Include="Exceptions\DatabaseOpenException.cs" />
<Compile Include="Exceptions\DatabaseTooBigException.cs" />
<Compile Include="Exceptions\NavigationException.cs" />
<Compile Include="Exceptions\SaveException.cs" />
<Compile Include="Interfaces\IDateTime.cs" />
<Compile Include="Interfaces\IHasSelectableObject.cs" />
<Compile Include="Interfaces\IImportFormat.cs" />
<Compile Include="Interfaces\IIsEnabled.cs" />
<Compile Include="Interfaces\ISelectableModel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@@ -0,0 +1,8 @@
namespace ModernKeePass.Domain.Dtos
{
public class Attachment
{
public string Name { get; set; }
public byte[] Content { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
namespace ModernKeePass.Domain.Dtos
{
public class Credentials
{
public string Password { get; set; }
public byte[] KeyFileContents { get; set; }
// TODO: add Windows Hello
}
}

View File

@@ -0,0 +1,9 @@
namespace ModernKeePass.Domain.Dtos
{
public class FileInfo
{
public string Id { get; set; }
public string Name { get; set; }
public string Path { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
namespace ModernKeePass.Domain.Dtos
{
public class PasswordGenerationOptions
{
public int PasswordLength { get; set; }
public bool UpperCasePatternSelected { get; set; }
public bool LowerCasePatternSelected { get; set; }
public bool DigitsPatternSelected { get; set; }
public bool SpecialPatternSelected { get; set; }
public bool MinusPatternSelected { get; set; }
public bool UnderscorePatternSelected { get; set; }
public bool SpacePatternSelected { get; set; }
public bool BracketsPatternSelected { get; set; }
public string CustomChars { get; set; }
}
}

View File

@@ -0,0 +1,13 @@
using System;
namespace ModernKeePass.Domain.Entities
{
public class BaseEntity
{
public string Id { get; set; }
public string Name { get; set; }
public string ParentGroupId { get; set; }
public string ParentGroupName { get; set; }
public DateTimeOffset ModificationDate { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using ModernKeePass.Domain.Enums;
namespace ModernKeePass.Domain.Entities
{
public class EntryEntity: BaseEntity
{
public IEnumerable<FieldEntity> Fields { get; set; } = new List<FieldEntity>();
public IEnumerable<EntryEntity> History { get; set; } = new List<EntryEntity>();
public Dictionary<string, byte[]> Attachments { get; set; } = new Dictionary<string, byte[]>();
public DateTimeOffset ExpirationDate { get; set; }
public Icon Icon { get; set; }
public Color ForegroundColor { get; set; }
public Color BackgroundColor { get; set; }
public bool HasExpirationDate { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
namespace ModernKeePass.Domain.Entities
{
public class FieldEntity
{
public string Name { get; set; }
public string Value { get; set; }
public bool IsProtected { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
using System.Collections.Generic;
using ModernKeePass.Domain.Enums;
namespace ModernKeePass.Domain.Entities
{
public class GroupEntity : BaseEntity
{
public List<GroupEntity> Groups { get; set; } = new List<GroupEntity>();
public List<EntryEntity> Entries { get; set; } = new List<EntryEntity>();
public Icon Icon { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
namespace ModernKeePass.Domain.Enums
{
public enum CredentialStatusTypes
{
Normal = 0,
Error = 1,
Warning = 3,
Success = 5
}
}

View File

@@ -0,0 +1,9 @@
namespace ModernKeePass.Domain.Enums
{
public enum DatabaseVersion
{
V2,
V3,
V4
}
}

View File

@@ -0,0 +1,32 @@
using System.Collections.Generic;
namespace ModernKeePass.Domain.Enums
{
public static class EntryFieldName
{
public const string Title = nameof(Title);
public const string UserName = nameof(UserName);
public const string Password = nameof(Password);
public const string Url = "URL";
public const string Notes = nameof(Notes);
public const string Icon = nameof(Icon);
public const string ExpirationDate = nameof(ExpirationDate);
public const string HasExpirationDate = nameof(HasExpirationDate);
public const string BackgroundColor = nameof(BackgroundColor);
public const string ForegroundColor = nameof(ForegroundColor);
public static IEnumerable<string> StandardFieldNames => new[]
{
Title,
UserName,
Password,
Url,
Notes,
Icon,
ExpirationDate,
HasExpirationDate,
BackgroundColor,
ForegroundColor
};
}
}

View File

@@ -0,0 +1,54 @@
namespace ModernKeePass.Domain.Enums
{
public enum Icon
{
Delete,
Edit,
Save,
Cancel,
Accept,
Home,
Camera,
Setting,
Mail,
Find,
Help,
Clock,
Crop,
World,
Flag,
PreviewLink,
Document,
ProtectedDocument,
ContactInfo,
ViewAll,
Rotate,
List,
Shop,
BrowsePhotos,
Caption,
Repair,
Page,
Paste,
Important,
SlideShow,
MapDrive,
ContactPresence,
Contact,
Folder,
View,
Permissions,
Map,
CellPhone,
OutlineStar,
Calculator,
Library,
SyncFolder,
GoToStart,
ZeroBars,
FourBars,
Scan,
ReportHacked,
Stop
}
}

View File

@@ -0,0 +1,7 @@
namespace ModernKeePass.Domain.Enums
{
public enum ImportFormat
{
CSV
}
}

View File

@@ -0,0 +1,7 @@
using System;
namespace ModernKeePass.Domain.Exceptions
{
public class DatabaseClosedException: Exception
{ }
}

View File

@@ -0,0 +1,7 @@
using System;
namespace ModernKeePass.Domain.Exceptions
{
public class DatabaseOpenException: Exception
{ }
}

View File

@@ -0,0 +1,6 @@
using System;
namespace ModernKeePass.Domain.Exceptions
{
public class DatabaseTooBigException: Exception { }
}

View File

@@ -0,0 +1,11 @@
using System;
namespace ModernKeePass.Domain.Exceptions
{
public class NavigationException: Exception
{
public NavigationException(Type pageType) : base($"Failed to load Page {pageType.FullName}")
{
}
}
}

View File

@@ -0,0 +1,16 @@
using System;
namespace ModernKeePass.Domain.Exceptions
{
public class SaveException : Exception
{
public new string Message { get; }
public new string Source { get; }
public SaveException(Exception exception)
{
Message = exception.Message;
Source = exception.Source;
}
}
}

View File

@@ -0,0 +1,9 @@
using System;
namespace ModernKeePass.Domain.Interfaces
{
public interface IDateTime
{
DateTime Now { get; }
}
}

View File

@@ -0,0 +1,7 @@
namespace ModernKeePass.Domain.Interfaces
{
public interface IHasSelectableObject
{
ISelectableModel SelectedItem { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ModernKeePass.Domain.Interfaces
{
public interface IImportFormat
{
Task<List<Dictionary<string, string>>> Import(string path);
}
}

View File

@@ -1,4 +1,4 @@
namespace ModernKeePass.Interfaces namespace ModernKeePass.Domain.Interfaces
{ {
public interface IIsEnabled public interface IIsEnabled
{ {

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